From 06a2e0b5919ca1ece1fc63a62ccd817d90b4b3b3 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 6 Nov 2017 23:07:08 -0500 Subject: [PATCH] Kernel/Sessions: Wake up any threads waiting on a ServerSession when its client is closed The error code 0xC920181A will be returned by svcReplyAndReceive when the wakeup callback runs. This lets LLE services be properly notified of clients closing the connection so they can end their handler threads instead of letting them linger indefinitely, taking up connection slots in their parent port. --- src/core/hle/kernel/client_session.cpp | 10 +++++++--- src/core/hle/kernel/server_session.cpp | 7 ++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 646a5cc64..4780590e6 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -26,9 +26,6 @@ ClientSession::~ClientSession() { if (hle_handler) hle_handler->ClientDisconnected(server); - // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set - // their WaitSynchronization result to 0xC920181A. - // Clean up the list of client threads with pending requests, they are unneeded now that the // client endpoint is closed. server->pending_requesting_threads.clear(); @@ -36,6 +33,13 @@ ClientSession::~ClientSession() { } parent->client = nullptr; + + if (server) { + // Notify any threads waiting on the ServerSession that the endpoint has been closed. Note + // that this call has to happen after `Session::client` has been set to nullptr to let the + // ServerSession know that the client endpoint has been closed. + server->WakeupAllWaitingThreads(); + } } ResultCode ClientSession::SendSyncRequest(SharedPtr thread) { diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index bf2e9e376..6ceb67c55 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -47,8 +47,13 @@ bool ServerSession::ShouldWait(Thread* thread) const { void ServerSession::Acquire(Thread* thread) { ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); + + // If the client endpoint was closed, don't do anything. This ServerSession is now useless and + // will linger until its last handle is closed by the running application. + if (parent->client == nullptr) + return; + // We are now handling a request, pop it from the stack. - // TODO(Subv): What happens if the client endpoint is closed before any requests are made? ASSERT(!pending_requesting_threads.empty()); currently_handling = pending_requesting_threads.back(); pending_requesting_threads.pop_back();