diff --git a/include/stratosphere.hpp b/include/stratosphere.hpp index 000a8b74..7d861a8a 100644 --- a/include/stratosphere.hpp +++ b/include/stratosphere.hpp @@ -1,5 +1,7 @@ #pragma once +#include "stratosphere/ipc_templating.hpp" + #include "stratosphere/iwaitable.hpp" #include "stratosphere/iserviceobject.hpp" #include "stratosphere/iserver.hpp" @@ -8,12 +10,9 @@ #include "stratosphere/serviceserver.hpp" #include "stratosphere/managedportserver.hpp" #include "stratosphere/existingportserver.hpp" -#include "stratosphere/childholder.hpp" #include "stratosphere/ievent.hpp" #include "stratosphere/systemevent.hpp" #include "stratosphere/hossynch.hpp" #include "stratosphere/waitablemanager.hpp" - -#include "stratosphere/ipc_templating.hpp" \ No newline at end of file diff --git a/include/stratosphere/childholder.hpp b/include/stratosphere/childholder.hpp deleted file mode 100644 index 428ccef6..00000000 --- a/include/stratosphere/childholder.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include -#include - -#include "iwaitable.hpp" - -class ChildWaitableHolder : public IWaitable { - protected: - std::vector children; - - public: - /* Implicit constructor. */ - - void add_child(IWaitable *child) { - this->children.push_back(child); - } - - virtual ~ChildWaitableHolder() { - for (unsigned int i = 0; i < this->children.size(); i++) { - delete this->children[i]; - } - this->children.clear(); - } - - /* IWaitable */ - virtual unsigned int get_num_waitables() { - unsigned int n = 0; - for (unsigned int i = 0; i < this->children.size(); i++) { - if (this->children[i]) { - n += this->children[i]->get_num_waitables(); - } - } - return n; - } - - virtual void get_waitables(IWaitable **dst) { - unsigned int n = 0; - for (unsigned int i = 0; i < this->children.size(); i++) { - if (this->children[i]) { - this->children[i]->get_waitables(&dst[n]); - n += this->children[i]->get_num_waitables(); - } - } - } - - virtual void delete_child(IWaitable *child) { - unsigned int i; - for (i = 0; i < this->children.size(); i++) { - if (this->children[i] == child) { - break; - } - } - - if (i == this->children.size()) { - /* TODO: Panic, because this isn't our child. */ - } else { - delete this->children[i]; - this->children.erase(this->children.begin() + i); - } - } - - virtual Handle get_handle() { - /* We don't have a handle. */ - return 0; - } - - - virtual void handle_deferred() { - /* TODO: Panic, because we can never defer a server. */ - } - - virtual Result handle_signaled(u64 timeout) { - /* TODO: Panic, because we can never be signalled. */ - return 0; - } -}; \ No newline at end of file diff --git a/include/stratosphere/domainowner.hpp b/include/stratosphere/domainowner.hpp new file mode 100644 index 00000000..bf7b560f --- /dev/null +++ b/include/stratosphere/domainowner.hpp @@ -0,0 +1,80 @@ +#pragma once +#include +#include + +#include "iserviceobject.hpp" + +#define DOMAIN_ID_MAX 0x200 + +class IServiceObject; + +class DomainOwner { + private: + IServiceObject *domain_objects[DOMAIN_ID_MAX]; + public: + DomainOwner() { + for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) { + domain_objects[i] = NULL; + } + } + + virtual ~DomainOwner() { + for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) { + this->delete_object(i); + } + } + + IServiceObject *get_domain_object(unsigned int i) { + if (i < DOMAIN_ID_MAX) { + return domain_objects[i]; + } + return NULL; + } + + Result reserve_object(IServiceObject *object, unsigned int *out_i) { + for (unsigned int i = 4; i < DOMAIN_ID_MAX; i++) { + if (domain_objects[i] == NULL) { + domain_objects[i] = object; + object->set_owner(this); + *out_i = i; + return 0; + } + } + return 0x1900B; + } + + Result set_object(IServiceObject *object, unsigned int i) { + if (domain_objects[i] == NULL) { + domain_objects[i] = object; + object->set_owner(this); + return 0; + } + return 0x1900B; + } + + unsigned int get_object_id(IServiceObject *object) { + for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) { + if (domain_objects[i] == object) { + return i; + } + } + return DOMAIN_ID_MAX; + } + + void delete_object(unsigned int i) { + if (domain_objects[i]) { + delete domain_objects[i]; + domain_objects[i] = NULL; + } + } + + void delete_object(IServiceObject *object) { + for (unsigned int i = 0; i < DOMAIN_ID_MAX; i++) { + if (domain_objects[i] == object) { + delete domain_objects[i]; + domain_objects[i] = NULL; + break; + } + } + } +}; \ No newline at end of file diff --git a/include/stratosphere/existingportserver.hpp b/include/stratosphere/existingportserver.hpp index 4ec15b00..d026fb67 100644 --- a/include/stratosphere/existingportserver.hpp +++ b/include/stratosphere/existingportserver.hpp @@ -5,7 +5,11 @@ template class ExistingPortServer : public IServer { public: - ExistingPortServer(Handle port_h, unsigned int max_s) : IServer(NULL, max_s) { + ExistingPortServer(Handle port_h, unsigned int max_s, bool s_d = false) : IServer(NULL, max_s, s_d) { this->port_handle = port_h; } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/include/stratosphere/ievent.hpp b/include/stratosphere/ievent.hpp index c30f11bb..ae41a912 100644 --- a/include/stratosphere/ievent.hpp +++ b/include/stratosphere/ievent.hpp @@ -27,24 +27,7 @@ class IEvent : public IWaitable { virtual Result signal_event() = 0; - /* IWaitable */ - virtual unsigned int get_num_waitables() { - if (handles.size() > 0) { - return 1; - } - return 0; - } - - virtual void get_waitables(IWaitable **dst) { - if (handles.size() > 0) { - dst[0] = this; - } - } - - virtual void delete_child(IWaitable *child) { - /* TODO: Panic, an event can never be a parent. */ - } - + /* IWaitable */ virtual Handle get_handle() { if (handles.size() > 0) { return this->handles[0]; diff --git a/include/stratosphere/ipc_templating.hpp b/include/stratosphere/ipc_templating.hpp index e3cca287..2ea9187e 100644 --- a/include/stratosphere/ipc_templating.hpp +++ b/include/stratosphere/ipc_templating.hpp @@ -6,6 +6,8 @@ #include "../boost/callable_traits.hpp" #include +#include "domainowner.hpp" + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -88,6 +90,21 @@ struct CopiedHandle { CopiedHandle(Handle h) : handle(h) { } }; +/* Forward declarations. */ +template +class ISession; + +/* Represents an output ServiceObject. */ +struct OutSessionBase {}; + +template +struct OutSession : OutSessionBase { + ISession *session; + u32 domain_id; + + OutSession(ISession *s) : session(s), domain_id(DOMAIN_ID_MAX) { } +}; + /* Utilities. */ template class Template> struct is_specialization_of { @@ -117,9 +134,14 @@ struct is_ipc_handle { static const size_t value = (std::is_same::value || std::is_same::value) ? 1 : 0; }; +template +struct is_out_session { + static const bool value = std::is_base_of::value; +}; + template struct size_in_raw_data { - static const size_t value = (is_ipc_buffer::value || is_ipc_handle::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); + static const size_t value = (is_ipc_buffer::value || is_ipc_handle::value || is_out_session::value) ? 0 : ((sizeof(T) < sizeof(u32)) ? sizeof(u32) : (sizeof(T) + 3) & (~3)); }; template @@ -127,6 +149,11 @@ struct size_in_raw_data_for_arguments { static const size_t value = (size_in_raw_data::value + ... + 0); }; +template +struct num_out_sessions_in_arguments { + static const size_t value = ((is_out_session::value ? 1 : 0) + ... + 0); +}; + template struct size_in_raw_data_with_out_pointers { static const size_t value = is_specialization_of::value ? 2 : size_in_raw_data::value; @@ -293,6 +320,10 @@ struct Validator> { return 0xF601; } + if (((u32 *)r.Raw)[0] != SFCI_MAGIC) { + //return 0xF601; + } + size_t a_index = 0, b_index = num_inbuffers_in_arguments::value, x_index = 0, c_index = 0, h_index = 0; size_t cur_rawdata_index = 4; size_t cur_c_size_offset = 0x10 + size_in_raw_data_for_arguments::value + (0x10 - ((uintptr_t)r.Raw - (uintptr_t)r.RawWithoutPadding)); @@ -334,33 +365,55 @@ template struct Encoder; template -constexpr size_t GetAndUpdateOffsetIntoRawData(size_t& offset) { +constexpr size_t GetAndUpdateOffsetIntoRawData(DomainOwner *domain_owner, size_t& offset) { auto old = offset; if (old == 0) { offset += sizeof(u64); } else { - offset += size_in_raw_data::value; + if constexpr (is_out_session::value) { + if (domain_owner) { + offset += sizeof(u32); + } + } else { + offset += size_in_raw_data::value; + } } return old; } template -void EncodeValueIntoIpcMessageBeforePrepare(IpcCommand *c, T value) { +void EncodeValueIntoIpcMessageBeforePrepare(DomainOwner *domain_owner, IpcCommand *c, T &value) { if constexpr (std::is_same::value) { ipcSendHandleMove(c, value.handle); } else if constexpr (std::is_same::value) { ipcSendHandleCopy(c, value.handle); } else if constexpr (std::is_same::value) { ipcSendPid(c); + } else if constexpr (is_out_session::value) { + if (domain_owner && value.session) { + /* TODO: Check error... */ + if (value.domain_id != DOMAIN_ID_MAX) { + domain_owner->set_object(value.session->get_service_object(), value.domain_id); + } else { + domain_owner->reserve_object(value.session->get_service_object(), &value.domain_id); + } + value.session->close_handles(); + } else { + ipcSendHandleMove(c, value.session ? value.session->get_client_handle() : 0x0); + } } } template -void EncodeValueIntoIpcMessageAfterPrepare(u8 *cur_out, T value) { +void EncodeValueIntoIpcMessageAfterPrepare(DomainOwner *domain_owner, u8 *cur_out, T value) { if constexpr (is_ipc_handle::value || std::is_same::value) { /* Do nothing. */ + } else if constexpr (is_out_session::value) { + if (domain_owner) { + *((u32 *)cur_out) = value.domain_id; + } } else { *((T *)(cur_out)) = value; } @@ -370,7 +423,7 @@ template struct Encoder> { IpcCommand &out_command; - auto operator()(Args... args) { + auto operator()(DomainOwner *domain_owner, Args... args) { static_assert(sizeof...(Args) > 0, "IpcCommandImpls must return std::tuple"); size_t offset = 0; @@ -378,19 +431,26 @@ struct Encoder> { std::fill(tls, tls + 0x100, 0x00); - ((EncodeValueIntoIpcMessageBeforePrepare(&out_command, args)), ...); + ((EncodeValueIntoIpcMessageBeforePrepare(domain_owner, &out_command, args)), ...); /* Remove the extra space resulting from first Result type. */ struct { u64 magic; u64 result; - } *raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value - sizeof(Result)); + } *raw; + if (domain_owner == NULL) { + raw = (decltype(raw))ipcPrepareHeader(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value - sizeof(Result)); + } else { + raw = (decltype(raw))ipcPrepareHeaderForDomain(&out_command, sizeof(*raw) + size_in_raw_data_for_arguments::value + (num_out_sessions_in_arguments::value * sizeof(u32)) - sizeof(Result), 0); + *((DomainMessageHeader *)((uintptr_t)raw - sizeof(DomainMessageHeader))) = {0}; + } + raw->magic = SFCO_MAGIC; u8 *raw_data = (u8 *)&raw->result; - ((EncodeValueIntoIpcMessageAfterPrepare(raw_data + GetAndUpdateOffsetIntoRawData(offset), args)), ...); + ((EncodeValueIntoIpcMessageAfterPrepare(domain_owner, raw_data + GetAndUpdateOffsetIntoRawData(domain_owner, offset), args)), ...); Result rc = raw->result; @@ -424,7 +484,9 @@ Result WrapDeferredIpcCommandImpl(Class *this_ptr, Args... args) { auto tuple_args = std::make_tuple(args...); auto result = std::apply( [=](auto&&... a) { return (this_ptr->*IpcCommandImpl)(a...); }, tuple_args); - return std::apply(Encoder{out_command}, result); + DomainOwner *down = NULL; + + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } template @@ -446,8 +508,12 @@ Result WrapIpcCommandImpl(Class *this_ptr, IpcParsedCommand& r, IpcCommand &out_ auto args = Decoder::Decode(r, out_command, pointer_buffer); auto result = std::apply( [=](auto&&... args) { return (this_ptr->*IpcCommandImpl)(args...); }, args); + DomainOwner *down = NULL; + if (r.IsDomainMessage) { + down = this_ptr->get_owner(); + } - return std::apply(Encoder{out_command}, result); + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } template @@ -468,8 +534,11 @@ Result WrapStaticIpcCommandImpl(IpcParsedCommand& r, IpcCommand &out_command, u8 auto args = Decoder::Decode(r, out_command, pointer_buffer); auto result = std::apply(IpcCommandImpl, args); + DomainOwner *down = NULL; - return std::apply(Encoder{out_command}, result); + return std::apply(Encoder{out_command}, std::tuple_cat(std::make_tuple(down), result)); } #pragma GCC diagnostic pop + +#include "isession.hpp" diff --git a/include/stratosphere/ipcsession.hpp b/include/stratosphere/ipcsession.hpp index ef95238c..5cabd6a1 100644 --- a/include/stratosphere/ipcsession.hpp +++ b/include/stratosphere/ipcsession.hpp @@ -5,200 +5,31 @@ #include "ipc_templating.hpp" #include "iserviceobject.hpp" #include "iwaitable.hpp" -#include "servicesession.hpp" +#include "isession.hpp" template -class IPCSession final : public IWaitable { +class IPCSession final : public ISession { static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); - T *service_object; - Handle server_handle; - Handle client_handle; - char *pointer_buffer; - size_t pointer_buffer_size; - - static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!"); - public: - IPCSession(size_t pbs = 0x400) : pointer_buffer_size(pbs) { + IPCSession(size_t pbs = 0x400) : ISession(NULL, 0, 0, 0) { Result rc; - if (R_FAILED((rc = svcCreateSession(&server_handle, &client_handle, 0, 0)))) { + if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) { fatalSimple(rc); } this->service_object = new T(); - this->pointer_buffer = new char[pointer_buffer_size]; + this->pointer_buffer_size = pbs; + this->pointer_buffer = new char[this->pointer_buffer_size]; + this->is_domain = false; } - IPCSession(T *so, size_t pbs = 0x400) : service_object(so), pointer_buffer_size(pbs) { + IPCSession(T *so, size_t pbs = 0x400) : ISession(NULL, 0, 0, so, 0) { Result rc; - if (R_FAILED((rc = svcCreateSession(&server_handle, &client_handle, 0, 0)))) { + if (R_FAILED((rc = svcCreateSession(&this->server_handle, &this->client_handle, 0, 0)))) { fatalSimple(rc); } - this->pointer_buffer = new char[pointer_buffer_size]; - } - - ~IPCSession() override { - delete this->service_object; - delete this->pointer_buffer; - if (server_handle) { - svcCloseHandle(server_handle); - } - if (client_handle) { - svcCloseHandle(client_handle); - } - } - - T *get_service_object() { return this->service_object; } - Handle get_server_handle() { return this->server_handle; } - Handle get_client_handle() { return this->client_handle; } - - /* IWaitable */ - unsigned int get_num_waitables() override { - return 1; - } - - void get_waitables(IWaitable **dst) override { - dst[0] = this; - } - - void delete_child(IWaitable *child) override { - /* TODO: Panic, because we can never have any children. */ - } - - Handle get_handle() override { - return this->server_handle; - } - - void handle_deferred() override { - Result rc = this->service_object->handle_deferred(); - int handle_index; - - if (rc != RESULT_DEFER_SESSION) { - this->set_deferred(false); - if (rc == 0xF601) { - svcCloseHandle(this->get_handle()); - } else { - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - } - } - } - - Result handle_signaled(u64 timeout) override { - Result rc; - int handle_index; - - /* Prepare pointer buffer... */ - IpcCommand c_for_reply; - ipcInitialize(&c_for_reply); - ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, this->pointer_buffer_size, 0); - ipcPrepareHeader(&c_for_reply, 0); - - if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) { - if (handle_index != 0) { - /* TODO: Panic? */ - } - u32 *cmdbuf = (u32 *)armGetTls(); - Result retval = 0; - u32 *rawdata_start = cmdbuf; - - IpcParsedCommand r; - IpcCommand c; - - ipcInitialize(&c); - - retval = ipcParse(&r); - - if (R_SUCCEEDED(retval)) { - rawdata_start = (u32 *)r.Raw; - switch (r.CommandType) { - case IpcCommandType_Close: - /* TODO: This should close the session and clean up its resources. */ - retval = 0xF601; - break; - case IpcCommandType_LegacyControl: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_LegacyRequest: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_Request: - case IpcCommandType_RequestWithContext: - retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - case IpcCommandType_Control: - case IpcCommandType_ControlWithContext: - retval = this->dispatch_control_command(r, c, rawdata_start[2]); - break; - case IpcCommandType_Invalid: - default: - retval = 0xF601; - break; - } - - } - - if (retval == RESULT_DEFER_SESSION) { - /* Session defer. */ - this->set_deferred(true); - rc = retval; - } else if (retval == 0xF601) { - /* Session close. */ - rc = retval; - } else { - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - } - } - - return rc; - } - - /* Control commands. */ - std::tuple ConvertCurrentObjectToDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CopyFromCurrentDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CloneCurrentObject() { - /* TODO */ - return {0xF601}; - } - std::tuple QueryPointerBufferSize() { - return {0x0, (u32)this->pointer_buffer_size}; - } - std::tuple CloneCurrentObjectEx() { - /* TODO */ - return {0xF601}; - } - - Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) { - Result rc = 0xF601; - - /* TODO: Implement. */ - switch ((IpcControlCommand)cmd_id) { - case IpcCtrl_Cmd_ConvertCurrentObjectToDomain: - rc = WrapIpcCommandImpl<&IPCSession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - case IpcCtrl_Cmd_CopyFromCurrentDomain: - rc = WrapIpcCommandImpl<&IPCSession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - case IpcCtrl_Cmd_CloneCurrentObject: - rc = WrapIpcCommandImpl<&IPCSession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - case IpcCtrl_Cmd_QueryPointerBufferSize: - rc = WrapIpcCommandImpl<&IPCSession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - case IpcCtrl_Cmd_CloneCurrentObjectEx: - rc = WrapIpcCommandImpl<&IPCSession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); - break; - default: - break; - } - - return rc; + this->pointer_buffer_size = pbs; + this->pointer_buffer = new char[this->pointer_buffer_size]; + this->is_domain = false; } }; diff --git a/include/stratosphere/iserver.hpp b/include/stratosphere/iserver.hpp index 66cb1e7a..24ff1ee6 100644 --- a/include/stratosphere/iserver.hpp +++ b/include/stratosphere/iserver.hpp @@ -4,10 +4,10 @@ #include "iserviceobject.hpp" #include "iwaitable.hpp" -#include "servicesession.hpp" +#include "isession.hpp" template -class ServiceSession; +class ISession; template class IServer : public IWaitable { @@ -15,71 +15,22 @@ class IServer : public IWaitable { protected: Handle port_handle; unsigned int max_sessions; - unsigned int num_sessions; - ServiceSession **sessions; + bool supports_domains; public: - IServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { - this->sessions = new ServiceSession *[this->max_sessions]; - for (unsigned int i = 0; i < this->max_sessions; i++) { - this->sessions[i] = NULL; - } - this->num_sessions = 0; + IServer(const char *service_name, unsigned int max_s, bool s_d = false) : max_sessions(max_s), supports_domains(s_d) { + } - virtual ~IServer() { - for (unsigned int i = 0; i < this->max_sessions; i++) { - if (this->sessions[i]) { - delete this->sessions[i]; - } - - delete this->sessions; - } - + virtual ~IServer() { if (port_handle) { svcCloseHandle(port_handle); } } + + virtual ISession *get_new_session(Handle session_h) = 0; - /* IWaitable */ - virtual unsigned int get_num_waitables() { - unsigned int n = 1; - for (unsigned int i = 0; i < this->max_sessions; i++) { - if (this->sessions[i]) { - n += this->sessions[i]->get_num_waitables(); - } - } - return n; - } - - virtual void get_waitables(IWaitable **dst) { - dst[0] = this; - unsigned int n = 0; - for (unsigned int i = 0; i < this->max_sessions; i++) { - if (this->sessions[i]) { - this->sessions[i]->get_waitables(&dst[1 + n]); - n += this->sessions[i]->get_num_waitables(); - } - } - } - - virtual void delete_child(IWaitable *child) { - unsigned int i; - for (i = 0; i < this->max_sessions; i++) { - if (this->sessions[i] == child) { - break; - } - } - - if (i == this->max_sessions) { - /* TODO: Panic, because this isn't our child. */ - } else { - delete this->sessions[i]; - this->sessions[i] = NULL; - this->num_sessions--; - } - } - + /* IWaitable */ virtual Handle get_handle() { return this->port_handle; } @@ -92,23 +43,12 @@ class IServer : public IWaitable { virtual Result handle_signaled(u64 timeout) { /* If this server's port was signaled, accept a new session. */ Handle session_h; - svcAcceptSession(&session_h, this->port_handle); + Result rc = svcAcceptSession(&session_h, this->port_handle); + if (R_FAILED(rc)) { + return rc; + } - if (this->num_sessions >= this->max_sessions) { - svcCloseHandle(session_h); - return 0x10601; - } - - unsigned int i; - for (i = 0; i < this->max_sessions; i++) { - if (this->sessions[i] == NULL) { - break; - } - } - - this->sessions[i] = new ServiceSession(this, session_h, 0); - this->sessions[i]->set_parent(this); - this->num_sessions++; + this->get_manager()->add_waitable(this->get_new_session(session_h)); return 0; } }; \ No newline at end of file diff --git a/include/stratosphere/iserviceobject.hpp b/include/stratosphere/iserviceobject.hpp index 9b569722..965fc59c 100644 --- a/include/stratosphere/iserviceobject.hpp +++ b/include/stratosphere/iserviceobject.hpp @@ -1,11 +1,25 @@ #pragma once #include -#include "ipc_templating.hpp" +template +class ISession; + +class DomainOwner; class IServiceObject { - protected: + private: + DomainOwner *owner = NULL; + public: virtual ~IServiceObject() { } + + virtual IServiceObject *clone() = 0; + + bool is_domain() { return this->owner != NULL; } + DomainOwner *get_owner() { return this->owner; } + void set_owner(DomainOwner *owner) { this->owner = owner; } virtual Result dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id, u8 *pointer_buffer, size_t pointer_buffer_size) = 0; + protected: virtual Result handle_deferred() = 0; }; + +#include "domainowner.hpp" diff --git a/include/stratosphere/isession.hpp b/include/stratosphere/isession.hpp new file mode 100644 index 00000000..de33692e --- /dev/null +++ b/include/stratosphere/isession.hpp @@ -0,0 +1,288 @@ +#pragma once +#include +#include + +#include "ipc_templating.hpp" +#include "iserviceobject.hpp" +#include "iwaitable.hpp" +#include "iserver.hpp" + +#include "domainowner.hpp" + +enum IpcControlCommand { + IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0, + IpcCtrl_Cmd_CopyFromCurrentDomain = 1, + IpcCtrl_Cmd_CloneCurrentObject = 2, + IpcCtrl_Cmd_QueryPointerBufferSize = 3, + IpcCtrl_Cmd_CloneCurrentObjectEx = 4 +}; + +#define POINTER_BUFFER_SIZE_MAX 0xFFFF +#define RESULT_DEFER_SESSION (0x6580A) + + +template +class IServer; + +class IServiceObject; + +template +class ISession : public IWaitable, public DomainOwner { + static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); + protected: + T *service_object; + IServer *server; + Handle server_handle; + Handle client_handle; + char *pointer_buffer; + size_t pointer_buffer_size; + + bool is_domain; + + + IServiceObject *active_object; + + static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!"); + + public: + ISession(IServer *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : server(s), server_handle(s_h), client_handle(c_h), pointer_buffer_size(pbs) { + this->service_object = new T(); + if (this->pointer_buffer_size) { + this->pointer_buffer = new char[this->pointer_buffer_size]; + } + this->is_domain = false; + this->active_object = NULL; + } + + ISession(IServer *s, Handle s_h, Handle c_h, T *so, size_t pbs = 0x400) : service_object(so), server(s), server_handle(s_h), client_handle(c_h), pointer_buffer_size(pbs) { + if (this->pointer_buffer_size) { + this->pointer_buffer = new char[this->pointer_buffer_size]; + } + this->is_domain = false; + this->active_object = NULL; + } + + ~ISession() override { + delete this->pointer_buffer; + if (this->service_object && !this->is_domain) { + //delete this->service_object; + } + if (server_handle) { + svcCloseHandle(server_handle); + } + if (client_handle) { + svcCloseHandle(client_handle); + } + } + + void close_handles() { + if (server_handle) { + svcCloseHandle(server_handle); + server_handle = 0; + } + if (client_handle) { + svcCloseHandle(client_handle); + client_handle = 0; + } + } + + T *get_service_object() { return this->service_object; } + Handle get_server_handle() { return this->server_handle; } + Handle get_client_handle() { return this->client_handle; } + + + DomainOwner *get_owner() { return is_domain ? this : NULL; } + + /* IWaitable */ + Handle get_handle() override { + return this->server_handle; + } + + void handle_deferred() override { + Result rc = this->service_object->handle_deferred(); + int handle_index; + + if (rc != RESULT_DEFER_SESSION) { + this->set_deferred(false); + if (rc == 0xF601) { + svcCloseHandle(this->get_handle()); + } else { + rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); + } + } + } + + + virtual Result handle_message(IpcParsedCommand &r) { + Result retval = 0xF601; + + IpcCommand c; + ipcInitialize(&c); + + if (r.IsDomainMessage && this->active_object == NULL) { + return 0xF601; + } + + + if (r.IsDomainMessage && r.MessageType == DomainMessageType_Close) { + this->delete_object(this->active_object); + this->active_object = NULL; + struct { + u64 magic; + u64 result; + } *raw = (decltype(raw))ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCO_MAGIC; + raw->result = 0x0; + return 0x0; + } + + u64 cmd_id = ((u32 *)r.Raw)[2]; + switch (r.CommandType) { + case IpcCommandType_Close: + /* TODO: This should close the session and clean up its resources. */ + retval = 0xF601; + break; + case IpcCommandType_LegacyControl: + /* TODO: What does this allow one to do? */ + retval = 0xF601; + break; + case IpcCommandType_LegacyRequest: + /* TODO: What does this allow one to do? */ + retval = 0xF601; + break; + case IpcCommandType_Request: + case IpcCommandType_RequestWithContext: + retval = this->active_object->dispatch(r, c, cmd_id, (u8 *)this->pointer_buffer, this->pointer_buffer_size); + break; + case IpcCommandType_Control: + case IpcCommandType_ControlWithContext: + retval = this->dispatch_control_command(r, c, cmd_id); + break; + case IpcCommandType_Invalid: + default: + retval = 0xF601; + break; + } + + return retval; + } + + virtual void postprocess(IpcParsedCommand &r, u64 cmd_id) { + /* ... */ + (void)(r); + (void)(cmd_id); + } + + virtual void cleanup() { + /* ... */ + } + + Result handle_signaled(u64 timeout) override { + Result rc; + int handle_index; + + /* Prepare pointer buffer... */ + IpcCommand c_for_reply; + ipcInitialize(&c_for_reply); + ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, this->pointer_buffer_size, 0); + ipcPrepareHeader(&c_for_reply, 0); + + if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) { + if (handle_index != 0) { + /* TODO: Panic? */ + } + IpcParsedCommand r; + u64 cmd_id; + + + Result retval = ipcParse(&r); + if (R_SUCCEEDED(retval)) { + if (this->is_domain && (r.CommandType == IpcCommandType_Request || r.CommandType == IpcCommandType_RequestWithContext)) { + retval = ipcParseForDomain(&r); + if (!r.IsDomainMessage || r.ThisObjectId >= DOMAIN_ID_MAX) { + retval = 0xF601; + } else { + this->active_object = this->get_domain_object(r.ThisObjectId); + } + } else { + this->active_object = this->service_object; + } + } + if (R_SUCCEEDED(retval)) { + cmd_id = ((u32 *)r.Raw)[2]; + } + if (R_SUCCEEDED(retval)) { + retval = this->handle_message(r); + } + + if (retval == RESULT_DEFER_SESSION) { + /* Session defer. */ + this->active_object = NULL; + this->set_deferred(true); + rc = retval; + } else if (retval == 0xF601) { + /* Session close. */ + this->active_object = NULL; + rc = retval; + } else { + if (R_SUCCEEDED(retval)) { + this->postprocess(r, cmd_id); + } + this->active_object = NULL; + rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); + this->cleanup(); + } + } + + return rc; + } + + Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) { + Result rc = 0xF601; + + /* TODO: Implement. */ + switch ((IpcControlCommand)cmd_id) { + case IpcCtrl_Cmd_ConvertCurrentObjectToDomain: + rc = WrapIpcCommandImpl<&ISession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); + break; + case IpcCtrl_Cmd_CopyFromCurrentDomain: + rc = WrapIpcCommandImpl<&ISession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); + break; + case IpcCtrl_Cmd_CloneCurrentObject: + rc = WrapIpcCommandImpl<&ISession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); + break; + case IpcCtrl_Cmd_QueryPointerBufferSize: + rc = WrapIpcCommandImpl<&ISession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, this->pointer_buffer_size); + break; + case IpcCtrl_Cmd_CloneCurrentObjectEx: + rc = WrapIpcCommandImpl<&ISession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); + break; + default: + break; + } + + return rc; + } + + /* Control commands. */ + std::tuple ConvertCurrentObjectToDomain() { + /* TODO */ + return {0xF601}; + } + std::tuple CopyFromCurrentDomain() { + /* TODO */ + return {0xF601}; + } + std::tuple CloneCurrentObject() { + /* TODO */ + return {0xF601}; + } + std::tuple QueryPointerBufferSize() { + return {0x0, (u32)this->pointer_buffer_size}; + } + std::tuple CloneCurrentObjectEx() { + /* TODO */ + return {0xF601}; + } +}; diff --git a/include/stratosphere/iwaitable.hpp b/include/stratosphere/iwaitable.hpp index ded31396..4a81f3c4 100644 --- a/include/stratosphere/iwaitable.hpp +++ b/include/stratosphere/iwaitable.hpp @@ -2,38 +2,34 @@ #include +#include "waitablemanagerbase.hpp" + +class WaitableManager; + class IWaitable { - u64 wait_priority = 0; - bool is_deferred = false; - IWaitable *parent_waitable; + private: + u64 wait_priority = 0; + bool is_deferred = false; + WaitableManagerBase *manager; public: virtual ~IWaitable() { } - virtual unsigned int get_num_waitables() = 0; - virtual void get_waitables(IWaitable **dst) = 0; - virtual void delete_child(IWaitable *child) = 0; virtual void handle_deferred() = 0; virtual Handle get_handle() = 0; virtual Result handle_signaled(u64 timeout) = 0; - - bool has_parent() { - return this->parent_waitable != NULL; + + WaitableManager *get_manager() { + return (WaitableManager *)this->manager; } - void set_parent(IWaitable *p) { - if (has_parent()) { - /* TODO: Panic? */ - } - this->parent_waitable = p; - } - - IWaitable *get_parent() { - return this->parent_waitable; + void set_manager(WaitableManagerBase *m) { + this->manager = m; } void update_priority() { - static u64 g_cur_priority = 0; - this->wait_priority = g_cur_priority++; + if (manager) { + this->wait_priority = this->manager->get_priority(); + } } bool get_deferred() { @@ -47,4 +43,6 @@ class IWaitable { static bool compare(IWaitable *a, IWaitable *b) { return (a->wait_priority < b->wait_priority) && !a->is_deferred; } -}; \ No newline at end of file +}; + +#include "waitablemanager.hpp" \ No newline at end of file diff --git a/include/stratosphere/managedportserver.hpp b/include/stratosphere/managedportserver.hpp index af86db42..83ed7df5 100644 --- a/include/stratosphere/managedportserver.hpp +++ b/include/stratosphere/managedportserver.hpp @@ -5,9 +5,13 @@ template class ManagedPortServer : public IServer { public: - ManagedPortServer(const char *service_name, unsigned int max_s) : IServer(service_name, max_s) { + ManagedPortServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer(service_name, max_s, s_d) { if (R_FAILED(svcManageNamedPort(&this->port_handle, service_name, this->max_sessions))) { /* TODO: panic */ } } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/include/stratosphere/serviceserver.hpp b/include/stratosphere/serviceserver.hpp index 28951822..e7338867 100644 --- a/include/stratosphere/serviceserver.hpp +++ b/include/stratosphere/serviceserver.hpp @@ -5,9 +5,13 @@ template class ServiceServer : public IServer { public: - ServiceServer(const char *service_name, unsigned int max_s) : IServer(service_name, max_s) { + ServiceServer(const char *service_name, unsigned int max_s, bool s_d = false) : IServer(service_name, max_s, s_d) { if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) { /* TODO: Panic. */ } } + + ISession *get_new_session(Handle session_h) override { + return new ServiceSession(this, session_h, 0); + } }; \ No newline at end of file diff --git a/include/stratosphere/servicesession.hpp b/include/stratosphere/servicesession.hpp index 1b397701..da64e8d6 100644 --- a/include/stratosphere/servicesession.hpp +++ b/include/stratosphere/servicesession.hpp @@ -6,200 +6,15 @@ #include "iserviceobject.hpp" #include "iwaitable.hpp" #include "iserver.hpp" - -enum IpcControlCommand { - IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0, - IpcCtrl_Cmd_CopyFromCurrentDomain = 1, - IpcCtrl_Cmd_CloneCurrentObject = 2, - IpcCtrl_Cmd_QueryPointerBufferSize = 3, - IpcCtrl_Cmd_CloneCurrentObjectEx = 4 -}; - -#define POINTER_BUFFER_SIZE_MAX 0xFFFF -#define RESULT_DEFER_SESSION (0x6580A) - +#include "isession.hpp" template -class IServer; - -template -class ServiceSession final : public IWaitable { +class ServiceSession final : public ISession { static_assert(std::is_base_of::value, "Service Objects must derive from IServiceObject"); - - T *service_object; - IServer *server; - Handle server_handle; - Handle client_handle; - char pointer_buffer[0x400]; - - static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!"); - + public: - ServiceSession(IServer *s, Handle s_h, Handle c_h) : server(s), server_handle(s_h), client_handle(c_h) { - this->service_object = new T(); + ServiceSession(IServer *s, Handle s_h, Handle c_h, size_t pbs = 0x400) : ISession(s, s_h, c_h, pbs) { + /* ... */ } - ~ServiceSession() override { - delete this->service_object; - if (server_handle) { - svcCloseHandle(server_handle); - } - if (client_handle) { - svcCloseHandle(client_handle); - } - } - - T *get_service_object() { return this->service_object; } - Handle get_server_handle() { return this->server_handle; } - Handle get_client_handle() { return this->client_handle; } - - /* IWaitable */ - unsigned int get_num_waitables() override { - return 1; - } - - void get_waitables(IWaitable **dst) override { - dst[0] = this; - } - - void delete_child(IWaitable *child) override { - /* TODO: Panic, because we can never have any children. */ - } - - Handle get_handle() override { - return this->server_handle; - } - - void handle_deferred() override { - Result rc = this->service_object->handle_deferred(); - int handle_index; - - if (rc != RESULT_DEFER_SESSION) { - this->set_deferred(false); - if (rc == 0xF601) { - svcCloseHandle(this->get_handle()); - } else { - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - } - } - } - - Result handle_signaled(u64 timeout) override { - Result rc; - int handle_index; - - /* Prepare pointer buffer... */ - IpcCommand c_for_reply; - ipcInitialize(&c_for_reply); - ipcAddRecvStatic(&c_for_reply, this->pointer_buffer, sizeof(this->pointer_buffer), 0); - ipcPrepareHeader(&c_for_reply, 0); - - if (R_SUCCEEDED(rc = svcReplyAndReceive(&handle_index, &this->server_handle, 1, 0, timeout))) { - if (handle_index != 0) { - /* TODO: Panic? */ - } - u32 *cmdbuf = (u32 *)armGetTls(); - Result retval = 0; - u32 *rawdata_start = cmdbuf; - - IpcParsedCommand r; - IpcCommand c; - - ipcInitialize(&c); - - retval = ipcParse(&r); - - if (R_SUCCEEDED(retval)) { - rawdata_start = (u32 *)r.Raw; - switch (r.CommandType) { - case IpcCommandType_Close: - /* TODO: This should close the session and clean up its resources. */ - retval = 0xF601; - break; - case IpcCommandType_LegacyControl: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_LegacyRequest: - /* TODO: What does this allow one to do? */ - retval = 0xF601; - break; - case IpcCommandType_Request: - case IpcCommandType_RequestWithContext: - retval = this->service_object->dispatch(r, c, rawdata_start[2], (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - case IpcCommandType_Control: - case IpcCommandType_ControlWithContext: - retval = this->dispatch_control_command(r, c, rawdata_start[2]); - break; - case IpcCommandType_Invalid: - default: - retval = 0xF601; - break; - } - - } - - if (retval == RESULT_DEFER_SESSION) { - /* Session defer. */ - this->set_deferred(true); - rc = retval; - } else if (retval == 0xF601) { - /* Session close. */ - rc = retval; - } else { - rc = svcReplyAndReceive(&handle_index, &this->server_handle, 0, this->server_handle, 0); - } - } - - return rc; - } - - /* Control commands. */ - std::tuple ConvertCurrentObjectToDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CopyFromCurrentDomain() { - /* TODO */ - return {0xF601}; - } - std::tuple CloneCurrentObject() { - /* TODO */ - return {0xF601}; - } - std::tuple QueryPointerBufferSize() { - return {0x0, (u32)sizeof(this->pointer_buffer)}; - } - std::tuple CloneCurrentObjectEx() { - /* TODO */ - return {0xF601}; - } - - Result dispatch_control_command(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id) { - Result rc = 0xF601; - - /* TODO: Implement. */ - switch ((IpcControlCommand)cmd_id) { - case IpcCtrl_Cmd_ConvertCurrentObjectToDomain: - rc = WrapIpcCommandImpl<&ServiceSession::ConvertCurrentObjectToDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - case IpcCtrl_Cmd_CopyFromCurrentDomain: - rc = WrapIpcCommandImpl<&ServiceSession::CopyFromCurrentDomain>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - case IpcCtrl_Cmd_CloneCurrentObject: - rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObject>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - case IpcCtrl_Cmd_QueryPointerBufferSize: - rc = WrapIpcCommandImpl<&ServiceSession::QueryPointerBufferSize>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - case IpcCtrl_Cmd_CloneCurrentObjectEx: - rc = WrapIpcCommandImpl<&ServiceSession::CloneCurrentObjectEx>(this, r, out_c, (u8 *)this->pointer_buffer, sizeof(this->pointer_buffer)); - break; - default: - break; - } - - return rc; - } }; diff --git a/include/stratosphere/waitablemanager.hpp b/include/stratosphere/waitablemanager.hpp index 407c7c24..ebefa548 100644 --- a/include/stratosphere/waitablemanager.hpp +++ b/include/stratosphere/waitablemanager.hpp @@ -2,15 +2,22 @@ #include #include +#include "waitablemanagerbase.hpp" #include "iwaitable.hpp" +#include "hossynch.hpp" -class WaitableManager { +class IWaitable; + +class WaitableManager : public WaitableManagerBase { + std::vector to_add_waitables; std::vector waitables; u64 timeout; + HosMutex lock; + std::atomic_bool has_new_items; private: void process_internal(bool break_on_timeout); public: - WaitableManager(u64 t) : waitables(0), timeout(t) { } + WaitableManager(u64 t) : waitables(0), timeout(t), has_new_items(false) { } ~WaitableManager() { /* This should call the destructor for every waitable. */ for (auto & waitable : waitables) { @@ -19,7 +26,6 @@ class WaitableManager { waitables.clear(); } - unsigned int get_num_signalable(); void add_waitable(IWaitable *waitable); void process(); void process_until_timeout(); diff --git a/include/stratosphere/waitablemanagerbase.hpp b/include/stratosphere/waitablemanagerbase.hpp new file mode 100644 index 00000000..f294b8fd --- /dev/null +++ b/include/stratosphere/waitablemanagerbase.hpp @@ -0,0 +1,14 @@ +#pragma once +#include +#include +#include + +class WaitableManagerBase { + std::atomic cur_priority; + public: + WaitableManagerBase() : cur_priority(0) { } + + u64 get_priority() { + return std::atomic_fetch_add(&cur_priority, (u64)1); + } +}; \ No newline at end of file diff --git a/source/waitablemanager.cpp b/source/waitablemanager.cpp index eb272730..fee21cb4 100644 --- a/source/waitablemanager.cpp +++ b/source/waitablemanager.cpp @@ -4,56 +4,51 @@ #include - -unsigned int WaitableManager::get_num_signalable() { - unsigned int n = 0; - for (auto & waitable : this->waitables) { - n += waitable->get_num_waitables(); - } - return n; -} - void WaitableManager::add_waitable(IWaitable *waitable) { - this->waitables.push_back(waitable); + this->lock.Lock(); + this->to_add_waitables.push_back(waitable); + waitable->set_manager(this); + this->has_new_items = true; + this->lock.Unlock(); } void WaitableManager::process_internal(bool break_on_timeout) { - std::vector signalables; std::vector handles; int handle_index = 0; Result rc; while (1) { - /* Create vector of signalable items. */ - signalables.resize(this->get_num_signalable(), NULL); - unsigned int n = 0; - for (auto & waitable : this->waitables) { - waitable->get_waitables(signalables.data() + n); - n += waitable->get_num_waitables(); + /* Add new items, if relevant. */ + if (this->has_new_items) { + this->lock.Lock(); + this->waitables.insert(this->waitables.end(), this->to_add_waitables.begin(), this->to_add_waitables.end()); + this->to_add_waitables.clear(); + this->has_new_items = false; + this->lock.Unlock(); } - - /* Sort signalables by priority. */ - std::sort(signalables.begin(), signalables.end(), IWaitable::compare); + + /* Sort waitables by priority. */ + std::sort(this->waitables.begin(), this->waitables.end(), IWaitable::compare); /* Copy out handles. */ - handles.resize(signalables.size()); - std::transform(signalables.begin(), signalables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); + handles.resize(this->waitables.size()); + std::transform(this->waitables.begin(), this->waitables.end(), handles.begin(), [](IWaitable *w) { return w->get_handle(); }); - rc = svcWaitSynchronization(&handle_index, handles.data(), signalables.size(), this->timeout); + rc = svcWaitSynchronization(&handle_index, handles.data(), this->waitables.size(), this->timeout); if (R_SUCCEEDED(rc)) { /* Handle a signaled waitable. */ /* TODO: What timeout should be passed here? */ - rc = signalables[handle_index]->handle_signaled(0); + rc = this->waitables[handle_index]->handle_signaled(0); for (int i = 0; i < handle_index; i++) { - signalables[i]->update_priority(); + this->waitables[i]->update_priority(); } } else if (rc == 0xEA01) { /* Timeout. */ - for (auto & waitable : signalables) { + for (auto & waitable : this->waitables) { waitable->update_priority(); } if (break_on_timeout) { @@ -69,26 +64,21 @@ void WaitableManager::process_internal(bool break_on_timeout) { /* Close the handle. */ svcCloseHandle(handles[handle_index]); + IWaitable *to_delete = this->waitables[handle_index]; + /* If relevant, remove from waitables. */ - this->waitables.erase(std::remove(this->waitables.begin(), this->waitables.end(), signalables[handle_index]), this->waitables.end()); + this->waitables.erase(this->waitables.begin() + handle_index); /* Delete it. */ - if (signalables[handle_index]->has_parent()) { - signalables[handle_index]->get_parent()->delete_child(signalables[handle_index]); - } else { - delete signalables[handle_index]; - } - - /* If relevant, remove from signalables. */ - signalables.erase(std::remove(signalables.begin(), signalables.end(), signalables[handle_index]), signalables.end()); - + delete to_delete; + for (int i = 0; i < handle_index; i++) { - signalables[i]->update_priority(); + this->waitables[i]->update_priority(); } } /* Do deferred callback for each waitable. */ - for (auto & waitable : signalables) { + for (auto & waitable : this->waitables) { if (waitable->get_deferred()) { waitable->handle_deferred(); }