diff --git a/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp b/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp index 62f17055..0d964069 100644 --- a/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp +++ b/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp @@ -127,6 +127,10 @@ namespace sts::sf::hipc { os::Mutex waitlist_mutex; os::WaitableManager waitlist; + + os::Mutex deferred_session_mutex; + using DeferredSessionList = typename util::IntrusiveListMemberTraits<&ServerSession::deferred_list_node>::ListType; + DeferredSessionList deferred_session_list; private: virtual void RegisterSessionToWaitList(ServerSession *session) override final; void RegisterToWaitList(os::WaitableHolder *holder); @@ -138,6 +142,8 @@ namespace sts::sf::hipc { Result ProcessForMitmServer(os::WaitableHolder *holder); Result ProcessForSession(os::WaitableHolder *holder); + void ProcessDeferredSessions(); + template> void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) { /* Allocate server memory. */ diff --git a/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp b/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp index 9e267f54..37e82c59 100644 --- a/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp +++ b/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp @@ -32,6 +32,7 @@ namespace sts::sf::hipc { NON_COPYABLE(ServerSession); NON_MOVEABLE(ServerSession); private: + util::IntrusiveListNode deferred_list_node; cmif::ServiceObjectHolder srv_obj_holder; cmif::PointerAndSize pointer_buffer; cmif::PointerAndSize saved_message; diff --git a/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp b/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp index ff97dffc..2ea26530 100644 --- a/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp +++ b/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp @@ -936,10 +936,15 @@ namespace sts::sf::impl { if constexpr (Info.arg_type == ArgumentType::InData) { /* New in rawdata. */ constexpr size_t Offset = CommandMeta::InDataOffsets[Info.in_raw_data_index]; - return *reinterpret_cast(in_raw_data.GetAddress() + Offset); + if constexpr (!std::is_same::value) { + return *reinterpret_cast(in_raw_data.GetAddress() + Offset); + } else { + /* Special case bools. */ + return *reinterpret_cast(in_raw_data.GetAddress() + Offset) & 1; + } } else if constexpr (Info.arg_type == ArgumentType::OutData) { /* New out rawdata. */ - constexpr size_t Offset = CommandMeta::InDataOffsets[Info.in_raw_data_index]; + constexpr size_t Offset = CommandMeta::InDataOffsets[Info.out_raw_data_index]; return T(out_raw_holder.template GetAddress()); } else if constexpr (Info.arg_type == ArgumentType::InHandle) { /* New InHandle. */ diff --git a/source/sf/hipc/sf_hipc_server_manager.cpp b/source/sf/hipc/sf_hipc_server_manager.cpp index e4c7ab07..d9a23e6a 100644 --- a/source/sf/hipc/sf_hipc_server_manager.cpp +++ b/source/sf/hipc/sf_hipc_server_manager.cpp @@ -127,6 +127,27 @@ namespace sts::sf::hipc { return this->ProcessRequest(session, tls_message); } + void ServerManagerBase::ProcessDeferredSessions() { + /* Iterate over the list of deferred sessions, and see if we can't do anything. */ + std::scoped_lock lk(this->deferred_session_mutex); + + auto it = this->deferred_session_list.begin(); + while (it != this->deferred_session_list.end()) { + ServerSession *session = static_cast(&*it); + R_TRY_CATCH(this->ProcessForSession(session)) { + R_CATCH(ResultServiceFrameworkRequestDeferredByUser) { + /* Session is still deferred, so let's continue. */ + it++; + continue; + } + /* TODO: N has a result that undefers without success. */ + } R_END_TRY_CATCH_WITH_ASSERT; + + /* We succeeded! Remove from deferred list. */ + it = this->deferred_session_list.erase(it); + } + } + Result ServerManagerBase::Process(os::WaitableHolder *holder) { switch (static_cast(holder->GetUserData())) { case UserDataTag::Server: @@ -136,8 +157,19 @@ namespace sts::sf::hipc { return this->ProcessForMitmServer(holder); break; case UserDataTag::Session: - /* TODO: Process deferred. */ - return this->ProcessForSession(holder); + /* Try to process for session. */ + R_TRY_CATCH(this->ProcessForSession(holder)) { + R_CATCH(ResultServiceFrameworkRequestDeferredByUser) { + /* The session was deferred, so push it onto the deferred session list. */ + std::scoped_lock lk(this->deferred_session_mutex); + this->deferred_session_list.push_back(*static_cast(holder)); + return ResultSuccess; + } + } R_END_TRY_CATCH; + + /* We successfully invoked a command...so let's see if anything can be undeferred. */ + this->ProcessDeferredSessions(); + return ResultSuccess; break; STS_UNREACHABLE_DEFAULT_CASE(); }