mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
sm: implement accurate request deferral semantics
This commit is contained in:
parent
d42f2e4d1b
commit
f768e3c8f9
7 changed files with 196 additions and 75 deletions
|
@ -128,10 +128,6 @@ namespace ams::sf::hipc {
|
||||||
|
|
||||||
os::Mutex waitlist_mutex;
|
os::Mutex waitlist_mutex;
|
||||||
os::WaitableManagerType waitlist;
|
os::WaitableManagerType waitlist;
|
||||||
|
|
||||||
os::Mutex deferred_session_mutex;
|
|
||||||
using DeferredSessionList = typename util::IntrusiveListMemberTraits<&ServerSession::deferred_list_node>::ListType;
|
|
||||||
DeferredSessionList deferred_session_list;
|
|
||||||
private:
|
private:
|
||||||
virtual void RegisterSessionToWaitList(ServerSession *session) override final;
|
virtual void RegisterSessionToWaitList(ServerSession *session) override final;
|
||||||
void RegisterToWaitList(os::WaitableHolderType *holder);
|
void RegisterToWaitList(os::WaitableHolderType *holder);
|
||||||
|
@ -143,8 +139,6 @@ namespace ams::sf::hipc {
|
||||||
Result ProcessForMitmServer(os::WaitableHolderType *holder);
|
Result ProcessForMitmServer(os::WaitableHolderType *holder);
|
||||||
Result ProcessForSession(os::WaitableHolderType *holder);
|
Result ProcessForSession(os::WaitableHolderType *holder);
|
||||||
|
|
||||||
void ProcessDeferredSessions();
|
|
||||||
|
|
||||||
template<typename Interface, auto MakeShared>
|
template<typename Interface, auto MakeShared>
|
||||||
void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) {
|
void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) {
|
||||||
/* Allocate server memory. */
|
/* Allocate server memory. */
|
||||||
|
@ -176,7 +170,7 @@ namespace ams::sf::hipc {
|
||||||
ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) :
|
ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) :
|
||||||
ServerDomainSessionManager(entry_storage, entry_count),
|
ServerDomainSessionManager(entry_storage, entry_count),
|
||||||
request_stop_event(os::EventClearMode_ManualClear), notify_event(os::EventClearMode_ManualClear),
|
request_stop_event(os::EventClearMode_ManualClear), notify_event(os::EventClearMode_ManualClear),
|
||||||
waitable_selection_mutex(false), waitlist_mutex(false), deferred_session_mutex(false)
|
waitable_selection_mutex(false), waitlist_mutex(false)
|
||||||
{
|
{
|
||||||
/* Link waitables. */
|
/* Link waitables. */
|
||||||
os::InitializeWaitableManager(std::addressof(this->waitable_manager));
|
os::InitializeWaitableManager(std::addressof(this->waitable_manager));
|
||||||
|
|
|
@ -45,7 +45,6 @@ namespace ams::sf::hipc {
|
||||||
NON_COPYABLE(ServerSession);
|
NON_COPYABLE(ServerSession);
|
||||||
NON_MOVEABLE(ServerSession);
|
NON_MOVEABLE(ServerSession);
|
||||||
private:
|
private:
|
||||||
util::IntrusiveListNode deferred_list_node;
|
|
||||||
cmif::ServiceObjectHolder srv_obj_holder;
|
cmif::ServiceObjectHolder srv_obj_holder;
|
||||||
cmif::PointerAndSize pointer_buffer;
|
cmif::PointerAndSize pointer_buffer;
|
||||||
cmif::PointerAndSize saved_message;
|
cmif::PointerAndSize saved_message;
|
||||||
|
|
|
@ -147,62 +147,14 @@ namespace ams::sf::hipc {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* Undeferring a request may undefer another request. We'll continue looping until everything is stable. */
|
|
||||||
bool needs_undefer_all = true;
|
|
||||||
while (needs_undefer_all) {
|
|
||||||
needs_undefer_all = false;
|
|
||||||
|
|
||||||
auto it = this->deferred_session_list.begin();
|
|
||||||
while (it != this->deferred_session_list.end()) {
|
|
||||||
ServerSession *session = static_cast<ServerSession *>(&*it);
|
|
||||||
R_TRY_CATCH(this->ProcessForSession(session)) {
|
|
||||||
R_CATCH(sf::ResultRequestDeferred) {
|
|
||||||
/* Session is still deferred, so let's continue. */
|
|
||||||
it++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
R_CATCH(sf::impl::ResultRequestInvalidated) {
|
|
||||||
/* Session is no longer deferred! */
|
|
||||||
it = this->deferred_session_list.erase(it);
|
|
||||||
needs_undefer_all = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
|
||||||
|
|
||||||
/* We succeeded! Remove from deferred list. */
|
|
||||||
it = this->deferred_session_list.erase(it);
|
|
||||||
needs_undefer_all = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ServerManagerBase::Process(os::WaitableHolderType *holder) {
|
Result ServerManagerBase::Process(os::WaitableHolderType *holder) {
|
||||||
switch (static_cast<UserDataTag>(os::GetWaitableHolderUserData(holder))) {
|
switch (static_cast<UserDataTag>(os::GetWaitableHolderUserData(holder))) {
|
||||||
case UserDataTag::Server:
|
case UserDataTag::Server:
|
||||||
return this->ProcessForServer(holder);
|
return this->ProcessForServer(holder);
|
||||||
break;
|
|
||||||
case UserDataTag::MitmServer:
|
case UserDataTag::MitmServer:
|
||||||
return this->ProcessForMitmServer(holder);
|
return this->ProcessForMitmServer(holder);
|
||||||
break;
|
|
||||||
case UserDataTag::Session:
|
case UserDataTag::Session:
|
||||||
/* Try to process for session. */
|
return this->ProcessForSession(holder);
|
||||||
R_TRY_CATCH(this->ProcessForSession(holder)) {
|
|
||||||
R_CATCH(sf::ResultRequestDeferred) {
|
|
||||||
/* 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<ServerSession *>(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;
|
|
||||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,20 @@
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "sm_service_manager.hpp"
|
#include "sm_service_manager.hpp"
|
||||||
|
#include "sm_wait_list.hpp"
|
||||||
|
|
||||||
namespace ams::sm::impl {
|
namespace ams::sm::impl {
|
||||||
|
|
||||||
/* Anonymous namespace for implementation details. */
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* Constexpr definitions. */
|
/* Constexpr definitions. */
|
||||||
static constexpr size_t ProcessCountMax = 0x40;
|
static constexpr size_t ProcessCountMax = 0x40;
|
||||||
static constexpr size_t ServiceCountMax = 0x100;
|
static constexpr size_t ServiceCountMax = 0x100;
|
||||||
static constexpr size_t FutureMitmCountMax = 0x20;
|
static constexpr size_t FutureMitmCountMax = 0x20;
|
||||||
static constexpr size_t AccessControlSizeMax = 0x200;
|
static constexpr size_t AccessControlSizeMax = 0x200;
|
||||||
|
|
||||||
|
constexpr auto InitiallyDeferredServiceName = ServiceName::Encode("fsp-srv");
|
||||||
|
|
||||||
/* Types. */
|
/* Types. */
|
||||||
struct ProcessInfo {
|
struct ProcessInfo {
|
||||||
os::ProcessId process_id;
|
os::ProcessId process_id;
|
||||||
|
@ -274,6 +277,9 @@ namespace ams::sm::impl {
|
||||||
g_future_mitm_list[i] = InvalidServiceName;
|
g_future_mitm_list[i] = InvalidServiceName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This might undefer some requests. */
|
||||||
|
TriggerResume(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetServiceInfoRecord(ServiceRecord *out_record, const ServiceInfo *service_info) {
|
void GetServiceInfoRecord(ServiceRecord *out_record, const ServiceInfo *service_info) {
|
||||||
|
@ -347,7 +353,7 @@ namespace ams::sm::impl {
|
||||||
|
|
||||||
/* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */
|
/* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */
|
||||||
/* This can be extended with more services as needed at a later date. */
|
/* This can be extended with more services as needed at a later date. */
|
||||||
return service == ServiceName::Encode("fsp-srv");
|
return service == InitiallyDeferredServiceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldCloseOnClientDisconnect(ServiceName service) {
|
bool ShouldCloseOnClientDisconnect(ServiceName service) {
|
||||||
|
@ -423,6 +429,9 @@ namespace ams::sm::impl {
|
||||||
free_service->max_sessions = max_sessions;
|
free_service->max_sessions = max_sessions;
|
||||||
free_service->is_light = is_light;
|
free_service->is_light = is_light;
|
||||||
|
|
||||||
|
/* This might undefer some requests. */
|
||||||
|
TriggerResume(service);
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,8 +503,9 @@ namespace ams::sm::impl {
|
||||||
R_TRY(impl::HasService(&has_service, service));
|
R_TRY(impl::HasService(&has_service, service));
|
||||||
|
|
||||||
/* Wait until we have the service. */
|
/* Wait until we have the service. */
|
||||||
R_UNLESS(has_service, sf::ResultRequestDeferredByUser());
|
R_SUCCEED_IF(has_service);
|
||||||
return ResultSuccess();
|
|
||||||
|
return StartRegisterRetry(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GetServiceHandle(Handle *out, os::ProcessId process_id, ServiceName service) {
|
Result GetServiceHandle(Handle *out, os::ProcessId process_id, ServiceName service) {
|
||||||
|
@ -519,10 +529,9 @@ namespace ams::sm::impl {
|
||||||
|
|
||||||
/* Get service info. Check to see if we need to defer this until later. */
|
/* Get service info. Check to see if we need to defer this until later. */
|
||||||
ServiceInfo *service_info = GetServiceInfo(service);
|
ServiceInfo *service_info = GetServiceInfo(service);
|
||||||
R_UNLESS(service_info != nullptr, sf::ResultRequestDeferredByUser());
|
if (service_info == nullptr || ShouldDeferForInit(service) || HasFutureMitmDeclaration(service) || service_info->mitm_waiting_ack) {
|
||||||
R_UNLESS(!ShouldDeferForInit(service), sf::ResultRequestDeferredByUser());
|
return StartRegisterRetry(service);
|
||||||
R_UNLESS(!HasFutureMitmDeclaration(service), sf::ResultRequestDeferredByUser());
|
}
|
||||||
R_UNLESS(!service_info->mitm_waiting_ack, sf::ResultRequestDeferredByUser());
|
|
||||||
|
|
||||||
/* Get a handle from the service info. */
|
/* Get a handle from the service info. */
|
||||||
R_TRY_CATCH(GetServiceHandleImpl(out, service_info, process_id)) {
|
R_TRY_CATCH(GetServiceHandleImpl(out, service_info, process_id)) {
|
||||||
|
@ -588,8 +597,9 @@ namespace ams::sm::impl {
|
||||||
R_TRY(impl::HasMitm(&has_mitm, service));
|
R_TRY(impl::HasMitm(&has_mitm, service));
|
||||||
|
|
||||||
/* Wait until we have the mitm. */
|
/* Wait until we have the mitm. */
|
||||||
R_UNLESS(has_mitm, sf::ResultRequestDeferredByUser());
|
R_SUCCEED_IF(has_mitm);
|
||||||
return ResultSuccess();
|
|
||||||
|
return StartRegisterRetry(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result InstallMitm(Handle *out, Handle *out_query, os::ProcessId process_id, ServiceName service) {
|
Result InstallMitm(Handle *out, Handle *out_query, os::ProcessId process_id, ServiceName service) {
|
||||||
|
@ -607,7 +617,9 @@ namespace ams::sm::impl {
|
||||||
ServiceInfo *service_info = GetServiceInfo(service);
|
ServiceInfo *service_info = GetServiceInfo(service);
|
||||||
|
|
||||||
/* If it doesn't exist, defer until it does. */
|
/* If it doesn't exist, defer until it does. */
|
||||||
R_UNLESS(service_info != nullptr, sf::ResultRequestDeferredByUser());
|
if (service_info == nullptr) {
|
||||||
|
return StartRegisterRetry(service);
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate that the service isn't already being mitm'd. */
|
/* Validate that the service isn't already being mitm'd. */
|
||||||
R_UNLESS(!IsValidProcessId(service_info->mitm_process_id), sm::ResultAlreadyRegistered());
|
R_UNLESS(!IsValidProcessId(service_info->mitm_process_id), sm::ResultAlreadyRegistered());
|
||||||
|
@ -637,6 +649,9 @@ namespace ams::sm::impl {
|
||||||
service_info->mitm_query_h = std::move(mitm_qry_hnd);
|
service_info->mitm_query_h = std::move(mitm_qry_hnd);
|
||||||
*out = hnd.Move();
|
*out = hnd.Move();
|
||||||
*out_query = qry_hnd.Move();
|
*out_query = qry_hnd.Move();
|
||||||
|
|
||||||
|
/* This might undefer some requests. */
|
||||||
|
TriggerResume(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
future_guard.Cancel();
|
future_guard.Cancel();
|
||||||
|
@ -733,6 +748,10 @@ namespace ams::sm::impl {
|
||||||
|
|
||||||
/* Acknowledge. */
|
/* Acknowledge. */
|
||||||
service_info->AcknowledgeMitmSession(out_info, out_hnd);
|
service_info->AcknowledgeMitmSession(out_info, out_hnd);
|
||||||
|
|
||||||
|
/* Undefer requests to the session. */
|
||||||
|
TriggerResume(service);
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,6 +790,10 @@ namespace ams::sm::impl {
|
||||||
/* Deferral extension (works around FS bug). */
|
/* Deferral extension (works around FS bug). */
|
||||||
Result EndInitialDefers() {
|
Result EndInitialDefers() {
|
||||||
g_ended_initial_defers = true;
|
g_ended_initial_defers = true;
|
||||||
|
|
||||||
|
/* This might undefer some requests. */
|
||||||
|
TriggerResume(InitiallyDeferredServiceName);
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
107
stratosphere/sm/source/impl/sm_wait_list.cpp
Normal file
107
stratosphere/sm/source/impl/sm_wait_list.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* 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 "sm_wait_list.hpp"
|
||||||
|
|
||||||
|
namespace ams::sm::impl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static constexpr size_t DeferredSessionCountMax = 0x40;
|
||||||
|
|
||||||
|
struct WaitListEntry {
|
||||||
|
sm::ServiceName service;
|
||||||
|
os::WaitableHolderType *session;
|
||||||
|
};
|
||||||
|
|
||||||
|
constinit WaitListEntry g_entries[DeferredSessionCountMax];
|
||||||
|
constinit WaitListEntry *g_processing_entry = nullptr;
|
||||||
|
constinit ServiceName g_triggered_service = InvalidServiceName;
|
||||||
|
|
||||||
|
WaitListEntry *Find(ServiceName service) {
|
||||||
|
for (auto &entry : g_entries) {
|
||||||
|
if (entry.service == service) {
|
||||||
|
return std::addressof(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Result StartRegisterRetry(ServiceName service) {
|
||||||
|
/* Check that we're not already processing a retry. */
|
||||||
|
AMS_ABORT_UNLESS(g_processing_entry == nullptr);
|
||||||
|
|
||||||
|
/* Find a free entry. */
|
||||||
|
auto *entry = Find(InvalidServiceName);
|
||||||
|
R_UNLESS(entry != nullptr, sm::ResultOutOfProcesses());
|
||||||
|
|
||||||
|
/* Initialize the entry. */
|
||||||
|
entry->service = service;
|
||||||
|
entry->session = nullptr;
|
||||||
|
|
||||||
|
/* Set the processing entry. */
|
||||||
|
g_processing_entry = entry;
|
||||||
|
|
||||||
|
return sf::ResultRequestDeferredByUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessRegisterRetry(os::WaitableHolderType *session_holder) {
|
||||||
|
/* Verify that we have a processing entry. */
|
||||||
|
AMS_ABORT_UNLESS(g_processing_entry != nullptr);
|
||||||
|
|
||||||
|
/* Process the session. */
|
||||||
|
g_processing_entry->session = session_holder;
|
||||||
|
g_processing_entry = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerResume(ServiceName service) {
|
||||||
|
/* Check that we haven't already triggered a resume. */
|
||||||
|
AMS_ABORT_UNLESS(g_triggered_service == InvalidServiceName);
|
||||||
|
|
||||||
|
/* Set the triggered resume. */
|
||||||
|
g_triggered_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestAndResume(ResumeFunction resume_function) {
|
||||||
|
/* If we don't have a triggered service, there's nothing to do. */
|
||||||
|
if (g_triggered_service == InvalidServiceName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process all entries. */
|
||||||
|
for (auto &entry : g_entries) {
|
||||||
|
if (entry.service == g_triggered_service) {
|
||||||
|
/* Get the entry's session. */
|
||||||
|
auto * const session = entry.session;
|
||||||
|
|
||||||
|
/* Clear the entry. */
|
||||||
|
entry.service = InvalidServiceName;
|
||||||
|
entry.session = nullptr;
|
||||||
|
|
||||||
|
/* Resume the request. */
|
||||||
|
R_TRY_CATCH(resume_function(session)) {
|
||||||
|
R_CATCH(sf::ResultRequestDeferred) {
|
||||||
|
ProcessRegisterRetry(session);
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
stratosphere/sm/source/impl/sm_wait_list.hpp
Normal file
29
stratosphere/sm/source/impl/sm_wait_list.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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 <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::sm::impl {
|
||||||
|
|
||||||
|
using ResumeFunction = Result (*)(os::WaitableHolderType *session_holder);
|
||||||
|
|
||||||
|
Result StartRegisterRetry(ServiceName service);
|
||||||
|
void ProcessRegisterRetry(os::WaitableHolderType *session_holder);
|
||||||
|
|
||||||
|
void TriggerResume(ServiceName service);
|
||||||
|
void TestAndResume(ResumeFunction resume_function);
|
||||||
|
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
#include "sm_manager_service.hpp"
|
#include "sm_manager_service.hpp"
|
||||||
#include "sm_debug_monitor_service.hpp"
|
#include "sm_debug_monitor_service.hpp"
|
||||||
#include "impl/sm_service_manager.hpp"
|
#include "impl/sm_service_manager.hpp"
|
||||||
|
#include "impl/sm_wait_list.hpp"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
extern u32 __start__;
|
extern u32 __start__;
|
||||||
|
@ -86,6 +87,10 @@ namespace {
|
||||||
constexpr size_t NumServers = 3;
|
constexpr size_t NumServers = 3;
|
||||||
sf::hipc::ServerManager<NumServers> g_server_manager;
|
sf::hipc::ServerManager<NumServers> g_server_manager;
|
||||||
|
|
||||||
|
ams::Result ResumeImpl(os::WaitableHolderType *session_holder) {
|
||||||
|
return g_server_manager.Process(session_holder);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -94,13 +99,10 @@ int main(int argc, char **argv)
|
||||||
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(sm, Main));
|
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(sm, Main));
|
||||||
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(sm, Main));
|
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(sm, Main));
|
||||||
|
|
||||||
/* NOTE: These handles are manually managed, but we don't save references to them to close on exit. */
|
|
||||||
/* This is fine, because if SM crashes we have much bigger issues. */
|
|
||||||
|
|
||||||
/* Create sm:, (and thus allow things to register to it). */
|
/* Create sm:, (and thus allow things to register to it). */
|
||||||
{
|
{
|
||||||
Handle sm_h;
|
Handle sm_h;
|
||||||
R_ABORT_UNLESS(svcManageNamedPort(&sm_h, "sm:", 0x40));
|
R_ABORT_UNLESS(svc::ManageNamedPort(&sm_h, "sm:", 0x40));
|
||||||
g_server_manager.RegisterServer<sm::impl::IUserInterface, sm::UserService>(sm_h);
|
g_server_manager.RegisterServer<sm::impl::IUserInterface, sm::UserService>(sm_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +124,23 @@ int main(int argc, char **argv)
|
||||||
/*================================*/
|
/*================================*/
|
||||||
|
|
||||||
/* Loop forever, servicing our services. */
|
/* Loop forever, servicing our services. */
|
||||||
g_server_manager.LoopProcess();
|
while (true) {
|
||||||
|
/* Get the next signaled holder. */
|
||||||
|
auto *holder = g_server_manager.WaitSignaled();
|
||||||
|
AMS_ABORT_UNLESS(holder != nullptr);
|
||||||
|
|
||||||
/* Cleanup. */
|
/* Process the holder. */
|
||||||
return 0;
|
R_TRY_CATCH(g_server_manager.Process(holder)) {
|
||||||
|
R_CATCH(sf::ResultRequestDeferred) {
|
||||||
|
sm::impl::ProcessRegisterRetry(holder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
|
||||||
|
/* Test to see if anything can be undeferred. */
|
||||||
|
sm::impl::TestAndResume(ResumeImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This can never be reached. */
|
||||||
|
AMS_ASSUME(false);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue