From a493ab2678078ce2066e8120ec93c0f6b4274df6 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Mon, 7 Jun 2021 21:10:51 -0700
Subject: [PATCH] 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/hle_ipc.h            |  6 +++---
 src/core/hle/kernel/k_server_session.cpp |  2 +-
 src/core/hle/kernel/kernel.cpp           | 18 ++++--------------
 3 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 2aaf93fca4..159565203c 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -85,8 +85,8 @@ public:
      */
     void ClientDisconnected(KServerSession* session);
 
-    std::shared_ptr<ServiceThread> GetServiceThread() const {
-        return service_thread.lock();
+    std::weak_ptr<ServiceThread> GetServiceThread() const {
+        return service_thread;
     }
 
 protected:
@@ -152,7 +152,7 @@ public:
         session_handler = std::move(handler);
     }
 
-    std::shared_ptr<ServiceThread> GetServiceThread() const {
+    std::weak_ptr<ServiceThread> GetServiceThread() const {
         return session_handler->GetServiceThread();
     }
 
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 528ca86146..61213c20e0 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 {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0ffb78d51d..2ceeaeb5fb 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -63,8 +63,6 @@ struct KernelCore::Impl {
         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
 
-        service_thread_manager =
-            std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
         is_phantom_mode_for_singlecore = false;
 
         InitializePhysicalCores();
@@ -96,7 +94,6 @@ struct KernelCore::Impl {
         process_list.clear();
 
         // Ensures all service threads gracefully shutdown
-        service_thread_manager.reset();
         service_threads.clear();
 
         next_object_id = 0;
@@ -680,10 +677,6 @@ struct KernelCore::Impl {
     // Threads used for services
     std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
 
-    // Service threads are managed by a worker thread, so that a calling service thread can queue up
-    // the release of itself
-    std::unique_ptr<Common::ThreadWorker> service_thread_manager;
-
     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -986,17 +979,14 @@ void KernelCore::ExitSVCProfile() {
 
 std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
     auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
-    impl->service_thread_manager->QueueWork(
-        [this, service_thread] { impl->service_threads.emplace(service_thread); });
+    impl->service_threads.emplace(service_thread);
     return service_thread;
 }
 
 void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
-    impl->service_thread_manager->QueueWork([this, service_thread] {
-        if (auto strong_ptr = service_thread.lock()) {
-            impl->service_threads.erase(strong_ptr);
-        }
-    });
+    if (auto strong_ptr = service_thread.lock()) {
+        impl->service_threads.erase(strong_ptr);
+    }
 }
 
 Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {