From a493ab2678078ce2066e8120ec93c0f6b4274df6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 7 Jun 2021 21:10:51 -0700 Subject: hle: kernel: Remove service thread manager and use weak_ptr. - We no longer need to queue up service threads to be destroyed. - Fixes a race condition where a thread could be destroyed too early, which caused a crash in Pokemon Sword/Shield. --- src/core/hle/kernel/k_server_session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/k_server_session.cpp') diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 528ca8614..61213c20e 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -119,7 +119,7 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); - if (auto strong_ptr = manager->GetServiceThread(); strong_ptr) { + if (auto strong_ptr = manager->GetServiceThread().lock()) { strong_ptr->QueueSyncRequest(*parent, std::move(context)); return ResultSuccess; } else { -- cgit v1.2.3 From 08d798b6fe8b09f28c0302b52c3b832b786d1b8a Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 7 Jun 2021 21:55:37 -0700 Subject: hle: kernel: hle_ipc: Ensure SessionRequestHandler is valid. --- src/core/hle/kernel/k_server_session.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/k_server_session.cpp') diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 61213c20e..dd62706a8 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -119,11 +119,16 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); - if (auto strong_ptr = manager->GetServiceThread().lock()) { - strong_ptr->QueueSyncRequest(*parent, std::move(context)); - return ResultSuccess; + // Ensure we have a session request handler + if (manager->HasSessionRequestHandler(*context)) { + if (auto strong_ptr = manager->GetServiceThread().lock()) { + strong_ptr->QueueSyncRequest(*parent, std::move(context)); + return ResultSuccess; + } else { + ASSERT_MSG(false, "strong_ptr is nullptr!"); + } } else { - ASSERT_MSG(false, "strong_ptr was nullptr!"); + ASSERT_MSG(false, "handler is invalid!"); } return ResultSuccess; -- cgit v1.2.3 From b8fb9b3f112cb43831aeac8ab1242ae653989067 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 8 Jun 2021 13:39:20 -0700 Subject: hle: kernel: KServerSession: Work-around scenario where session is closed too early. --- src/core/hle/kernel/k_server_session.cpp | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel/k_server_session.cpp') diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index dd62706a8..5c3c13ce6 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -8,6 +8,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -119,11 +120,20 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); + // In the event that something fails here, stub a result to prevent the game from crashing. + // This is a work-around in the event that somehow we process a service request after the + // session has been closed by the game. This has been observed to happen rarely in Pokemon + // Sword/Shield and is likely a result of us using host threads/scheduling for services. + // TODO(bunnei): Find a better solution here. + auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); }); + // Ensure we have a session request handler if (manager->HasSessionRequestHandler(*context)) { if (auto strong_ptr = manager->GetServiceThread().lock()) { strong_ptr->QueueSyncRequest(*parent, std::move(context)); - return ResultSuccess; + + // We succeeded. + error_guard.Cancel(); } else { ASSERT_MSG(false, "strong_ptr is nullptr!"); } @@ -136,13 +146,20 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { ResultCode result = ResultSuccess; + // If the session has been converted to a domain, handle the domain request - if (IsDomain() && context.HasDomainMessageHeader()) { - result = HandleDomainSyncRequest(context); - // If there is no domain header, the regular session handler is used - } else if (manager->HasSessionHandler()) { - // If this ServerSession has an associated HLE handler, forward the request to it. - result = manager->SessionHandler().HandleSyncRequest(*this, context); + if (manager->HasSessionRequestHandler(context)) { + if (IsDomain() && context.HasDomainMessageHeader()) { + result = HandleDomainSyncRequest(context); + // If there is no domain header, the regular session handler is used + } else if (manager->HasSessionHandler()) { + // If this ServerSession has an associated HLE handler, forward the request to it. + result = manager->SessionHandler().HandleSyncRequest(*this, context); + } + } else { + ASSERT_MSG(false, "Session handler is invalid, stubbing response!"); + IPC::ResponseBuilder rb(context, 2); + rb.Push(ResultSuccess); } if (convert_to_domain) { -- cgit v1.2.3