diff options
Diffstat (limited to 'src/core/hle/service/sm')
-rw-r--r-- | src/core/hle/service/sm/sm.cpp | 106 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 35 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm_controller.cpp | 17 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm_controller.h | 8 |
4 files changed, 101 insertions, 65 deletions
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 84720094f..b4046d3ce 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -5,62 +5,60 @@ #include "common/assert.h" #include "common/scope_exit.h" #include "core/core.h" -#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_port.h" #include "core/hle/result.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm_controller.h" namespace Service::SM { -constexpr Result ERR_NOT_INITIALIZED(ErrorModule::SM, 2); -constexpr Result ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); -constexpr Result ERR_INVALID_NAME(ErrorModule::SM, 6); -constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); +constexpr Result ResultInvalidClient(ErrorModule::SM, 2); +constexpr Result ResultAlreadyRegistered(ErrorModule::SM, 4); +constexpr Result ResultInvalidServiceName(ErrorModule::SM, 6); +constexpr Result ResultNotRegistered(ErrorModule::SM, 7); -ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} +ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} { + controller_interface = std::make_unique<Controller>(kernel.System()); +} ServiceManager::~ServiceManager() { for (auto& [name, port] : service_ports) { port->GetClientPort().Close(); port->GetServerPort().Close(); } + + if (deferral_event) { + deferral_event->Close(); + } } -void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { +void ServiceManager::InvokeControlRequest(HLERequestContext& context) { controller_interface->InvokeRequest(context); } static Result ValidateServiceName(const std::string& name) { if (name.empty() || name.size() > 8) { LOG_ERROR(Service_SM, "Invalid service name! service={}", name); - return ERR_INVALID_NAME; + return Service::SM::ResultInvalidServiceName; } return ResultSuccess; } -Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { - self.sm_interface = std::make_shared<SM>(self, system); - self.controller_interface = std::make_unique<Controller>(system); - return self.sm_interface->CreatePort(); -} - -void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) { - self.sm_interface->AcceptSession(server_port); -} - Result ServiceManager::RegisterService(std::string name, u32 max_sessions, - Kernel::SessionRequestHandlerPtr handler) { + SessionRequestHandlerPtr handler) { CASCADE_CODE(ValidateServiceName(name)); + std::scoped_lock lk{lock}; if (registered_services.find(name) != registered_services.end()) { LOG_ERROR(Service_SM, "Service is already registered! service={}", name); - return ERR_ALREADY_REGISTERED; + return Service::SM::ResultAlreadyRegistered; } auto* port = Kernel::KPort::Create(kernel); @@ -68,6 +66,9 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, service_ports.emplace(name, port); registered_services.emplace(name, handler); + if (deferral_event) { + deferral_event->Signal(); + } return ResultSuccess; } @@ -75,10 +76,11 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, Result ServiceManager::UnregisterService(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); + std::scoped_lock lk{lock}; const auto iter = registered_services.find(name); if (iter == registered_services.end()) { LOG_ERROR(Service_SM, "Server is not registered! service={}", name); - return ERR_SERVICE_NOT_REGISTERED; + return Service::SM::ResultNotRegistered; } registered_services.erase(iter); @@ -89,10 +91,12 @@ Result ServiceManager::UnregisterService(const std::string& name) { ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); + + std::scoped_lock lk{lock}; auto it = service_ports.find(name); if (it == service_ports.end()) { - LOG_ERROR(Service_SM, "Server is not registered! service={}", name); - return ERR_SERVICE_NOT_REGISTERED; + LOG_WARNING(Service_SM, "Server is not registered! service={}", name); + return Service::SM::ResultNotRegistered; } return it->second; @@ -105,17 +109,22 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name * Outputs: * 0: Result */ -void SM::Initialize(Kernel::HLERequestContext& ctx) { +void SM::Initialize(HLERequestContext& ctx) { LOG_DEBUG(Service_SM, "called"); - is_initialized = true; + ctx.GetManager()->SetIsInitializedForSm(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } -void SM::GetService(Kernel::HLERequestContext& ctx) { +void SM::GetService(HLERequestContext& ctx) { auto result = GetServiceImpl(ctx); + if (ctx.GetIsDeferred()) { + // Don't overwrite the command buffer. + return; + } + if (result.Succeeded()) { IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(result.Code()); @@ -126,8 +135,13 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { } } -void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { +void SM::GetServiceTipc(HLERequestContext& ctx) { auto result = GetServiceImpl(ctx); + if (ctx.GetIsDeferred()) { + // Don't overwrite the command buffer. + return; + } + IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(result.Code()); rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); @@ -144,9 +158,9 @@ static std::string PopServiceName(IPC::RequestParser& rp) { return result; } -ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) { - if (!is_initialized) { - return ERR_NOT_INITIALIZED; +ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) { + if (!ctx.GetManager()->GetIsInitializedForSm()) { + return Service::SM::ResultInvalidClient; } IPC::RequestParser rp{ctx}; @@ -154,10 +168,15 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& // Find the named port. auto port_result = service_manager.GetServicePort(name); - auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name); - if (port_result.Failed() || !service) { - LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); - return port_result.Code(); + if (port_result.Code() == Service::SM::ResultInvalidServiceName) { + LOG_ERROR(Service_SM, "Invalid service name '{}'", name); + return Service::SM::ResultInvalidServiceName; + } + + if (port_result.Failed()) { + LOG_INFO(Service_SM, "Waiting for service {} to become available", name); + ctx.SetIsDeferred(); + return Service::SM::ResultNotRegistered; } auto& port = port_result.Unwrap(); @@ -167,14 +186,13 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); return result; } - service->AcceptSession(&port->GetServerPort()); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); return session; } -void SM::RegisterService(Kernel::HLERequestContext& ctx) { +void SM::RegisterService(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; std::string name(PopServiceName(rp)); @@ -201,7 +219,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(port->GetServerPort()); } -void SM::UnregisterService(Kernel::HLERequestContext& ctx) { +void SM::UnregisterService(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; std::string name(PopServiceName(rp)); @@ -212,7 +230,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) { } SM::SM(ServiceManager& service_manager_, Core::System& system_) - : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4}, + : ServiceFramework{system_, "sm:", 4}, service_manager{service_manager_}, kernel{system_.Kernel()} { RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, @@ -232,4 +250,16 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_) SM::~SM() = default; +void LoopProcess(Core::System& system) { + auto& service_manager = system.ServiceManager(); + auto server_manager = std::make_unique<ServerManager>(system); + + Kernel::KEvent* deferral_event{}; + server_manager->ManageDeferral(&deferral_event); + service_manager.SetDeferralEvent(deferral_event); + + server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system)); + ServerManager::RunServer(std::move(server_manager)); +} + } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 02a5dde9e..6697f4007 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -4,6 +4,7 @@ #pragma once #include <memory> +#include <mutex> #include <string> #include <unordered_map> @@ -35,33 +36,28 @@ public: ~SM() override; private: - void Initialize(Kernel::HLERequestContext& ctx); - void GetService(Kernel::HLERequestContext& ctx); - void GetServiceTipc(Kernel::HLERequestContext& ctx); - void RegisterService(Kernel::HLERequestContext& ctx); - void UnregisterService(Kernel::HLERequestContext& ctx); + void Initialize(HLERequestContext& ctx); + void GetService(HLERequestContext& ctx); + void GetServiceTipc(HLERequestContext& ctx); + void RegisterService(HLERequestContext& ctx); + void UnregisterService(HLERequestContext& ctx); - ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx); + ResultVal<Kernel::KClientSession*> GetServiceImpl(HLERequestContext& ctx); ServiceManager& service_manager; - bool is_initialized{}; Kernel::KernelCore& kernel; }; class ServiceManager { public: - static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system); - static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port); - explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); - Result RegisterService(std::string name, u32 max_sessions, - Kernel::SessionRequestHandlerPtr handler); + Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler); Result UnregisterService(const std::string& name); ResultVal<Kernel::KPort*> GetServicePort(const std::string& name); - template <Common::DerivedFrom<Kernel::SessionRequestHandler> T> + template <Common::DerivedFrom<SessionRequestHandler> T> std::shared_ptr<T> GetService(const std::string& service_name) const { auto service = registered_services.find(service_name); if (service == registered_services.end()) { @@ -71,18 +67,27 @@ public: return std::static_pointer_cast<T>(service->second); } - void InvokeControlRequest(Kernel::HLERequestContext& context); + void InvokeControlRequest(HLERequestContext& context); + + void SetDeferralEvent(Kernel::KEvent* deferral_event_) { + deferral_event = deferral_event_; + } private: std::shared_ptr<SM> sm_interface; std::unique_ptr<Controller> controller_interface; /// Map of registered services, retrieved using GetServicePort. - std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services; + std::mutex lock; + std::unordered_map<std::string, SessionRequestHandlerPtr> registered_services; std::unordered_map<std::string, Kernel::KPort*> service_ports; /// Kernel context Kernel::KernelCore& kernel; + Kernel::KEvent* deferral_event{}; }; +/// Runs SM services. +void LoopProcess(Core::System& system); + } // namespace Service::SM diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 1cf9dd1c4..0111c8d7f 100644 --- a/src/core/hle/service/sm/sm_controller.cpp +++ b/src/core/hle/service/sm/sm_controller.cpp @@ -4,17 +4,18 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm_controller.h" namespace Service::SM { -void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { +void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) { ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); ctx.GetManager()->ConvertToDomainOnRequestEnd(); @@ -24,7 +25,7 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { rb.Push<u32>(1); // Converted sessions start with 1 request handler } -void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { +void Controller::CloneCurrentObject(HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); auto& process = *ctx.GetThread().GetOwnerProcess(); @@ -48,9 +49,9 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { // Commit the session reservation. session_reservation.Commit(); - // Register with manager. - session_manager->SessionHandler().RegisterSession(&session->GetServerSession(), - session_manager); + // Register with server manager. + session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), + session_manager); // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; @@ -58,13 +59,13 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(session->GetClientSession()); } -void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { +void Controller::CloneCurrentObjectEx(HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); CloneCurrentObject(ctx); } -void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { +void Controller::QueryPointerBufferSize(HLERequestContext& ctx) { LOG_WARNING(Service, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/sm/sm_controller.h b/src/core/hle/service/sm/sm_controller.h index ed386f660..4e748b36d 100644 --- a/src/core/hle/service/sm/sm_controller.h +++ b/src/core/hle/service/sm/sm_controller.h @@ -17,10 +17,10 @@ public: ~Controller() override; private: - void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx); - void CloneCurrentObject(Kernel::HLERequestContext& ctx); - void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx); - void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); + void ConvertCurrentObjectToDomain(HLERequestContext& ctx); + void CloneCurrentObject(HLERequestContext& ctx); + void CloneCurrentObjectEx(HLERequestContext& ctx); + void QueryPointerBufferSize(HLERequestContext& ctx); }; } // namespace Service::SM |