Explorar o código

hle: kernel: Move ServiceThread ownership to KernelCore.

- Fixes a circular dependency which prevented threads from being released on shutdown.
bunnei %!s(int64=5) %!d(string=hai) anos
pai
achega
dfdac7d38a

+ 20 - 1
src/core/hle/kernel/kernel.cpp

@@ -8,7 +8,7 @@
 #include <functional>
 #include <functional>
 #include <memory>
 #include <memory>
 #include <thread>
 #include <thread>
-#include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <utility>
 
 
 #include "common/assert.h"
 #include "common/assert.h"
@@ -35,6 +35,7 @@
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/service_thread.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/synchronization.h"
 #include "core/hle/kernel/synchronization.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/thread.h"
@@ -107,6 +108,9 @@ struct KernelCore::Impl {
         std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
         std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
                   std::thread::id{});
                   std::thread::id{});
         std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
         std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
+
+        // Ensures all service threads gracefully shutdown
+        service_threads.clear();
     }
     }
 
 
     void InitializePhysicalCores() {
     void InitializePhysicalCores() {
@@ -345,6 +349,9 @@ struct KernelCore::Impl {
     std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
     std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
     std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
     std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
 
 
+    // Threads used for services
+    std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
+
     std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
     std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -639,4 +646,16 @@ void KernelCore::ExitSVCProfile() {
     MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
     MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
 }
 }
 
 
+std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
+    auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
+    impl->service_threads.emplace(service_thread);
+    return service_thread;
+}
+
+void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
+    if (auto strong_ptr = service_thread.lock()) {
+        impl->service_threads.erase(strong_ptr);
+    }
+}
+
 } // namespace Kernel
 } // namespace Kernel

+ 17 - 0
src/core/hle/kernel/kernel.h

@@ -42,6 +42,7 @@ class Process;
 class ResourceLimit;
 class ResourceLimit;
 class KScheduler;
 class KScheduler;
 class SharedMemory;
 class SharedMemory;
+class ServiceThread;
 class Synchronization;
 class Synchronization;
 class Thread;
 class Thread;
 class TimeManager;
 class TimeManager;
@@ -227,6 +228,22 @@ public:
 
 
     void ExitSVCProfile();
     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.
+     * @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);
+
+    /**
+     * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
+     * the ServerSession associated with the thread is destroyed.
+     * @param service_thread Service thread to release.
+     */
+    void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
+
 private:
 private:
     friend class Object;
     friend class Object;
     friend class Process;
     friend class Process;

+ 10 - 3
src/core/hle/kernel/server_session.cpp

@@ -25,7 +25,10 @@
 namespace Kernel {
 namespace Kernel {
 
 
 ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
 ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
-ServerSession::~ServerSession() = default;
+
+ServerSession::~ServerSession() {
+    kernel.ReleaseServiceThread(service_thread);
+}
 
 
 ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
 ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
                                                                 std::shared_ptr<Session> parent,
                                                                 std::shared_ptr<Session> parent,
@@ -34,7 +37,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
 
 
     session->name = std::move(name);
     session->name = std::move(name);
     session->parent = std::move(parent);
     session->parent = std::move(parent);
-    session->service_thread = std::make_unique<ServiceThread>(kernel, 1, session->name);
+    session->service_thread = kernel.CreateServiceThread(session->name);
 
 
     return MakeResult(std::move(session));
     return MakeResult(std::move(session));
 }
 }
@@ -139,7 +142,11 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
         std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
         std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
 
 
     context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
     context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
-    service_thread->QueueSyncRequest(*this, std::move(context));
+
+    if (auto strong_ptr = service_thread.lock()) {
+        strong_ptr->QueueSyncRequest(*this, std::move(context));
+        return RESULT_SUCCESS;
+    }
 
 
     return RESULT_SUCCESS;
     return RESULT_SUCCESS;
 }
 }

+ 1 - 1
src/core/hle/kernel/server_session.h

@@ -167,7 +167,7 @@ private:
     std::string name;
     std::string name;
 
 
     /// Thread to dispatch service requests
     /// Thread to dispatch service requests
-    std::unique_ptr<ServiceThread> service_thread;
+    std::weak_ptr<ServiceThread> service_thread;
 };
 };
 
 
 } // namespace Kernel
 } // namespace Kernel