mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	KServerPorts now have an HLE handler "template", which is inherited by all ServerSessions created from it.
This commit is contained in:
		
							parent
							
								
									2ce61344d6
								
							
						
					
					
						commit
						dd8887c8cf
					
				
					 12 changed files with 86 additions and 69 deletions
				
			
		|  | @ -13,10 +13,18 @@ namespace Kernel { | |||
| ClientPort::ClientPort() {} | ||||
| ClientPort::~ClientPort() {} | ||||
| 
 | ||||
| void ClientPort::AddWaitingSession(SharedPtr<ServerSession> server_session) { | ||||
| SharedPtr<ClientSession> ClientPort::Connect() { | ||||
|     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
 | ||||
|     auto sessions = ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); | ||||
|     auto client_session = std::get<SharedPtr<ClientSession>>(sessions); | ||||
|     auto server_session = std::get<SharedPtr<ServerSession>>(sessions); | ||||
| 
 | ||||
|     server_port->pending_sessions.push_back(server_session); | ||||
| 
 | ||||
|     // Wake the threads waiting on the ServerPort
 | ||||
|     server_port->WakeupAllWaitingThreads(); | ||||
| 
 | ||||
|     return std::move(client_session); | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
| namespace Kernel { | ||||
| 
 | ||||
| class ServerPort; | ||||
| class ServerSession; | ||||
| class ClientSession; | ||||
| 
 | ||||
| class ClientPort final : public Object { | ||||
| public: | ||||
|  | @ -29,15 +29,17 @@ public: | |||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 | ||||
|      * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's list of pending sessions, | ||||
|      * and signals the ServerPort, causing any threads waiting on it to awake. | ||||
|      * @returns ClientSession The client endpoint of the created Session pair. | ||||
|      */ | ||||
|     void AddWaitingSession(SharedPtr<ServerSession> server_session); | ||||
|     SharedPtr<ClientSession> Connect(); | ||||
| 
 | ||||
|     SharedPtr<ServerPort> 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)
 | ||||
| 
 | ||||
| private: | ||||
|     ClientPort(); | ||||
|     ~ClientPort() override; | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ ResultVal<SharedPtr<ClientSession>> ClientSession::Create(SharedPtr<ServerSessio | |||
|     return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); | ||||
| } | ||||
| 
 | ||||
| ResultCode ClientSession::HandleSyncRequest() { | ||||
| ResultCode ClientSession::SendSyncRequest() { | ||||
|     // Signal the server session that new data is available
 | ||||
|     return server_session->HandleSyncRequest(); | ||||
| } | ||||
|  |  | |||
|  | @ -17,17 +17,12 @@ class ServerSession; | |||
| 
 | ||||
| class ClientSession final : public Object { | ||||
| public: | ||||
|     /**
 | ||||
|      * Creates a client session. | ||||
|      * @param server_session The server session associated with this client session | ||||
|      * @param name Optional name of client session | ||||
|      * @return The created client session | ||||
|      */ | ||||
|     static ResultVal<SharedPtr<ClientSession>> Create(SharedPtr<ServerSession> server_session, std::string name = "Unknown"); | ||||
|     friend class ServerSession; | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ClientSession"; | ||||
|     } | ||||
| 
 | ||||
|     std::string GetName() const override { | ||||
|         return name; | ||||
|     } | ||||
|  | @ -38,10 +33,10 @@ public: | |||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Handle a SyncRequest from the emulated application. | ||||
|      * Sends an SyncRequest from the current emulated thread. | ||||
|      * @return ResultCode of the operation. | ||||
|      */ | ||||
|     ResultCode HandleSyncRequest(); | ||||
|     ResultCode SendSyncRequest(); | ||||
| 
 | ||||
|     std::string name;                           ///< Name of client port (optional)
 | ||||
|     SharedPtr<ServerSession> server_session;    ///< The server session associated with this client session.
 | ||||
|  | @ -49,6 +44,14 @@ public: | |||
| private: | ||||
|     ClientSession(); | ||||
|     ~ClientSession() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a client session. | ||||
|      * @param server_session The server session associated with this client session | ||||
|      * @param name Optional name of client session | ||||
|      * @return The created client session | ||||
|      */ | ||||
|     static ResultVal<SharedPtr<ClientSession>> Create(SharedPtr<ServerSession> server_session, std::string name = "Unknown"); | ||||
| }; | ||||
| 
 | ||||
| } // namespace
 | ||||
|  |  | |||
|  | @ -24,12 +24,13 @@ void ServerPort::Acquire() { | |||
| } | ||||
| 
 | ||||
| std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( | ||||
|     u32 max_sessions, std::string name) { | ||||
|     u32 max_sessions, std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { | ||||
| 
 | ||||
|     SharedPtr<ServerPort> server_port(new ServerPort); | ||||
|     SharedPtr<ClientPort> client_port(new ClientPort); | ||||
| 
 | ||||
|     server_port->name = name + "_Server"; | ||||
|     server_port->hle_handler = hle_handler; | ||||
|     client_port->name = name + "_Client"; | ||||
|     client_port->server_port = server_port; | ||||
|     client_port->max_sessions = max_sessions; | ||||
|  |  | |||
|  | @ -9,6 +9,10 @@ | |||
| #include "common/common_types.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| 
 | ||||
| namespace Service { | ||||
| class SessionRequestHandler; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class ClientPort; | ||||
|  | @ -19,10 +23,13 @@ public: | |||
|      * Creates a pair of ServerPort and an associated ClientPort. | ||||
|      * @param max_sessions Maximum number of sessions to the port | ||||
|      * @param name Optional name of the ports | ||||
|      * @param hle_handler Optional HLE handler template for the port, | ||||
|      * ServerSessions crated from this port will inherit a reference to this handler. | ||||
|      * @return The created port tuple | ||||
|      */ | ||||
|     static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( | ||||
|         u32 max_sessions, std::string name = "UnknownPort"); | ||||
|         u32 max_sessions, std::string name = "UnknownPort", | ||||
|         std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ServerPort"; | ||||
|  | @ -41,6 +48,10 @@ public: | |||
|     std::vector<SharedPtr<WaitObject>> | ||||
|         pending_sessions; ///< ServerSessions waiting to be accepted by the port
 | ||||
| 
 | ||||
|     /// This session's HLE request handler template (optional)
 | ||||
|     /// ServerSessions created from this port inherit a reference to this handler.
 | ||||
|     std::shared_ptr<Service::SessionRequestHandler> hle_handler; | ||||
| 
 | ||||
|     bool ShouldWait() override; | ||||
|     void Acquire() override; | ||||
| 
 | ||||
|  |  | |||
|  | @ -47,10 +47,10 @@ ResultCode ServerSession::HandleSyncRequest() { | |||
| } | ||||
| 
 | ||||
| std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>> ServerSession::CreateSessionPair(const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { | ||||
|     auto server_session = ServerSession::Create(name + "Server", hle_handler).MoveFrom(); | ||||
|     auto client_session = ClientSession::Create(server_session, name + "Client").MoveFrom(); | ||||
|     auto server_session = ServerSession::Create(name + "_Server", hle_handler).MoveFrom(); | ||||
|     auto client_session = ClientSession::Create(server_session, name + "_Client").MoveFrom(); | ||||
| 
 | ||||
|     return std::make_tuple(server_session, client_session); | ||||
|     return std::make_tuple(std::move(server_session), std::move(client_session)); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -29,20 +29,8 @@ class ClientSession; | |||
|  * the request, the response is marshalled back to the caller's TLS buffer and control is | ||||
|  * transferred back to it. | ||||
|  */ | ||||
| class ServerSession : public WaitObject { | ||||
| class ServerSession final : public WaitObject { | ||||
| public: | ||||
|     ServerSession(); | ||||
|     ~ServerSession() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a server session. The server session can have an optional HLE handler, | ||||
|      * which will be invoked to handle the IPC requests that this session receives. | ||||
|      * @param name Optional name of the server session. | ||||
|      * @param hle_handler Optional HLE handler for this server session. | ||||
|      * @return The created server session | ||||
|      */ | ||||
|     static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown", std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||||
| 
 | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ServerSession"; | ||||
|     } | ||||
|  | @ -61,10 +49,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(); | ||||
|     ResultCode HandleSyncRequest(); | ||||
| 
 | ||||
|     bool ShouldWait() override; | ||||
| 
 | ||||
|  | @ -73,5 +60,18 @@ public: | |||
|     std::string name; ///< The name of this session (optional)
 | ||||
|     bool signaled;    ///< Whether there's new data available to this ServerSession
 | ||||
|     std::shared_ptr<Service::SessionRequestHandler> hle_handler; ///< This session's HLE request handler (optional)
 | ||||
| 
 | ||||
| private: | ||||
|     ServerSession(); | ||||
|     ~ServerSession() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a server session. The server session can have an optional HLE handler, | ||||
|      * which will be invoked to handle the IPC requests that this session receives. | ||||
|      * @param name Optional name of the server session. | ||||
|      * @param hle_handler Optional HLE handler for this server session. | ||||
|      * @return The created server session | ||||
|      */ | ||||
|     static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown", std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||||
| }; | ||||
| } | ||||
|  |  | |||
|  | @ -44,8 +44,8 @@ | |||
| 
 | ||||
| namespace Service { | ||||
| 
 | ||||
| std::unordered_map<std::string, std::tuple<Kernel::SharedPtr<Kernel::ClientPort>, std::shared_ptr<Interface>>> g_kernel_named_ports; | ||||
| std::unordered_map<std::string, std::tuple<Kernel::SharedPtr<Kernel::ClientPort>, std::shared_ptr<Interface>>> g_srv_services; | ||||
| std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | ||||
| std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a function string for logging, complete with the name (or header code, depending | ||||
|  | @ -102,15 +102,17 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { | |||
| // Module interface
 | ||||
| 
 | ||||
| static void AddNamedPort(Interface* interface_) { | ||||
|     auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); | ||||
|     auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | ||||
|                                                     std::shared_ptr<Interface>(interface_)); | ||||
|     auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | ||||
|     g_kernel_named_ports.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr<Interface>(interface_))); | ||||
|     g_kernel_named_ports.emplace(interface_->GetPortName(), client_port); | ||||
| } | ||||
| 
 | ||||
| void AddService(Interface* interface_) { | ||||
|     auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName()); | ||||
|     auto ports = Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | ||||
|                                                     std::shared_ptr<Interface>(interface_)); | ||||
|     auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | ||||
|     g_srv_services.emplace(interface_->GetPortName(), std::make_tuple(client_port, std::shared_ptr<Interface>(interface_))); | ||||
|     g_srv_services.emplace(interface_->GetPortName(), client_port); | ||||
| } | ||||
| 
 | ||||
| /// Initialize ServiceManager
 | ||||
|  |  | |||
|  | @ -176,7 +176,11 @@ namespace Service { | |||
| static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
 | ||||
| static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE port
 | ||||
| 
 | ||||
| /// TODO(Subv): Write documentation for this class
 | ||||
| /**
 | ||||
|  * Interface implemented by HLE Session handlers. | ||||
|  * This can be provided to a ServerSession in order to hook into several relevant events (such as a new connection or a SyncRequest) | ||||
|  * so they can be implemented in the emulator. | ||||
|  */ | ||||
| class SessionRequestHandler { | ||||
| public: | ||||
|     /**
 | ||||
|  | @ -190,7 +194,9 @@ public: | |||
|     virtual ResultCode HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; | ||||
| }; | ||||
| 
 | ||||
| /// Interface to a CTROS service
 | ||||
| /**
 | ||||
|  * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a table mapping header ids to handler functions. | ||||
|  */ | ||||
| class Interface : public SessionRequestHandler { | ||||
| public: | ||||
|     std::string GetName() const { | ||||
|  | @ -257,9 +263,9 @@ void Init(); | |||
| void Shutdown(); | ||||
| 
 | ||||
| /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
 | ||||
| extern std::unordered_map<std::string, std::tuple<Kernel::SharedPtr<Kernel::ClientPort>, std::shared_ptr<Interface>>> g_kernel_named_ports; | ||||
| extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; | ||||
| /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
 | ||||
| extern std::unordered_map<std::string, std::tuple<Kernel::SharedPtr<Kernel::ClientPort>, std::shared_ptr<Interface>>> g_srv_services; | ||||
| extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; | ||||
| 
 | ||||
| /// Adds a service to the services table
 | ||||
| void AddService(Interface* interface_); | ||||
|  |  | |||
|  | @ -85,21 +85,13 @@ static void GetServiceHandle(Service::Interface* self) { | |||
|     auto it = Service::g_srv_services.find(port_name); | ||||
| 
 | ||||
|     if (it != Service::g_srv_services.end()) { | ||||
|         auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); | ||||
|         // The hle_handler will be nullptr if this port was registered by the emulated
 | ||||
|         // application by means of srv:RegisterService.
 | ||||
|         auto hle_handler = std::get<std::shared_ptr<Service::Interface>>(it->second); | ||||
| 
 | ||||
|         // Create a new session pair
 | ||||
|         auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); | ||||
|         auto client_session = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); | ||||
|         auto server_session = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); | ||||
|         auto client_port = it->second; | ||||
| 
 | ||||
|         // Note: Threads do not wait for the server endpoint to call
 | ||||
|         // AcceptSession before returning from this call.
 | ||||
| 
 | ||||
|         // Add the server session to the port's queue
 | ||||
|         client_port->AddWaitingSession(server_session); | ||||
|         // Connect to the port and retrieve the client endpoint of the connection Session.
 | ||||
|         auto client_session = client_port->Connect(); | ||||
| 
 | ||||
|         // Return the client session
 | ||||
|         cmd_buff[3] = Kernel::g_handle_table.Create(client_session).MoveFrom(); | ||||
|  |  | |||
|  | @ -224,18 +224,10 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { | |||
|         return ERR_NOT_FOUND; | ||||
|     } | ||||
| 
 | ||||
|     auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); | ||||
|     // The hle_handler will be nullptr if this port was registered by the emulated
 | ||||
|     // application by means of svcCreatePort with a defined name.
 | ||||
|     auto hle_handler = std::get<std::shared_ptr<Service::Interface>>(it->second); | ||||
|     auto client_port = it->second; | ||||
| 
 | ||||
|     // Create a new session pair
 | ||||
|     auto sessions = Kernel::ServerSession::CreateSessionPair(port_name, hle_handler); | ||||
|     auto client_session = std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); | ||||
|     auto server_session = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); | ||||
| 
 | ||||
|     // Add the server session to the port's queue
 | ||||
|     client_port->AddWaitingSession(server_session); | ||||
|     // Connect to the port and retrieve the client endpoint of the connection Session.
 | ||||
|     auto client_session = client_port->Connect(); | ||||
| 
 | ||||
|     // Note: Threads do not wait for the server endpoint to call
 | ||||
|     // AcceptSession before returning from this call.
 | ||||
|  | @ -254,8 +246,8 @@ static ResultCode SendSyncRequest(Handle handle) { | |||
| 
 | ||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); | ||||
| 
 | ||||
|     // TODO(Subv): Wait the current thread and reschedule if this request is not going to be handled by HLE code.
 | ||||
|     return session->HandleSyncRequest(); | ||||
|     // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server responds and cause a reschedule.
 | ||||
|     return session->SendSyncRequest(); | ||||
| } | ||||
| 
 | ||||
| /// Close a handle
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue