From 864523327f9526fa65c92d383ce8536392c0b888 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 30 Mar 2022 21:11:11 -0700
Subject: [PATCH] hle: kernel: Create a default thread for services that do not
 need their own host thread.

---
 src/core/hle/kernel/kernel.cpp | 14 +++++++++++++-
 src/core/hle/kernel/kernel.h   | 16 +++++++++++++---
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 34da7c23b7..6387d0c297 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
         global_handle_table->Initialize(KHandleTable::MaxTableSize);
+        default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
 
         is_phantom_mode_for_singlecore = false;
 
@@ -677,6 +678,12 @@ struct KernelCore::Impl {
 
     void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
         if (auto strong_ptr = service_thread.lock()) {
+            if (strong_ptr == default_service_thread.lock()) {
+                // Nothing to do here, the service is using default_service_thread, which will be
+                // released on shutdown.
+                return;
+            }
+
             service_threads_manager.QueueWork(
                 [this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
         }
@@ -739,7 +746,8 @@ struct KernelCore::Impl {
     std::unique_ptr<KMemoryLayout> memory_layout;
 
     // Threads used for services
-    std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
+    std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
+    std::weak_ptr<ServiceThread> default_service_thread;
     Common::ThreadWorker service_threads_manager;
 
     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
@@ -1065,6 +1073,10 @@ std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::
     return impl->CreateServiceThread(*this, name);
 }
 
+std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
+    return impl->default_service_thread;
+}
+
 void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
     impl->ReleaseServiceThread(service_thread);
 }
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4c68e96dfc..24e26fa44a 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -271,15 +271,25 @@ public:
     void ExitSVCProfile();
 
     /**
-     * Creates an HLE service thread, which are used to execute service routines asynchronously.
-     * While these are allocated per ServerSession, these need to be owned and managed outside
-     * of ServerSession to avoid a circular dependency.
+     * Creates a host thread to execute HLE service requests, which are used to execute service
+     * routines asynchronously. While these are allocated per ServerSession, these need to be owned
+     * and managed outside of ServerSession to avoid a circular dependency. In general, most
+     * services can just use the default service thread, and not need their own host service thread.
+     * See GetDefaultServiceThread.
      * @param name String name for the ServerSession creating this thread, used for debug
      * purposes.
      * @returns The a weak pointer newly created service thread.
      */
     std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
 
+    /**
+     * Gets the default host service thread, which executes HLE service requests. Unless service
+     * requests need to block on the host, the default service thread should be used in favor of
+     * creating a new service thread.
+     * @returns The a weak pointer for the default service thread.
+     */
+    std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
+
     /**
      * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
      * the ServerSession associated with the thread is destroyed.