tipc/sm: update more fully for 13.0.0 changes
This commit is contained in:
@@ -604,11 +604,10 @@ namespace ams::sm::impl {
|
||||
bool has_service = false;
|
||||
R_TRY(impl::HasService(std::addressof(has_service), service));
|
||||
|
||||
/* If we do, we can succeed immediately. */
|
||||
R_SUCCEED_IF(has_service);
|
||||
/* If we don't, we want to wait until the service is registered. */
|
||||
R_UNLESS(has_service, tipc::ResultRequestDeferred());
|
||||
|
||||
/* Otherwise, we want to wait until the service is registered. */
|
||||
return StartRegisterRetry(service);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetServiceHandle(os::NativeHandle *out, os::ProcessId process_id, ServiceName service) {
|
||||
@@ -628,9 +627,10 @@ namespace ams::sm::impl {
|
||||
/* Get service info. Check to see if we need to defer this until later. */
|
||||
ServiceInfo *service_info = GetServiceInfo(service);
|
||||
MitmInfo *mitm_info = GetMitmInfo(service_info);
|
||||
if (service_info == nullptr || ShouldDeferForInit(service) || HasFutureMitmDeclaration(service) || (mitm_info != nullptr && mitm_info->waiting_ack)) {
|
||||
return StartRegisterRetry(service);
|
||||
}
|
||||
R_UNLESS(service_info != nullptr, tipc::ResultRequestDeferred());
|
||||
R_UNLESS(!ShouldDeferForInit(service), tipc::ResultRequestDeferred());
|
||||
R_UNLESS(!HasFutureMitmDeclaration(service), tipc::ResultRequestDeferred());
|
||||
R_UNLESS((mitm_info == nullptr || !mitm_info->waiting_ack), tipc::ResultRequestDeferred());
|
||||
|
||||
/* Get a handle from the service info. */
|
||||
R_TRY_CATCH(GetServiceHandleImpl(out, service_info, process_id)) {
|
||||
@@ -715,11 +715,10 @@ namespace ams::sm::impl {
|
||||
bool has_mitm = false;
|
||||
R_TRY(impl::HasMitm(std::addressof(has_mitm), service));
|
||||
|
||||
/* If we do, we can succeed immediately. */
|
||||
R_SUCCEED_IF(has_mitm);
|
||||
/* If we don't, we want to wait until the mitm is installed. */
|
||||
R_UNLESS(has_mitm, tipc::ResultRequestDeferred());
|
||||
|
||||
/* Otherwise, we want to wait until the service is registered. */
|
||||
return StartRegisterRetry(service);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result InstallMitm(os::NativeHandle *out, os::NativeHandle *out_query, os::ProcessId process_id, ServiceName service) {
|
||||
@@ -740,7 +739,7 @@ namespace ams::sm::impl {
|
||||
ServiceInfo *service_info = GetServiceInfo(service);
|
||||
|
||||
/* If it doesn't exist, defer until it does. */
|
||||
R_UNLESS(service_info != nullptr, StartRegisterRetry(service));
|
||||
R_UNLESS(service_info != nullptr, tipc::ResultRequestDeferred());
|
||||
|
||||
/* Validate that the service isn't already being mitm'd. */
|
||||
R_UNLESS(GetMitmInfo(service_info) == nullptr, sm::ResultAlreadyRegistered());
|
||||
|
||||
@@ -40,99 +40,12 @@ namespace ams::sm {
|
||||
|
||||
static_assert(MaxSessionsTotal % NumTipcPorts == 0);
|
||||
|
||||
/* Define WaitList class. */
|
||||
class WaitList {
|
||||
public:
|
||||
using Key = sm::ServiceName;
|
||||
private:
|
||||
struct Entry {
|
||||
sm::ServiceName service_name{sm::InvalidServiceName};
|
||||
tipc::ObjectHolder object{};
|
||||
u8 message_buffer[svc::ipc::MessageBufferSize];
|
||||
};
|
||||
private:
|
||||
Entry m_entries[MaxSessionsTotal / NumTipcPorts]{};
|
||||
Entry *m_processing_entry{};
|
||||
public:
|
||||
constexpr WaitList() = default;
|
||||
public:
|
||||
Result StartRegisterRetry(sm::ServiceName service_name) {
|
||||
/* Check that we're not already processing a retry. */
|
||||
AMS_ABORT_UNLESS(m_processing_entry == nullptr);
|
||||
|
||||
/* Find a free entry. */
|
||||
Entry *free_entry = nullptr;
|
||||
for (auto &entry : m_entries) {
|
||||
if (entry.service_name == InvalidServiceName) {
|
||||
free_entry = std::addressof(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that we found a free entry. */
|
||||
R_UNLESS(free_entry != nullptr, sm::ResultOutOfProcesses());
|
||||
|
||||
/* Populate the entry. */
|
||||
free_entry->service_name = service_name;
|
||||
std::memcpy(free_entry->message_buffer, svc::ipc::GetMessageBuffer(), util::size(free_entry->message_buffer));
|
||||
|
||||
/* Set the processing entry. */
|
||||
m_processing_entry = free_entry;
|
||||
|
||||
/* Return the special request deferral result. */
|
||||
return tipc::ResultRequestDeferred();
|
||||
}
|
||||
|
||||
void ProcessRegisterRetry(tipc::ObjectHolder &object) {
|
||||
/* Verify that we have a processing entry. */
|
||||
AMS_ABORT_UNLESS(m_processing_entry != nullptr);
|
||||
|
||||
/* Set the entry's object. */
|
||||
m_processing_entry->object = object;
|
||||
|
||||
/* Clear our processing entry. */
|
||||
m_processing_entry = nullptr;
|
||||
}
|
||||
|
||||
bool TestResume(sm::ServiceName service_name) {
|
||||
/* Check that we have a matching service name. */
|
||||
for (const auto &entry : m_entries) {
|
||||
if (entry.service_name == service_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename PortManagerType>
|
||||
void Resume(sm::ServiceName service_name, PortManagerType *port_manager) {
|
||||
/* Resume (and clear) all matching entries. */
|
||||
for (auto &entry : m_entries) {
|
||||
if (entry.service_name == service_name) {
|
||||
/* Copy the saved message buffer. */
|
||||
std::memcpy(svc::ipc::GetMessageBuffer(), entry.message_buffer, svc::ipc::MessageBufferSize);
|
||||
|
||||
/* Resume the request. */
|
||||
R_TRY_CATCH(port_manager->ProcessRequest(entry.object)) {
|
||||
R_CATCH(tipc::ResultRequestDeferred) {
|
||||
this->ProcessRegisterRetry(entry.object);
|
||||
}
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
|
||||
/* Clear the entry's service name. */
|
||||
entry.service_name = sm::InvalidServiceName;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Define port metadata. */
|
||||
using UserPortMeta = tipc::PortMeta<MaxSessionsUser, impl::IUserInterface, UserService, tipc::SlabAllocator>;
|
||||
using ManagerPortMeta = tipc::PortMeta<MaxSessionsManager, impl::IManagerInterface, ManagerService, tipc::SingletonAllocator>;
|
||||
using UserPortMeta = tipc::PortMeta<MaxSessionsUser, impl::IUserInterface, UserService, tipc::SlabAllocator>;
|
||||
using ManagerPortMeta = tipc::PortMeta<MaxSessionsManager, impl::IManagerInterface, ManagerService, tipc::SingletonAllocator>;
|
||||
|
||||
/* Define server manager global. */
|
||||
using ServerManager = tipc::ServerManagerWithDeferral<sm::WaitList, ManagerPortMeta, UserPortMeta>;
|
||||
using ServerManager = tipc::ServerManager<ManagerPortMeta, UserPortMeta>;
|
||||
|
||||
ServerManager g_server_manager;
|
||||
|
||||
@@ -162,14 +75,6 @@ namespace ams::sm {
|
||||
g_server_manager.LoopAuto();
|
||||
}
|
||||
|
||||
Result StartRegisterRetry(sm::ServiceName service_name) {
|
||||
/* Get the port manager from where it's saved in TLS. */
|
||||
auto *port_manager = reinterpret_cast<typename ServerManager::PortManagerBase *>(os::GetTlsValue(g_server_manager.GetTlsSlot()));
|
||||
|
||||
/* Register the retry. */
|
||||
return port_manager->StartRegisterRetry(service_name);
|
||||
}
|
||||
|
||||
void TriggerResume(sm::ServiceName service_name) {
|
||||
/* Trigger a resumption. */
|
||||
g_server_manager.TriggerResume(service_name);
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace ams::sm {
|
||||
const Result result = this->GetServiceHandle(std::addressof(out_handle), service_name);
|
||||
|
||||
/* Serialize output. */
|
||||
if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) {
|
||||
if (!tipc::ResultRequestDeferred::Includes(result)) {
|
||||
std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService));
|
||||
std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle));
|
||||
std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result));
|
||||
@@ -155,12 +155,8 @@ namespace ams::sm {
|
||||
const Result result = this->UnregisterService(service_name);
|
||||
|
||||
/* Serialize output. */
|
||||
if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) {
|
||||
std::memcpy(out_message_buffer + 0x00, CmifResponseToUnregisterService, sizeof(CmifResponseToUnregisterService));
|
||||
std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result));
|
||||
} else {
|
||||
std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral));
|
||||
}
|
||||
std::memcpy(out_message_buffer + 0x00, CmifResponseToUnregisterService, sizeof(CmifResponseToUnregisterService));
|
||||
std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result));
|
||||
} else {
|
||||
return tipc::ResultInvalidMethod();
|
||||
}
|
||||
@@ -186,13 +182,9 @@ namespace ams::sm {
|
||||
const Result result = this->RegisterService(std::addressof(out_handle), service_name, max_sessions, is_light);
|
||||
|
||||
/* Serialize output. */
|
||||
if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) {
|
||||
std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService));
|
||||
std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle));
|
||||
std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result));
|
||||
} else {
|
||||
std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral));
|
||||
}
|
||||
std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService));
|
||||
std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle));
|
||||
std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result));
|
||||
} else {
|
||||
return tipc::ResultInvalidMethod();
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
namespace ams::sm {
|
||||
|
||||
/* Service definition. */
|
||||
class UserService {
|
||||
class UserService : public tipc::DeferrableBase {
|
||||
private:
|
||||
os::ProcessId m_process_id;
|
||||
bool m_initialized;
|
||||
public:
|
||||
constexpr UserService() : m_process_id{os::InvalidProcessId}, m_initialized{false} { /* ... */ }
|
||||
virtual ~UserService() {
|
||||
UserService() : m_process_id{os::InvalidProcessId}, m_initialized{false} { /* ... */ }
|
||||
~UserService() {
|
||||
if (m_initialized) {
|
||||
impl::OnClientDisconnected(m_process_id);
|
||||
}
|
||||
@@ -41,7 +41,9 @@ namespace ams::sm {
|
||||
|
||||
Result GetServiceHandle(tipc::OutMoveHandle out_h, ServiceName service) {
|
||||
R_UNLESS(m_initialized, sm::ResultInvalidClient());
|
||||
return impl::GetServiceHandle(out_h.GetPointer(), m_process_id, service);
|
||||
return this->RegisterRetryIfDeferred(service, [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
return impl::GetServiceHandle(out_h.GetPointer(), m_process_id, service);
|
||||
});
|
||||
}
|
||||
|
||||
Result RegisterService(tipc::OutMoveHandle out_h, ServiceName service, u32 max_sessions, bool is_light) {
|
||||
@@ -64,7 +66,9 @@ namespace ams::sm {
|
||||
/* Atmosphere commands. */
|
||||
Result AtmosphereInstallMitm(tipc::OutMoveHandle srv_h, tipc::OutMoveHandle qry_h, ServiceName service) {
|
||||
R_UNLESS(m_initialized, sm::ResultInvalidClient());
|
||||
return impl::InstallMitm(srv_h.GetPointer(), qry_h.GetPointer(), m_process_id, service);
|
||||
return this->RegisterRetryIfDeferred(service, [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
return impl::InstallMitm(srv_h.GetPointer(), qry_h.GetPointer(), m_process_id, service);
|
||||
});
|
||||
}
|
||||
|
||||
Result AtmosphereUninstallMitm(ServiceName service) {
|
||||
@@ -84,7 +88,9 @@ namespace ams::sm {
|
||||
|
||||
Result AtmosphereWaitMitm(ServiceName service) {
|
||||
R_UNLESS(m_initialized, sm::ResultInvalidClient());
|
||||
return impl::WaitMitm(service);
|
||||
return this->RegisterRetryIfDeferred(service, [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
return impl::WaitMitm(service);
|
||||
});
|
||||
}
|
||||
|
||||
Result AtmosphereDeclareFutureMitm(ServiceName service) {
|
||||
@@ -104,13 +110,16 @@ namespace ams::sm {
|
||||
|
||||
Result AtmosphereWaitService(ServiceName service) {
|
||||
R_UNLESS(m_initialized, sm::ResultInvalidClient());
|
||||
return impl::WaitService(service);
|
||||
return this->RegisterRetryIfDeferred(service, [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
return impl::WaitService(service);
|
||||
});
|
||||
}
|
||||
public:
|
||||
/* Backwards compatibility layer for cmif. */
|
||||
Result ProcessDefaultServiceCommand(const svc::ipc::MessageBuffer &message_buffer);
|
||||
};
|
||||
static_assert(sm::impl::IsIUserInterface<UserService>);
|
||||
static_assert(tipc::IsDeferrable<UserService>);
|
||||
/* TODO: static assert that this is a tipc interface with default prototyping. */
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
namespace ams::sm {
|
||||
|
||||
Result StartRegisterRetry(sm::ServiceName service_name);
|
||||
|
||||
void TriggerResume(sm::ServiceName service_name);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user