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

View file

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

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

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

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

View file

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

View file

@ -26,6 +26,7 @@
#include <vapours/results/cal_results.hpp>
#include <vapours/results/capsrv_results.hpp>
#include <vapours/results/creport_results.hpp>
#include <vapours/results/ddsf_results.hpp>
#include <vapours/results/debug_results.hpp>
#include <vapours/results/dmnt_results.hpp>
#include <vapours/results/erpt_results.hpp>

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/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);
}