mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-23 04:41:12 +00:00
ddsf: implement namespace
This commit is contained in:
parent
d2e530c2aa
commit
5b617f4d2f
23 changed files with 1578 additions and 5 deletions
|
@ -43,6 +43,7 @@
|
||||||
#include <stratosphere/boot2.hpp>
|
#include <stratosphere/boot2.hpp>
|
||||||
#include <stratosphere/capsrv.hpp>
|
#include <stratosphere/capsrv.hpp>
|
||||||
#include <stratosphere/cfg.hpp>
|
#include <stratosphere/cfg.hpp>
|
||||||
|
#include <stratosphere/ddsf.hpp>
|
||||||
#include <stratosphere/dmnt.hpp>
|
#include <stratosphere/dmnt.hpp>
|
||||||
#include <stratosphere/erpt.hpp>
|
#include <stratosphere/erpt.hpp>
|
||||||
#include <stratosphere/err.hpp>
|
#include <stratosphere/err.hpp>
|
||||||
|
|
|
@ -13,7 +13,15 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stratosphere/ddsf/ddsf_types.hpp>
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_castable.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_session.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_device.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_driver.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_device_code_entry.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_device_code_entry_manager.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_event_handler.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_event_handler_manager.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_memory_api.hpp>
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class IDevice;
|
||||||
|
|
||||||
|
class DeviceCodeEntry {
|
||||||
|
NON_COPYABLE(DeviceCodeEntry);
|
||||||
|
NON_MOVEABLE(DeviceCodeEntry);
|
||||||
|
private:
|
||||||
|
ams::DeviceCode device_code = ams::InvalidDeviceCode;
|
||||||
|
IDevice *device = nullptr;
|
||||||
|
public:
|
||||||
|
constexpr DeviceCodeEntry(ams::DeviceCode dc, IDevice *dev) : device_code(dc), device(dev) {
|
||||||
|
AMS_ASSERT(dev != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ams::DeviceCode GetDeviceCode() const {
|
||||||
|
return this->device_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr IDevice &GetDevice() {
|
||||||
|
return *this->device;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const IDevice &GetDevice() const {
|
||||||
|
return *this->device;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class DeviceCodeEntryHolder {
|
||||||
|
NON_COPYABLE(DeviceCodeEntryHolder);
|
||||||
|
NON_MOVEABLE(DeviceCodeEntryHolder);
|
||||||
|
private:
|
||||||
|
util::IntrusiveListNode list_node;
|
||||||
|
TYPED_STORAGE(DeviceCodeEntry) entry_storage;
|
||||||
|
bool is_constructed;
|
||||||
|
public:
|
||||||
|
using ListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&DeviceCodeEntryHolder::list_node>;
|
||||||
|
using List = typename ListTraits::ListType;
|
||||||
|
friend class util::IntrusiveList<DeviceCodeEntryHolder, util::IntrusiveListMemberTraitsDeferredAssert<&DeviceCodeEntryHolder::list_node>>;
|
||||||
|
public:
|
||||||
|
DeviceCodeEntryHolder() : list_node(), entry_storage(), is_constructed(false) {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
~DeviceCodeEntryHolder() {
|
||||||
|
if (this->IsConstructed()) {
|
||||||
|
this->Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTo(List &list) {
|
||||||
|
list.push_back(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveFrom(List list) {
|
||||||
|
list.erase(list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLinkedToList() const {
|
||||||
|
return this->list_node.IsLinked();
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceCodeEntry &Construct(DeviceCode dc, IDevice *dev) {
|
||||||
|
AMS_ASSERT(!this->IsConstructed());
|
||||||
|
DeviceCodeEntry *entry = new (GetPointer(this->entry_storage)) DeviceCodeEntry(dc, dev);
|
||||||
|
this->is_constructed = true;
|
||||||
|
return *entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsConstructed() const {
|
||||||
|
return this->is_constructed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy() {
|
||||||
|
AMS_ASSERT(this->IsConstructed());
|
||||||
|
GetReference(this->entry_storage).~DeviceCodeEntry();
|
||||||
|
this->is_constructed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceCodeEntry &Get() {
|
||||||
|
AMS_ASSERT(this->IsConstructed());
|
||||||
|
return GetReference(this->entry_storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeviceCodeEntry &Get() const {
|
||||||
|
AMS_ASSERT(this->IsConstructed());
|
||||||
|
return GetReference(this->entry_storage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(DeviceCodeEntryHolder::ListTraits::IsValid());
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/impl/ddsf_for_each.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_device_code_entry.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class IDevice;
|
||||||
|
|
||||||
|
class DeviceCodeEntryManager {
|
||||||
|
private:
|
||||||
|
ams::MemoryResource *memory_resource;
|
||||||
|
ddsf::DeviceCodeEntryHolder::List entry_list;
|
||||||
|
mutable os::SdkMutex entry_list_lock;
|
||||||
|
private:
|
||||||
|
void DestroyAllEntries() {
|
||||||
|
auto it = this->entry_list.begin();
|
||||||
|
while (it != this->entry_list.end()) {
|
||||||
|
ddsf::DeviceCodeEntryHolder *entry = std::addressof(*it);
|
||||||
|
it = this->entry_list.erase(it);
|
||||||
|
|
||||||
|
AMS_ASSERT(entry->IsConstructed());
|
||||||
|
if (entry->IsConstructed()) {
|
||||||
|
entry->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->memory_resource->Deallocate(entry, sizeof(*entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
DeviceCodeEntryManager(ams::MemoryResource *mr) : memory_resource(mr), entry_list(), entry_list_lock() { /* ... */ }
|
||||||
|
|
||||||
|
~DeviceCodeEntryManager() {
|
||||||
|
this->DestroyAllEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
std::scoped_lock lk(this->entry_list_lock);
|
||||||
|
this->DestroyAllEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Add(DeviceCode device_code, IDevice *device);
|
||||||
|
bool Remove(DeviceCode device_code);
|
||||||
|
|
||||||
|
Result FindDeviceCodeEntry(DeviceCodeEntry **out, DeviceCode device_code);
|
||||||
|
Result FindDeviceCodeEntry(const DeviceCodeEntry **out, DeviceCode device_code) const;
|
||||||
|
|
||||||
|
Result FindDevice(IDevice **out, DeviceCode device_code);
|
||||||
|
Result FindDevice(const IDevice **out, DeviceCode device_code) const;
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachEntry(F f) {
|
||||||
|
return impl::ForEach(this->entry_list_lock, this->entry_list, [&](DeviceCodeEntryHolder &holder) -> bool {
|
||||||
|
AMS_ASSERT(holder.IsConstructed());
|
||||||
|
return f(holder.Get());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachEntry(F f) const {
|
||||||
|
return impl::ForEach(this->entry_list_lock, this->entry_list, [&](const DeviceCodeEntryHolder &holder) -> bool {
|
||||||
|
AMS_ASSERT(holder.IsConstructed());
|
||||||
|
return f(holder.Get());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_event_handler.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class EventHandlerManager;
|
||||||
|
|
||||||
|
class EventHandlerManager {
|
||||||
|
NON_COPYABLE(EventHandlerManager);
|
||||||
|
NON_MOVEABLE(EventHandlerManager);
|
||||||
|
private:
|
||||||
|
struct LoopControlCommandParameters;
|
||||||
|
private:
|
||||||
|
bool is_initialized;
|
||||||
|
bool is_looping;
|
||||||
|
os::SdkConditionVariable is_looping_cv;
|
||||||
|
os::WaitableManagerType waitable_manager;
|
||||||
|
os::ThreadType *loop_thread;
|
||||||
|
os::Event loop_control_event;
|
||||||
|
os::WaitableHolderType loop_control_event_holder;
|
||||||
|
LoopControlCommandParameters *loop_control_command_params;
|
||||||
|
os::Event loop_control_command_done_event; /* TODO: os::LightEvent, requires mesosphere for < 4.0.0 compat. */
|
||||||
|
os::SdkMutex loop_control_lock;
|
||||||
|
private:
|
||||||
|
void ProcessControlCommand(LoopControlCommandParameters *params);
|
||||||
|
void ProcessControlCommandImpl(LoopControlCommandParameters *params);
|
||||||
|
public:
|
||||||
|
EventHandlerManager()
|
||||||
|
: is_initialized(false), is_looping(false), is_looping_cv(), waitable_manager(),
|
||||||
|
loop_thread(), loop_control_event(os::EventClearMode_AutoClear), loop_control_event_holder(),
|
||||||
|
loop_control_command_params(), loop_control_command_done_event(os::EventClearMode_AutoClear),
|
||||||
|
loop_control_lock()
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
~EventHandlerManager() {
|
||||||
|
if (this->is_looping) {
|
||||||
|
AMS_ASSERT(!this->IsRunningOnLoopThread());
|
||||||
|
this->RequestStop();
|
||||||
|
}
|
||||||
|
if (this->is_initialized) {
|
||||||
|
this->Finalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRunningOnLoopThread() const { return this->loop_thread == os::GetCurrentThread(); }
|
||||||
|
bool IsLooping() const { return this->is_looping; }
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Finalize();
|
||||||
|
|
||||||
|
void RegisterHandler(IEventHandler *handler);
|
||||||
|
void UnregisterHandler(IEventHandler *handler);
|
||||||
|
|
||||||
|
void WaitLoopEnter();
|
||||||
|
void WaitLoopExit();
|
||||||
|
void RequestStop();
|
||||||
|
|
||||||
|
void LoopAuto();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/impl/ddsf_type_tag.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||||
|
|
||||||
|
#define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \
|
||||||
|
public: \
|
||||||
|
static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag(#__CLASS__, __BASE__::s_ams_ddsf_castable_type_tag); \
|
||||||
|
constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define AMS_DDSF_CASTABLE_TRAITS(__CLASS__, __BASE__) \
|
||||||
|
public: \
|
||||||
|
static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag(__BASE__::s_ams_ddsf_castable_type_tag); \
|
||||||
|
constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class ICastable {
|
||||||
|
private:
|
||||||
|
constexpr virtual const impl::TypeTag &GetTypeTag() const = 0;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr ALWAYS_INLINE void AssertCastableTo() const {
|
||||||
|
AMS_ASSERT(this->IsCastableTo<T>());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
constexpr bool IsCastableTo() const {
|
||||||
|
return this->GetTypeTag().DerivesFrom(T::s_ams_ddsf_castable_type_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr T &SafeCastTo() {
|
||||||
|
this->AssertCastableTo<T>();
|
||||||
|
return static_cast<T &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr const T &SafeCastTo() const {
|
||||||
|
this->AssertCastableTo<T>();
|
||||||
|
return static_cast<T &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr T *SafeCastToPointer() {
|
||||||
|
this->AssertCastableTo<T>();
|
||||||
|
return static_cast<T *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr const T *SafeCastToPointer() const {
|
||||||
|
this->AssertCastableTo<T>();
|
||||||
|
return static_cast<T *>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||||
|
|
||||||
|
constexpr const char *GetClassName() const {
|
||||||
|
return this->GetTypeTag().GetClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_sdk_mutex.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/impl/ddsf_for_each.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_castable.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_session.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class IDriver;
|
||||||
|
|
||||||
|
class IDevice : public ICastable {
|
||||||
|
friend Result OpenSession(IDevice *device, ISession *session, AccessMode mode);
|
||||||
|
friend void CloseSession(ISession *session);
|
||||||
|
friend class IDriver;
|
||||||
|
public:
|
||||||
|
AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDevice);
|
||||||
|
private:
|
||||||
|
util::IntrusiveListNode list_node;
|
||||||
|
IDriver *driver;
|
||||||
|
ISession::List session_list;
|
||||||
|
mutable os::SdkMutex session_list_lock;
|
||||||
|
bool is_exclusive_write;
|
||||||
|
public:
|
||||||
|
using ListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&IDevice::list_node>;
|
||||||
|
using List = typename ListTraits::ListType;
|
||||||
|
friend class util::IntrusiveList<IDevice, util::IntrusiveListMemberTraitsDeferredAssert<&IDevice::list_node>>;
|
||||||
|
private:
|
||||||
|
Result AttachSession(ISession *session) {
|
||||||
|
AMS_ASSERT(session != nullptr);
|
||||||
|
std::scoped_lock lk(this->session_list_lock);
|
||||||
|
|
||||||
|
/* Check if we're allowed to attach the session. */
|
||||||
|
if (this->is_exclusive_write && session->CheckExclusiveWrite()) {
|
||||||
|
for (const auto &attached : this->session_list) {
|
||||||
|
R_UNLESS(!attached.CheckAccess(AccessMode_Write), ddsf::ResultAccessModeDenied());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach the session. */
|
||||||
|
this->session_list.push_back(*session);
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetachSession(ISession *session) {
|
||||||
|
AMS_ASSERT(session != nullptr);
|
||||||
|
std::scoped_lock lk(this->session_list_lock);
|
||||||
|
this->session_list.erase(this->session_list.iterator_to(*session));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachDriver(IDriver *drv) {
|
||||||
|
AMS_ASSERT(drv != nullptr);
|
||||||
|
AMS_ASSERT(!this->IsDriverAttached());
|
||||||
|
this->driver = drv;
|
||||||
|
AMS_ASSERT(this->IsDriverAttached());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetachDriver() {
|
||||||
|
AMS_ASSERT(this->IsDriverAttached());
|
||||||
|
this->driver = nullptr;
|
||||||
|
AMS_ASSERT(!this->IsDriverAttached());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
IDevice(bool exclusive_write) : list_node(), driver(nullptr), session_list(), session_list_lock(), is_exclusive_write(exclusive_write) {
|
||||||
|
this->session_list.clear();
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
~IDevice() {
|
||||||
|
this->session_list.clear();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void AddTo(List &list) {
|
||||||
|
list.push_back(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveFrom(List list) {
|
||||||
|
list.erase(list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLinkedToList() const {
|
||||||
|
return this->list_node.IsLinked();
|
||||||
|
}
|
||||||
|
|
||||||
|
IDriver &GetDriver() {
|
||||||
|
AMS_ASSERT(this->IsDriverAttached());
|
||||||
|
return *this->driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IDriver &GetDriver() const {
|
||||||
|
AMS_ASSERT(this->IsDriverAttached());
|
||||||
|
return *this->driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDriverAttached() const {
|
||||||
|
return this->driver != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
Result ForEachSession(F f, bool return_on_fail) {
|
||||||
|
return impl::ForEach(this->session_list_lock, this->session_list, f, return_on_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
Result ForEachSession(F f, bool return_on_fail) const {
|
||||||
|
return impl::ForEach(this->session_list_lock, this->session_list, f, return_on_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachSession(F f) {
|
||||||
|
return impl::ForEach(this->session_list_lock, this->session_list, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachSession(F f) const {
|
||||||
|
return impl::ForEach(this->session_list_lock, this->session_list, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasAnyOpenSession() const {
|
||||||
|
return !this->session_list.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(IDevice::ListTraits::IsValid());
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_sdk_mutex.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/impl/ddsf_for_each.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_castable.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_device.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class IDriver : public ICastable {
|
||||||
|
public:
|
||||||
|
AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDriver);
|
||||||
|
private:
|
||||||
|
util::IntrusiveListNode list_node;
|
||||||
|
IDevice::List device_list;
|
||||||
|
mutable os::SdkMutex device_list_lock;
|
||||||
|
public:
|
||||||
|
using ListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&IDriver::list_node>;
|
||||||
|
using List = typename ListTraits::ListType;
|
||||||
|
friend class util::IntrusiveList<IDriver, util::IntrusiveListMemberTraitsDeferredAssert<&IDriver::list_node>>;
|
||||||
|
private:
|
||||||
|
public:
|
||||||
|
IDriver() : list_node(), device_list(), device_list_lock() {
|
||||||
|
this->device_list.clear();
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
~IDriver() {
|
||||||
|
this->device_list.clear();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void AddTo(List &list) {
|
||||||
|
list.push_back(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveFrom(List list) {
|
||||||
|
list.erase(list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLinkedToList() const {
|
||||||
|
return this->list_node.IsLinked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasAnyDevice() const {
|
||||||
|
return !this->device_list.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterDevice(IDevice *dev) {
|
||||||
|
AMS_ASSERT(dev != nullptr);
|
||||||
|
std::scoped_lock lk(this->device_list_lock);
|
||||||
|
dev->AttachDriver(this);
|
||||||
|
this->device_list.push_back(*dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnregisterDevice(IDevice *dev) {
|
||||||
|
AMS_ASSERT(dev != nullptr);
|
||||||
|
std::scoped_lock lk(this->device_list_lock);
|
||||||
|
this->device_list.erase(this->device_list.iterator_to(*dev));
|
||||||
|
dev->DetachDriver();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
Result ForEachDevice(F f, bool return_on_fail) {
|
||||||
|
return impl::ForEach(this->device_list_lock, this->device_list, f, return_on_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
Result ForEachDevice(F f, bool return_on_fail) const {
|
||||||
|
return impl::ForEach(this->device_list_lock, this->device_list, f, return_on_fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachDevice(F f) {
|
||||||
|
return impl::ForEach(this->device_list_lock, this->device_list, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
int ForEachDevice(F f) const {
|
||||||
|
return impl::ForEach(this->device_list_lock, this->device_list, f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(IDriver::ListTraits::IsValid());
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class EventHandlerManager;
|
||||||
|
|
||||||
|
class IEventHandler {
|
||||||
|
NON_COPYABLE(IEventHandler);
|
||||||
|
NON_MOVEABLE(IEventHandler);
|
||||||
|
friend class EventHandlerManager;
|
||||||
|
private:
|
||||||
|
os::WaitableHolderType holder;
|
||||||
|
uintptr_t user_data;
|
||||||
|
bool is_initialized;
|
||||||
|
bool is_registered;
|
||||||
|
private:
|
||||||
|
void Link(os::WaitableManagerType *manager) {
|
||||||
|
AMS_ASSERT(this->IsInitialized());
|
||||||
|
AMS_ASSERT(!this->IsRegistered());
|
||||||
|
AMS_ASSERT(manager != nullptr);
|
||||||
|
os::LinkWaitableHolder(manager, std::addressof(this->holder));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unlink() {
|
||||||
|
AMS_ASSERT(this->IsInitialized());
|
||||||
|
AMS_ASSERT(this->IsRegistered());
|
||||||
|
os::UnlinkWaitableHolder(std::addressof(this->holder));
|
||||||
|
}
|
||||||
|
|
||||||
|
static IEventHandler &ToEventHandler(os::WaitableHolderType *holder) {
|
||||||
|
AMS_ASSERT(holder != nullptr);
|
||||||
|
auto &event_handler = *reinterpret_cast<IEventHandler *>(os::GetWaitableHolderUserData(holder));
|
||||||
|
AMS_ASSERT(event_handler.IsInitialized());
|
||||||
|
return event_handler;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
IEventHandler() : holder(), user_data(0), is_initialized(false), is_registered(false) { /* ... */ }
|
||||||
|
|
||||||
|
~IEventHandler() {
|
||||||
|
if (this->IsRegistered()) {
|
||||||
|
this->Unlink();
|
||||||
|
}
|
||||||
|
if (this->IsInitialized()) {
|
||||||
|
this->Finalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInitialized() const { return this->is_initialized; }
|
||||||
|
bool IsRegistered() const { return this->is_registered; }
|
||||||
|
|
||||||
|
uintptr_t GetUserData() const { return this->user_data; }
|
||||||
|
void SetUserData(uintptr_t d) { this->user_data = d; }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Initialize(T *object) {
|
||||||
|
AMS_ASSERT(object != nullptr);
|
||||||
|
AMS_ASSERT(!this->IsInitialized());
|
||||||
|
os::InitializeWaitableHolder(std::addressof(this->holder), object);
|
||||||
|
os::SetWaitableHolderUserData(std::addressof(this->holder), reinterpret_cast<uintptr_t>(this));
|
||||||
|
this->is_initialized = true;
|
||||||
|
this->is_registered = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() {
|
||||||
|
AMS_ASSERT(this->IsInitialized());
|
||||||
|
AMS_ASSERT(!this->IsRegistered());
|
||||||
|
os::FinalizeWaitableHolder(std::addressof(this->holder));
|
||||||
|
this->is_initialized = false;
|
||||||
|
this->is_registered = false;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
virtual void HandleEvent() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
#include <stratosphere/ddsf/impl/ddsf_for_each.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_i_castable.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
class ISession;
|
||||||
|
class IDevice;
|
||||||
|
|
||||||
|
Result OpenSession(IDevice *device, ISession *session, AccessMode access_mode);
|
||||||
|
void CloseSession(ISession *session);
|
||||||
|
|
||||||
|
class ISession : public ICastable {
|
||||||
|
friend Result OpenSession(IDevice *device, ISession *session, AccessMode mode);
|
||||||
|
friend void CloseSession(ISession *session);
|
||||||
|
public:
|
||||||
|
AMS_DDSF_CASTABLE_ROOT_TRAITS(ams::ddsf::IDevice);
|
||||||
|
private:
|
||||||
|
util::IntrusiveListNode list_node;
|
||||||
|
IDevice *device;
|
||||||
|
AccessMode access_mode;
|
||||||
|
public:
|
||||||
|
using ListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&ISession::list_node>;
|
||||||
|
using List = typename ListTraits::ListType;
|
||||||
|
friend class util::IntrusiveList<ISession, util::IntrusiveListMemberTraitsDeferredAssert<&ISession::list_node>>;
|
||||||
|
private:
|
||||||
|
void AttachDevice(IDevice *dev, AccessMode mode) {
|
||||||
|
AMS_ASSERT(dev != nullptr);
|
||||||
|
AMS_ASSERT(!this->IsOpen());
|
||||||
|
this->device = dev;
|
||||||
|
this->access_mode = mode;
|
||||||
|
AMS_ASSERT(this->IsOpen());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DetachDevice() {
|
||||||
|
AMS_ASSERT(this->IsOpen());
|
||||||
|
this->device = nullptr;
|
||||||
|
this->access_mode = AccessMode_None;
|
||||||
|
AMS_ASSERT(!this->IsOpen());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
ISession() : list_node(), device(nullptr), access_mode() { /* ... */ }
|
||||||
|
protected:
|
||||||
|
~ISession() { this->DetachDevice(); AMS_ASSERT(!this->IsOpen()); }
|
||||||
|
public:
|
||||||
|
void AddTo(List &list) {
|
||||||
|
list.push_back(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveFrom(List list) {
|
||||||
|
list.erase(list.iterator_to(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLinkedToList() const {
|
||||||
|
return this->list_node.IsLinked();
|
||||||
|
}
|
||||||
|
|
||||||
|
IDevice &GetDevice() {
|
||||||
|
AMS_ASSERT(this->IsOpen());
|
||||||
|
return *this->device;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IDevice &GetDevice() const {
|
||||||
|
AMS_ASSERT(this->IsOpen());
|
||||||
|
return *this->device;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOpen() const {
|
||||||
|
return this->device != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckAccess(AccessMode mode) const {
|
||||||
|
AMS_ASSERT(this->IsOpen());
|
||||||
|
return ((~this->access_mode) & mode) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckExclusiveWrite() const {
|
||||||
|
return this->CheckAccess(AccessMode_Write) && !this->CheckAccess(AccessMode_Shared);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(ISession::ListTraits::IsValid());
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_device_code_entry.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
void SetMemoryResource(ams::MemoryResource *mr);
|
||||||
|
ams::MemoryResource *GetMemoryResource();
|
||||||
|
|
||||||
|
static constexpr size_t DeviceCodeEntryHolderSize = sizeof(DeviceCodeEntryHolder);
|
||||||
|
|
||||||
|
void SetDeviceCodeEntryHolderMemoryResource(ams::MemoryResource *mr);
|
||||||
|
ams::MemoryResource *GetDeviceCodeEntryHolderMemoryResource();
|
||||||
|
|
||||||
|
}
|
|
@ -20,11 +20,14 @@
|
||||||
namespace ams::ddsf {
|
namespace ams::ddsf {
|
||||||
|
|
||||||
enum AccessMode {
|
enum AccessMode {
|
||||||
AccessMode_None = (0u << 0),
|
AccessMode_None = (0u << 0),
|
||||||
AccessMode_Read = (1u << 0),
|
AccessMode_Read = (1u << 0),
|
||||||
AccessMode_Write = (1u << 1),
|
AccessMode_Write = (1u << 1),
|
||||||
|
AccessMode_Shared = (1u << 2),
|
||||||
|
|
||||||
AccessMode_ReadWrite = AccessMode_Read | AccessMode_Write,
|
AccessMode_ReadWrite = AccessMode_Read | AccessMode_Write,
|
||||||
|
AccessMode_WriteShared = AccessMode_Write | AccessMode_Shared,
|
||||||
|
AccessMode_ReadWriteShared = AccessMode_Read | AccessMode_WriteShared,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf::impl {
|
||||||
|
|
||||||
|
template<typename Lock, typename List, typename F>
|
||||||
|
inline Result ForEach(Lock &lock, List &list, F f, bool return_on_fail) {
|
||||||
|
std::scoped_lock lk(lock);
|
||||||
|
|
||||||
|
Result result = ResultSuccess();
|
||||||
|
for (auto && it : list) {
|
||||||
|
if (const auto cur_result = f(std::addressof(it)); R_FAILED(cur_result)) {
|
||||||
|
if (return_on_fail) {
|
||||||
|
return cur_result;
|
||||||
|
} else if (R_SUCCEEDED(result)) {
|
||||||
|
result = cur_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename List, typename F, typename Lock>
|
||||||
|
inline int ForEach(Lock &lock, List &list, F f) {
|
||||||
|
std::scoped_lock lk(lock);
|
||||||
|
|
||||||
|
int success_count = 0;
|
||||||
|
for (auto && it : list) {
|
||||||
|
if (!f(it)) {
|
||||||
|
return success_count;
|
||||||
|
}
|
||||||
|
++success_count;
|
||||||
|
}
|
||||||
|
return success_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/ddsf/ddsf_types.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf::impl {
|
||||||
|
|
||||||
|
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||||
|
|
||||||
|
#define AMS_DDSF_CASTABLE_ROOT_TRAITS(__CLASS__) \
|
||||||
|
public: \
|
||||||
|
static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag(#__CLASS__); \
|
||||||
|
constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define AMS_DDSF_CASTABLE_ROOT_TRAITS(__CLASS__) \
|
||||||
|
public: \
|
||||||
|
static constexpr inline ::ams::ddsf::impl::TypeTag s_ams_ddsf_castable_type_tag{}; \
|
||||||
|
constexpr virtual const ::ams::ddsf::impl::TypeTag &GetTypeTag() const override { return s_ams_ddsf_castable_type_tag; }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TypeTag {
|
||||||
|
private:
|
||||||
|
const char * const class_name;
|
||||||
|
const TypeTag * const base;
|
||||||
|
public:
|
||||||
|
#if !(defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING))
|
||||||
|
constexpr TypeTag() : class_name(nullptr), base(nullptr) { /* ... */}
|
||||||
|
constexpr TypeTag(const TypeTag &b) : class_name(nullptr), base(std::addressof(b)) { AMS_ASSERT(this != this->base); }
|
||||||
|
|
||||||
|
constexpr TypeTag(const char *c) : class_name(nullptr), base(nullptr) { AMS_UNUSED(c); }
|
||||||
|
constexpr TypeTag(const char *c, const TypeTag &b) : class_name(nullptr), base(std::addressof(b)) { AMS_UNUSED(c); AMS_ASSERT(this != this->base); }
|
||||||
|
#else
|
||||||
|
constexpr TypeTag(const char *c) : class_name(c), base(nullptr) { /* ... */ }
|
||||||
|
constexpr TypeTag(const char *c, const TypeTag &b) : class_name(c), base(std::addressof(b)) { AMS_ASSERT(this != this->base); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr const char * GetClassName() const { return this->class_name; }
|
||||||
|
|
||||||
|
constexpr bool Is(const TypeTag &rhs) const { return this == std::addressof(rhs); }
|
||||||
|
|
||||||
|
constexpr bool DerivesFrom(const TypeTag &rhs) const {
|
||||||
|
const TypeTag * cur = this;
|
||||||
|
while (cur != nullptr) {
|
||||||
|
if (cur == std::addressof(rhs)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cur = cur->base;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
#include <stratosphere/os/os_mutex.hpp>
|
#include <stratosphere/os/os_mutex.hpp>
|
||||||
#include <stratosphere/os/os_condition_variable.hpp>
|
#include <stratosphere/os/os_condition_variable.hpp>
|
||||||
#include <stratosphere/os/os_sdk_mutex.hpp>
|
#include <stratosphere/os/os_sdk_mutex.hpp>
|
||||||
|
#include <stratosphere/os/os_sdk_condition_variable.hpp>
|
||||||
#include <stratosphere/os/os_rw_lock.hpp>
|
#include <stratosphere/os/os_rw_lock.hpp>
|
||||||
#include <stratosphere/os/os_transfer_memory.hpp>
|
#include <stratosphere/os/os_transfer_memory.hpp>
|
||||||
#include <stratosphere/os/os_semaphore.hpp>
|
#include <stratosphere/os/os_semaphore.hpp>
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/os/os_sdk_mutex.hpp>
|
||||||
|
#include <stratosphere/os/impl/os_internal_condition_variable.hpp>
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
struct SdkConditionVariableType {
|
||||||
|
union {
|
||||||
|
s32 _arr[sizeof(impl::InternalConditionVariableStorage) / sizeof(s32)];
|
||||||
|
impl::InternalConditionVariableStorage _storage;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Initialize() {
|
||||||
|
GetReference(this->_storage).Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait(SdkMutexType &mutex);
|
||||||
|
bool TimedWait(SdkMutexType &mutex, TimeSpan timeout);
|
||||||
|
|
||||||
|
/* TODO: SdkRecursiveMutexType */
|
||||||
|
|
||||||
|
void Signal() {
|
||||||
|
GetReference(this->_storage).Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcast() {
|
||||||
|
GetReference(this->_storage).Broadcast();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(std::is_trivial<SdkConditionVariableType>::value);
|
||||||
|
|
||||||
|
class SdkConditionVariable {
|
||||||
|
private:
|
||||||
|
SdkConditionVariableType cv;
|
||||||
|
public:
|
||||||
|
constexpr SdkConditionVariable() : cv{{0}} { /* ... */ }
|
||||||
|
|
||||||
|
void Wait(SdkMutex &m) {
|
||||||
|
return this->cv.Wait(m.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimedWait(SdkMutex &m, TimeSpan timeout) {
|
||||||
|
return this->cv.TimedWait(m.mutex, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: SdkRecursiveMutexType */
|
||||||
|
|
||||||
|
void Signal() {
|
||||||
|
return this->cv.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Broadcast() {
|
||||||
|
return this->cv.Broadcast();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
Result DeviceCodeEntryManager::Add(DeviceCode device_code, IDevice *device) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(device != nullptr);
|
||||||
|
AMS_ASSERT(device->IsDriverAttached());
|
||||||
|
|
||||||
|
/* Acquire exclusive access to the manager. */
|
||||||
|
std::scoped_lock lk(this->entry_list_lock);
|
||||||
|
|
||||||
|
/* Check that we don't already have an entry with the code. */
|
||||||
|
for (const auto &holder : this->entry_list) {
|
||||||
|
AMS_ASSERT(holder.IsConstructed());
|
||||||
|
AMS_ASSERT(holder.Get().GetDeviceCode() != device_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory for a new device code entry holder. */
|
||||||
|
void *holder_storage = this->memory_resource->Allocate(sizeof(DeviceCodeEntryHolder));
|
||||||
|
R_UNLESS(holder_storage != nullptr, ddsf::ResultOutOfResource());
|
||||||
|
|
||||||
|
/* Initialize the new holder. */
|
||||||
|
auto *holder = new (static_cast<DeviceCodeEntryHolder *>(holder_storage)) DeviceCodeEntryHolder;
|
||||||
|
holder->Construct(device_code, device);
|
||||||
|
|
||||||
|
/* Link the new holder. */
|
||||||
|
holder->AddTo(this->entry_list);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceCodeEntryManager::Remove(DeviceCode device_code) {
|
||||||
|
/* Acquire exclusive access to the manager. */
|
||||||
|
std::scoped_lock lk(this->entry_list_lock);
|
||||||
|
|
||||||
|
/* Find and erase the entry. */
|
||||||
|
bool erased = false;
|
||||||
|
for (auto it = this->entry_list.begin(); it != this->entry_list.end(); /* ... */) {
|
||||||
|
/* Get the current entry, and advance the iterator. */
|
||||||
|
DeviceCodeEntryHolder *cur = std::addressof(*(it++));
|
||||||
|
|
||||||
|
/* If the entry matches the device code, remove it. */
|
||||||
|
AMS_ASSERT(cur->IsConstructed());
|
||||||
|
if (cur->Get().GetDeviceCode() == device_code) {
|
||||||
|
/* Destroy and deallocate the holder. */
|
||||||
|
cur->Destroy();
|
||||||
|
cur->~DeviceCodeEntryHolder();
|
||||||
|
this->memory_resource->Deallocate(cur, sizeof(*cur));
|
||||||
|
|
||||||
|
erased = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return erased;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DeviceCodeEntryManager::FindDeviceCodeEntry(DeviceCodeEntry **out, DeviceCode device_code) {
|
||||||
|
/* Check arguments. */
|
||||||
|
AMS_ASSERT(out != nullptr);
|
||||||
|
R_UNLESS(out != nullptr, ddsf::ResultInvalidArgument());
|
||||||
|
|
||||||
|
/* Find the device. */
|
||||||
|
bool found = false;
|
||||||
|
this->ForEachEntry([&](DeviceCodeEntry &entry) -> bool {
|
||||||
|
if (entry.GetDeviceCode() == device_code) {
|
||||||
|
found = true;
|
||||||
|
*out = std::addressof(entry);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Check that we found the device. */
|
||||||
|
R_UNLESS(found, ddsf::ResultDeviceCodeNotFound());
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DeviceCodeEntryManager::FindDeviceCodeEntry(const DeviceCodeEntry **out, DeviceCode device_code) const {
|
||||||
|
/* Check arguments. */
|
||||||
|
AMS_ASSERT(out != nullptr);
|
||||||
|
R_UNLESS(out != nullptr, ddsf::ResultInvalidArgument());
|
||||||
|
|
||||||
|
/* Find the device. */
|
||||||
|
bool found = false;
|
||||||
|
this->ForEachEntry([&](const DeviceCodeEntry &entry) -> bool {
|
||||||
|
if (entry.GetDeviceCode() == device_code) {
|
||||||
|
found = true;
|
||||||
|
*out = std::addressof(entry);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Check that we found the device. */
|
||||||
|
R_UNLESS(found, ddsf::ResultDeviceCodeNotFound());
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DeviceCodeEntryManager::FindDevice(IDevice **out, DeviceCode device_code) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(out != nullptr);
|
||||||
|
|
||||||
|
/* Find the entry. */
|
||||||
|
DeviceCodeEntry *entry;
|
||||||
|
R_TRY(this->FindDeviceCodeEntry(std::addressof(entry), device_code));
|
||||||
|
|
||||||
|
/* Set the output. */
|
||||||
|
if (out != nullptr) {
|
||||||
|
*out = std::addressof(entry->GetDevice());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result DeviceCodeEntryManager::FindDevice(const IDevice **out, DeviceCode device_code) const {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(out != nullptr);
|
||||||
|
|
||||||
|
/* Find the entry. */
|
||||||
|
const DeviceCodeEntry *entry;
|
||||||
|
R_TRY(this->FindDeviceCodeEntry(std::addressof(entry), device_code));
|
||||||
|
|
||||||
|
/* Set the output. */
|
||||||
|
if (out != nullptr) {
|
||||||
|
*out = std::addressof(entry->GetDevice());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
215
libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp
Normal file
215
libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum class LoopControlCommand {
|
||||||
|
None = 0,
|
||||||
|
Register = 1,
|
||||||
|
Unregister = 2,
|
||||||
|
Terminate = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EventHandlerManager::LoopControlCommandParameters {
|
||||||
|
LoopControlCommand command;
|
||||||
|
IEventHandler *target;
|
||||||
|
|
||||||
|
LoopControlCommandParameters() : command(LoopControlCommand::None), target(nullptr) { /* ... */ }
|
||||||
|
LoopControlCommandParameters(LoopControlCommand c, IEventHandler *t) : command(c), target(t) { /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
void EventHandlerManager::Initialize() {
|
||||||
|
/* Check that we're not already initialized. */
|
||||||
|
AMS_ASSERT(!this->is_initialized);
|
||||||
|
if (this->is_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize waitable manager/holder. */
|
||||||
|
os::InitializeWaitableManager(std::addressof(this->waitable_manager));
|
||||||
|
os::InitializeWaitableHolder(std::addressof(this->loop_control_event_holder), this->loop_control_event.GetBase());
|
||||||
|
os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->loop_control_event_holder));
|
||||||
|
|
||||||
|
this->is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::Finalize() {
|
||||||
|
/* Check that we're initialized and not looping. */
|
||||||
|
AMS_ASSERT(!this->is_looping);
|
||||||
|
AMS_ASSERT(this->is_initialized);
|
||||||
|
if (!this->is_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize waitable manager/holder. */
|
||||||
|
os::UnlinkWaitableHolder(std::addressof(this->loop_control_event_holder));
|
||||||
|
os::FinalizeWaitableHolder(std::addressof(this->loop_control_event_holder));
|
||||||
|
os::FinalizeWaitableManager(std::addressof(this->waitable_manager));
|
||||||
|
|
||||||
|
this->is_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::ProcessControlCommand(LoopControlCommandParameters *params) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(this->is_initialized);
|
||||||
|
AMS_ASSERT(params != nullptr);
|
||||||
|
|
||||||
|
/* Acquire exclusive access. */
|
||||||
|
std::scoped_lock lk(this->loop_control_lock);
|
||||||
|
|
||||||
|
/* If we're processing for the loop thread, we can directly handle. */
|
||||||
|
if (!this->is_looping || this->IsRunningOnLoopThread()) {
|
||||||
|
this->ProcessControlCommandImpl(params);
|
||||||
|
} else {
|
||||||
|
/* Otherwise, signal to the loop thread. */
|
||||||
|
this->loop_control_command_params = params;
|
||||||
|
this->loop_control_event.Signal();
|
||||||
|
this->loop_control_command_done_event.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::ProcessControlCommandImpl(LoopControlCommandParameters *params) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(this->loop_control_lock.IsLockedByCurrentThread() || !this->loop_control_lock.TryLock());
|
||||||
|
AMS_ASSERT(params != nullptr);
|
||||||
|
AMS_ASSERT(params->target != nullptr);
|
||||||
|
|
||||||
|
/* Process the command. */
|
||||||
|
switch (params->command) {
|
||||||
|
case LoopControlCommand::Register:
|
||||||
|
params->target->Link(std::addressof(this->waitable_manager));
|
||||||
|
break;
|
||||||
|
case LoopControlCommand::Unregister:
|
||||||
|
params->target->Unlink();
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::RegisterHandler(IEventHandler *handler) {
|
||||||
|
/* Check that the handler is valid. */
|
||||||
|
AMS_ASSERT(handler != nullptr);
|
||||||
|
AMS_ASSERT(handler->IsInitialized());
|
||||||
|
|
||||||
|
/* Send registration command. */
|
||||||
|
LoopControlCommandParameters params(LoopControlCommand::Register, handler);
|
||||||
|
return this->ProcessControlCommand(std::addressof(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::UnregisterHandler(IEventHandler *handler) {
|
||||||
|
/* Check that the handler is valid. */
|
||||||
|
AMS_ASSERT(handler != nullptr);
|
||||||
|
AMS_ASSERT(handler->IsInitialized());
|
||||||
|
|
||||||
|
/* Send registration command. */
|
||||||
|
LoopControlCommandParameters params(LoopControlCommand::Unregister, handler);
|
||||||
|
return this->ProcessControlCommand(std::addressof(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::WaitLoopEnter() {
|
||||||
|
/* Acquire exclusive access. */
|
||||||
|
std::scoped_lock lk(this->loop_control_lock);
|
||||||
|
|
||||||
|
/* Wait until we're looping. */
|
||||||
|
while (!this->is_looping) {
|
||||||
|
this->is_looping_cv.Wait(this->loop_control_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::WaitLoopExit() {
|
||||||
|
/* Acquire exclusive access. */
|
||||||
|
std::scoped_lock lk(this->loop_control_lock);
|
||||||
|
|
||||||
|
/* Wait until we're not looping. */
|
||||||
|
while (this->is_looping) {
|
||||||
|
this->is_looping_cv.Wait(this->loop_control_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::RequestStop() {
|
||||||
|
/* Check that we're looping and not the loop thread. */
|
||||||
|
AMS_ASSERT(this->is_looping);
|
||||||
|
AMS_ASSERT(!this->IsRunningOnLoopThread());
|
||||||
|
|
||||||
|
if (this->is_looping) {
|
||||||
|
/* Acquire exclusive access. */
|
||||||
|
std::scoped_lock lk(this->loop_control_lock);
|
||||||
|
|
||||||
|
/* Signal to the loop thread. */
|
||||||
|
LoopControlCommandParameters params(LoopControlCommand::Terminate, nullptr);
|
||||||
|
this->loop_control_command_params = std::addressof(params);
|
||||||
|
this->loop_control_event.Signal();
|
||||||
|
this->loop_control_command_done_event.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventHandlerManager::LoopAuto() {
|
||||||
|
/* Check that we're not already looping. */
|
||||||
|
AMS_ASSERT(!this->is_looping);
|
||||||
|
|
||||||
|
/* Begin looping with the current thread. */
|
||||||
|
this->loop_thread = os::GetCurrentThread();
|
||||||
|
this->is_looping = true;
|
||||||
|
this->is_looping_cv.Broadcast();
|
||||||
|
|
||||||
|
/* Whenever we're done looping, clean up. */
|
||||||
|
ON_SCOPE_EXIT {
|
||||||
|
this->loop_thread = nullptr;
|
||||||
|
this->is_looping = false;
|
||||||
|
this->is_looping_cv.Broadcast();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Loop until we're asked to stop. */
|
||||||
|
bool should_terminate = false;
|
||||||
|
while (!should_terminate) {
|
||||||
|
/* Wait for a holder to be signaled. */
|
||||||
|
os::WaitableHolderType *event_holder = os::WaitAny(std::addressof(this->waitable_manager));
|
||||||
|
AMS_ASSERT(event_holder != nullptr);
|
||||||
|
|
||||||
|
/* Check if we have a request to handle. */
|
||||||
|
if (event_holder == std::addressof(this->loop_control_event_holder)) {
|
||||||
|
/* Check that the request hasn't already been handled. */
|
||||||
|
if (this->loop_control_event.TryWait()) {
|
||||||
|
/* Handle the request. */
|
||||||
|
AMS_ASSERT(this->loop_control_command_params != nullptr);
|
||||||
|
switch (this->loop_control_command_params->command) {
|
||||||
|
case LoopControlCommand::Register:
|
||||||
|
case LoopControlCommand::Unregister:
|
||||||
|
this->ProcessControlCommandImpl(this->loop_control_command_params);
|
||||||
|
break;
|
||||||
|
case LoopControlCommand::Terminate:
|
||||||
|
should_terminate = true;
|
||||||
|
break;
|
||||||
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the request, and signal that it's done. */
|
||||||
|
this->loop_control_command_params = nullptr;
|
||||||
|
this->loop_control_command_done_event.Signal();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Handle the event. */
|
||||||
|
IEventHandler::ToEventHandler(event_holder).HandleEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
libraries/libstratosphere/source/ddsf/ddsf_memory_api.cpp
Normal file
49
libraries/libstratosphere/source/ddsf/ddsf_memory_api.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constinit ams::MemoryResource *g_memory_resource = nullptr;
|
||||||
|
constinit ams::MemoryResource *g_device_code_entry_holder_memory_resource = nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMemoryResource(ams::MemoryResource *mr) {
|
||||||
|
AMS_ASSERT(g_memory_resource == nullptr);
|
||||||
|
g_memory_resource = mr;
|
||||||
|
AMS_ASSERT(g_memory_resource != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ams::MemoryResource *GetMemoryResource() {
|
||||||
|
AMS_ASSERT(g_memory_resource != nullptr);
|
||||||
|
return g_memory_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDeviceCodeEntryHolderMemoryResource(ams::MemoryResource *mr) {
|
||||||
|
AMS_ASSERT(g_device_code_entry_holder_memory_resource == nullptr);
|
||||||
|
g_device_code_entry_holder_memory_resource = mr;
|
||||||
|
AMS_ASSERT(g_device_code_entry_holder_memory_resource != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
ams::MemoryResource *GetDeviceCodeEntryHolderMemoryResource() {
|
||||||
|
AMS_ASSERT(g_device_code_entry_holder_memory_resource != nullptr);
|
||||||
|
return g_device_code_entry_holder_memory_resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
libraries/libstratosphere/source/ddsf/ddsf_session_api.cpp
Normal file
49
libraries/libstratosphere/source/ddsf/ddsf_session_api.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
Result OpenSession(IDevice *device, ISession *session, AccessMode access_mode) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(device != nullptr);
|
||||||
|
AMS_ASSERT(session != nullptr);
|
||||||
|
AMS_ASSERT(!session->IsOpen());
|
||||||
|
|
||||||
|
/* Attack the session to the device. */
|
||||||
|
session->AttachDevice(device, access_mode);
|
||||||
|
auto session_guard = SCOPE_GUARD { session->DetachDevice(); };
|
||||||
|
|
||||||
|
/* Attach the device to the session. */
|
||||||
|
R_TRY(device->AttachSession(session));
|
||||||
|
|
||||||
|
/* We succeeded. */
|
||||||
|
session_guard.Cancel();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseSession(ISession *session) {
|
||||||
|
/* Check pre-conditions. */
|
||||||
|
AMS_ASSERT(session != nullptr);
|
||||||
|
|
||||||
|
/* Detach the device from the session. */
|
||||||
|
session->GetDevice().DetachSession(session);
|
||||||
|
|
||||||
|
/* Detach the session from the device. */
|
||||||
|
session->DetachDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include "impl/os_thread_manager.hpp"
|
||||||
|
#include "impl/os_timeout_helper.hpp"
|
||||||
|
|
||||||
|
namespace ams::os {
|
||||||
|
|
||||||
|
void SdkConditionVariableType::Wait(SdkMutexType &mutex) {
|
||||||
|
/* Check that we own the mutex. */
|
||||||
|
AMS_ABORT_UNLESS(os::IsSdkMutexLockedByCurrentThread(std::addressof(mutex)));
|
||||||
|
|
||||||
|
/* Wait on the mutex. */
|
||||||
|
GetReference(this->_storage).Wait(GetPointer(mutex._storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SdkConditionVariableType::TimedWait(SdkMutexType &mutex, TimeSpan timeout) {
|
||||||
|
/* Check preconditions. */
|
||||||
|
AMS_ASSERT(timeout.GetNanoSeconds() >= 0);
|
||||||
|
AMS_ABORT_UNLESS(os::IsSdkMutexLockedByCurrentThread(std::addressof(mutex)));
|
||||||
|
|
||||||
|
/* Handle zero timeout by unlocking and re-locking. */
|
||||||
|
if (timeout == TimeSpan(0)) {
|
||||||
|
GetReference(mutex._storage).Leave();
|
||||||
|
GetReference(mutex._storage).Enter();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle timed wait. */
|
||||||
|
impl::TimeoutHelper timeout_helper(timeout);
|
||||||
|
auto status = GetReference(this->_storage).TimedWait(GetPointer(mutex._storage), timeout_helper);
|
||||||
|
return status == ConditionVariableStatus::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
#include <vapours/results/cal_results.hpp>
|
#include <vapours/results/cal_results.hpp>
|
||||||
#include <vapours/results/capsrv_results.hpp>
|
#include <vapours/results/capsrv_results.hpp>
|
||||||
#include <vapours/results/creport_results.hpp>
|
#include <vapours/results/creport_results.hpp>
|
||||||
|
#include <vapours/results/ddsf_results.hpp>
|
||||||
#include <vapours/results/debug_results.hpp>
|
#include <vapours/results/debug_results.hpp>
|
||||||
#include <vapours/results/dmnt_results.hpp>
|
#include <vapours/results/dmnt_results.hpp>
|
||||||
#include <vapours/results/erpt_results.hpp>
|
#include <vapours/results/erpt_results.hpp>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vapours/results/results_common.hpp>
|
||||||
|
|
||||||
|
namespace ams::ddsf {
|
||||||
|
|
||||||
|
R_DEFINE_NAMESPACE_RESULT_MODULE(30);
|
||||||
|
|
||||||
|
R_DEFINE_ERROR_RESULT(OutOfResource, 1);
|
||||||
|
R_DEFINE_ERROR_RESULT(NotSupported, 2);
|
||||||
|
R_DEFINE_ERROR_RESULT(InvalidArgument, 3);
|
||||||
|
R_DEFINE_ERROR_RESULT(PermissionDenied, 4);
|
||||||
|
R_DEFINE_ERROR_RESULT(AccessModeDenied, 5);
|
||||||
|
R_DEFINE_ERROR_RESULT(DeviceCodeNotFound, 6);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue