mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #2406 from Subv/session_disconnect
Kernel: Properly update port counters on session disconnection.
This commit is contained in:
		
						commit
						cc566dadd8
					
				
					 8 changed files with 84 additions and 51 deletions
				
			
		|  | @ -239,6 +239,7 @@ set(HEADERS | ||||||
|             hle/kernel/semaphore.h |             hle/kernel/semaphore.h | ||||||
|             hle/kernel/server_port.h |             hle/kernel/server_port.h | ||||||
|             hle/kernel/server_session.h |             hle/kernel/server_session.h | ||||||
|  |             hle/kernel/session.h | ||||||
|             hle/kernel/shared_memory.h |             hle/kernel/shared_memory.h | ||||||
|             hle/kernel/thread.h |             hle/kernel/thread.h | ||||||
|             hle/kernel/timer.h |             hle/kernel/timer.h | ||||||
|  |  | ||||||
|  | @ -19,24 +19,21 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { | ||||||
|     // AcceptSession before returning from this call.
 |     // AcceptSession before returning from this call.
 | ||||||
| 
 | 
 | ||||||
|     if (active_sessions >= max_sessions) { |     if (active_sessions >= max_sessions) { | ||||||
|         // TODO(Subv): Return an error code in this situation after session disconnection is
 |         return ResultCode(ErrorDescription::MaxConnectionsReached, ErrorModule::OS, | ||||||
|         // implemented.
 |                           ErrorSummary::WouldBlock, ErrorLevel::Temporary); | ||||||
|         /*return ResultCode(ErrorDescription::MaxConnectionsReached,
 |  | ||||||
|                           ErrorModule::OS, ErrorSummary::WouldBlock, |  | ||||||
|                           ErrorLevel::Temporary);*/ |  | ||||||
|     } |     } | ||||||
|     active_sessions++; |     active_sessions++; | ||||||
| 
 | 
 | ||||||
|     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
 |     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
 | ||||||
|     auto sessions = |     auto sessions = | ||||||
|         ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); |         ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler, this); | ||||||
|     auto client_session = std::get<SharedPtr<ClientSession>>(sessions); |     auto client_session = std::get<SharedPtr<ClientSession>>(sessions); | ||||||
|     auto server_session = std::get<SharedPtr<ServerSession>>(sessions); |     auto server_session = std::get<SharedPtr<ServerSession>>(sessions); | ||||||
| 
 | 
 | ||||||
|     if (server_port->hle_handler) |     if (server_port->hle_handler) | ||||||
|         server_port->hle_handler->ClientConnected(server_session); |         server_port->hle_handler->ClientConnected(server_session); | ||||||
| 
 |     else | ||||||
|     server_port->pending_sessions.push_back(std::move(server_session)); |         server_port->pending_sessions.push_back(std::move(server_session)); | ||||||
| 
 | 
 | ||||||
|     // Wake the threads waiting on the ServerPort
 |     // Wake the threads waiting on the ServerPort
 | ||||||
|     server_port->WakeupAllWaitingThreads(); |     server_port->WakeupAllWaitingThreads(); | ||||||
|  |  | ||||||
|  | @ -14,27 +14,24 @@ ClientSession::~ClientSession() { | ||||||
|     // This destructor will be called automatically when the last ClientSession handle is closed by
 |     // This destructor will be called automatically when the last ClientSession handle is closed by
 | ||||||
|     // the emulated application.
 |     // the emulated application.
 | ||||||
| 
 | 
 | ||||||
|     if (server_session->hle_handler) |     if (parent->server) { | ||||||
|         server_session->hle_handler->ClientDisconnected(server_session); |         if (parent->server->hle_handler) | ||||||
|  |             parent->server->hle_handler->ClientDisconnected(parent->server); | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client),
 |         // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set
 | ||||||
|     // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to
 |         // their WaitSynchronization result to 0xC920181A.
 | ||||||
|     // 0xC920181A.
 |     } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session, |     parent->client = nullptr; | ||||||
