diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5ee7679eba..9a9cd4bfda 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -7,16 +7,39 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_port.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/service/service.h" namespace Kernel { ClientPort::ClientPort() {} ClientPort::~ClientPort() {} +Kernel::SharedPtr ClientPort::CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface) { + SharedPtr client_port(new ClientPort); + client_port->max_sessions = max_sessions; + client_port->active_sessions = 0; + client_port->name = hle_interface->GetPortName(); + client_port->hle_interface = std::move(hle_interface); + + return client_port; +} + void ClientPort::AddWaitingSession(SharedPtr server_session) { + // A port that has an associated HLE interface doesn't have a server port. + if (hle_interface != nullptr) + return; + server_port->pending_sessions.push_back(server_session); // Wake the threads waiting on the ServerPort server_port->WakeupAllWaitingThreads(); } +ResultCode ClientPort::HandleSyncRequest() { + // Forward the request to the associated HLE interface if it exists + if (hle_interface != nullptr) + return hle_interface->HandleSyncRequest(); + + return RESULT_SUCCESS; +} + } // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index eb0882870e..ee65606ba2 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -5,18 +5,31 @@ #pragma once #include +#include #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +namespace Service { +class Interface; +} + namespace Kernel { class ServerPort; class ServerSession; -class ClientPort : public Object { +class ClientPort final : public Object { public: friend class ServerPort; + /** + * Creates a serverless ClientPort that represents a bridge between the HLE implementation of a service/port and the emulated application. + * @param max_sessions Maximum number of sessions that this port is able to handle concurrently. + * @param hle_interface Interface object that implements the commands of the service. + * @returns ClientPort for the given HLE interface. + */ + static Kernel::SharedPtr CreateForHLE(u32 max_sessions, std::unique_ptr hle_interface); + /** * Adds the specified server session to the queue of pending sessions of the associated ServerPort * @param server_session Server session to add to the queue @@ -25,10 +38,9 @@ public: /** * Handle a sync request from the emulated application. - * Only HLE services should override this function. * @returns ResultCode from the operation. */ - virtual ResultCode HandleSyncRequest() { return RESULT_SUCCESS; } + ResultCode HandleSyncRequest(); std::string GetTypeName() const override { return "ClientPort"; } std::string GetName() const override { return name; } @@ -38,12 +50,13 @@ public: return HANDLE_TYPE; } - SharedPtr server_port; ///< ServerPort associated with this client port. - u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have - u32 active_sessions; ///< Number of currently open sessions to this port - std::string name; ///< Name of client port (optional) + SharedPtr server_port = nullptr; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) + std::unique_ptr hle_interface = nullptr; ///< HLE implementation of this port's request handler -protected: +private: ClientPort(); ~ClientPort() override; }; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index f51a042ff1..abfc1806bf 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -97,17 +97,13 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { // Module interface static void AddNamedPort(Interface* interface_) { - interface_->name = interface_->GetPortName(); - interface_->active_sessions = 0; - interface_->max_sessions = interface_->GetMaxSessions(); - g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); } void AddService(Interface* interface_) { - interface_->name = interface_->GetPortName(); - interface_->active_sessions = 0; - interface_->max_sessions = interface_->GetMaxSessions(); - g_srv_services.emplace(interface_->GetPortName(), interface_); + auto client_port = Kernel::ClientPort::CreateForHLE(interface_->GetMaxSessions(), std::unique_ptr(interface_)); + g_srv_services.emplace(interface_->GetPortName(), client_port); } /// Initialize ServiceManager diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 8df968b2ed..b22caca07f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -22,18 +22,16 @@ static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 character static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port /// Interface to a CTROS service -class Interface : public Kernel::ClientPort { - // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be - // just something that encapsulates a session and acts as a helper to implement service - // processes. +class Interface { public: - std::string GetName() const override { + std::string GetName() const { return GetPortName(); } virtual void SetVersion(u32 raw_version) { version.raw = raw_version; } + virtual ~Interface() {} /** * Gets the maximum allowed number of sessions that can be connected to this port at the same time. @@ -42,8 +40,6 @@ public: */ virtual u32 GetMaxSessions() const { return DefaultMaxSessions; } - void AddWaitingSession(Kernel::SharedPtr server_session) override { } - typedef void (*Function)(Interface*); struct FunctionInfo { @@ -60,7 +56,7 @@ public: return "[UNKNOWN SERVICE PORT]"; } - ResultCode HandleSyncRequest() override; + ResultCode HandleSyncRequest(); protected: /**