ddsf: implement namespace

This commit is contained in:
Michael Scire
2020-10-30 15:36:11 -07:00
committed by SciresM
parent d2e530c2aa
commit ddf2f5f3c5
23 changed files with 1578 additions and 5 deletions

View File

@@ -43,6 +43,7 @@
#include <stratosphere/boot2.hpp>
#include <stratosphere/capsrv.hpp>
#include <stratosphere/cfg.hpp>
#include <stratosphere/ddsf.hpp>
#include <stratosphere/dmnt.hpp>
#include <stratosphere/erpt.hpp>
#include <stratosphere/err.hpp>

View File

@@ -13,7 +13,15 @@
* 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 <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>

View File

@@ -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());
}

View File

@@ -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());
});
}
};
}

View File

@@ -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();
};
}

View File

@@ -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
};
}

View File

@@ -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());
}

View File

@@ -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());
}

View File

@@ -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;
};
}

View File

@@ -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());
}

View File

@@ -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();
}

View File

@@ -20,11 +20,14 @@
namespace ams::ddsf {
enum AccessMode {
AccessMode_None = (0u << 0),
AccessMode_Read = (1u << 0),
AccessMode_Write = (1u << 1),
AccessMode_None = (0u << 0),
AccessMode_Read = (1u << 0),
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,
};
}

View File

@@ -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;
}
}

View File

@@ -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;
}
};
}

View File

@@ -28,6 +28,7 @@
#include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condition_variable.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_transfer_memory.hpp>
#include <stratosphere/os/os_semaphore.hpp>

View File

@@ -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();
}
};
}