|                                                           std::string name) { |  | ||||||
|     SharedPtr<ClientSession> client_session(new ClientSession); |  | ||||||
| 
 |  | ||||||
|     client_session->name = std::move(name); |  | ||||||
|     client_session->server_session = server_session; |  | ||||||
|     client_session->session_status = SessionStatus::Open; |  | ||||||
|     return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode ClientSession::SendSyncRequest() { | ResultCode ClientSession::SendSyncRequest() { | ||||||
|     // Signal the server session that new data is available
 |     // Signal the server session that new data is available
 | ||||||
|     return server_session->HandleSyncRequest(); |     if (parent->server) | ||||||
|  |         return parent->server->HandleSyncRequest(); | ||||||
|  | 
 | ||||||
|  |     return ResultCode(ErrorDescription::SessionClosedByRemote, ErrorModule::OS, | ||||||
|  |                       ErrorSummary::Canceled, ErrorLevel::Status); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -14,12 +14,7 @@ | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class ServerSession; | class ServerSession; | ||||||
| 
 | class Session; | ||||||
| enum class SessionStatus { |  | ||||||
|     Open = 1, |  | ||||||
|     ClosedByClient = 2, |  | ||||||
|     ClosedBYServer = 3, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| class ClientSession final : public Object { | class ClientSession final : public Object { | ||||||
| public: | public: | ||||||
|  | @ -44,22 +39,14 @@ public: | ||||||
|      */ |      */ | ||||||
|     ResultCode SendSyncRequest(); |     ResultCode SendSyncRequest(); | ||||||
| 
 | 
 | ||||||
|     std::string name;              ///< Name of client port (optional)
 |     std::string name; ///< Name of client port (optional)
 | ||||||
|     ServerSession* server_session; ///< The server session associated with this client session.
 | 
 | ||||||
|     SessionStatus session_status;  ///< The session's current status.
 |     /// The parent session, which links to the server endpoint.
 | ||||||
|  |     std::shared_ptr<Session> parent; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     ClientSession(); |     ClientSession(); | ||||||
|     ~ClientSession() override; |     ~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(ServerSession* server_session, |  | ||||||
|                                                       std::string name = "Unknown"); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -14,8 +14,15 @@ ServerSession::ServerSession() = default; | ||||||
| ServerSession::~ServerSession() { | ServerSession::~ServerSession() { | ||||||
|     // This destructor will be called automatically when the last ServerSession handle is closed by
 |     // This destructor will be called automatically when the last ServerSession handle is closed by
 | ||||||
|     // the emulated application.
 |     // the emulated application.
 | ||||||
|     // TODO(Subv): Reduce the ClientPort's connection count,
 | 
 | ||||||
|     // if the session is still open, set the connection status to 3 (Closed by server),
 |     // Decrease the port's connection count.
 | ||||||
|  |     if (parent->port) | ||||||
|  |         parent->port->active_sessions--; | ||||||
|  | 
 | ||||||
|  |     // TODO(Subv): Wake up all the ClientSession's waiting threads and set
 | ||||||
|  |     // the SendSyncRequest result to 0xC920181A.
 | ||||||
|  | 
 | ||||||
|  |     parent->server = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<SharedPtr<ServerSession>> ServerSession::Create( | ResultVal<SharedPtr<ServerSession>> ServerSession::Create( | ||||||
|  | @ -25,6 +32,7 @@ ResultVal<SharedPtr<ServerSession>> ServerSession::Create( | ||||||
|     server_session->name = std::move(name); |     server_session->name = std::move(name); | ||||||
|     server_session->signaled = false; |     server_session->signaled = false; | ||||||
|     server_session->hle_handler = std::move(hle_handler); |     server_session->hle_handler = std::move(hle_handler); | ||||||
|  |     server_session->parent = nullptr; | ||||||
| 
 | 
 | ||||||
|     return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); |     return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); | ||||||
| } | } | ||||||
|  | @ -61,13 +69,22 @@ ResultCode ServerSession::HandleSyncRequest() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ServerSession::SessionPair ServerSession::CreateSessionPair( | ServerSession::SessionPair ServerSession::CreateSessionPair( | ||||||
|     const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { |     const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler, | ||||||
|  |     SharedPtr<ClientPort> port) { | ||||||
|  | 
 | ||||||
|     auto server_session = |     auto server_session = | ||||||
|         ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); |         ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); | ||||||
|     // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want
 | 
 | ||||||
|     // to prevent the ServerSession's destructor from being called when the emulated
 |     SharedPtr<ClientSession> client_session(new ClientSession); | ||||||
|     // application closes the last ServerSession handle.
 |     client_session->name = name + "_Client"; | ||||||
|     auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom(); | 
 | ||||||
|  |     std::shared_ptr<Session> parent(new Session); | ||||||
|  |     parent->client = client_session.get(); | ||||||
|  |     parent->server = server_session.get(); | ||||||
|  |     parent->port = port; | ||||||
|  | 
 | ||||||
|  |     client_session->parent = parent; | ||||||
|  |     server_session->parent = parent; | ||||||
| 
 | 
 | ||||||
|     return std::make_tuple(std::move(server_session), std::move(client_session)); |     return std::make_tuple(std::move(server_session), std::move(client_session)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
|  | #include "core/hle/kernel/session.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
|  | @ -17,6 +18,8 @@ | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| class ClientSession; | class ClientSession; | ||||||
|  | class ClientPort; | ||||||
|  | class ServerSession; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS |  * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS | ||||||
|  | @ -47,11 +50,13 @@ public: | ||||||
|      * Creates a pair of ServerSession and an associated ClientSession. |      * Creates a pair of ServerSession and an associated ClientSession. | ||||||
|      * @param name        Optional name of the ports. |      * @param name        Optional name of the ports. | ||||||
|      * @param hle_handler Optional HLE handler for this server session. |      * @param hle_handler Optional HLE handler for this server session. | ||||||
|  |      * @param client_port Optional The ClientPort that spawned this session. | ||||||
|      * @return The created session tuple |      * @return The created session tuple | ||||||
|      */ |      */ | ||||||
|     static SessionPair CreateSessionPair( |     static SessionPair CreateSessionPair( | ||||||
|         const std::string& name = "Unknown", |         const std::string& name = "Unknown", | ||||||
|         std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); |         std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr, | ||||||
|  |         SharedPtr<ClientPort> client_port = nullptr); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Handle a sync request from the emulated application. |      * Handle a sync request from the emulated application. | ||||||
|  | @ -63,8 +68,9 @@ public: | ||||||
| 
 | 
 | ||||||
|     void Acquire(Thread* thread) override; |     void Acquire(Thread* thread) override; | ||||||
| 
 | 
 | ||||||
|     std::string name; ///< The name of this session (optional)
 |     std::string name;                ///< The name of this session (optional)
 | ||||||
|     bool signaled;    ///< Whether there's new data available to this ServerSession
 |     bool signaled;                   ///< Whether there's new data available to this ServerSession
 | ||||||
|  |     std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.
 | ||||||
|     std::shared_ptr<Service::SessionRequestHandler> |     std::shared_ptr<Service::SessionRequestHandler> | ||||||
|         hle_handler; ///< This session's HLE request handler (optional)
 |         hle_handler; ///< This session's HLE request handler (optional)
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								src/core/hle/kernel/session.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/core/hle/kernel/session.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
|  | 
 | ||||||
|  | namespace Kernel { | ||||||
|  | 
 | ||||||
|  | class ClientSession; | ||||||
|  | class ClientPort; | ||||||
|  | class ServerSession; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Parent structure to link the client and server endpoints of a session with their associated | ||||||
|  |  * client port. The client port need not exist, as is the case for portless sessions like the | ||||||
|  |  * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its | ||||||
|  |  * corresponding field in this structure will be set to nullptr. | ||||||
|  |  */ | ||||||
|  | class Session final { | ||||||
|  | public: | ||||||
|  |     ClientSession* client = nullptr; ///< The client endpoint of the session.
 | ||||||
|  |     ServerSession* server = nullptr; ///< The server endpoint of the session.
 | ||||||
|  |     SharedPtr<ClientPort> port;      ///< The port that this session is associated with (optional).
 | ||||||
|  | }; | ||||||
|  | } | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| /// Detailed description of the error. This listing is likely incomplete.
 | /// Detailed description of the error. This listing is likely incomplete.
 | ||||||
| enum class ErrorDescription : u32 { | enum class ErrorDescription : u32 { | ||||||
|     Success = 0, |     Success = 0, | ||||||
|  |     SessionClosedByRemote = 26, | ||||||
|     WrongPermission = 46, |     WrongPermission = 46, | ||||||
|     OS_InvalidBufferDescriptor = 48, |     OS_InvalidBufferDescriptor = 48, | ||||||
|     MaxConnectionsReached = 52, |     MaxConnectionsReached = 52, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue