From 2d90a927c9f7652aa7e259ba57fa22ddbf8bed24 Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Sun, 23 Oct 2022 05:45:45 -0400
Subject: [PATCH] core: barrier service thread shutdown

---
 src/core/core.cpp                            |  1 +
 src/core/hle/kernel/kernel.cpp               | 12 +++++++++---
 src/core/hle/service/nvflinger/nvflinger.cpp | 12 ++++++++----
 src/core/hle/service/nvflinger/nvflinger.h   |  2 ++
 src/core/hle/service/service.cpp             |  4 ++++
 src/core/hle/service/service.h               |  2 ++
 6 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 7fb8bc019..40a610435 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -384,6 +384,7 @@ struct System::Impl {
         kernel.ShutdownCores();
         cpu_manager.Shutdown();
         debugger.reset();
+        services->KillNVNFlinger();
         kernel.CloseServices();
         services.reset();
         service_manager.reset();
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index eed2dc9f3..fdc774e30 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -48,8 +48,8 @@ namespace Kernel {
 
 struct KernelCore::Impl {
     explicit Impl(Core::System& system_, KernelCore& kernel_)
-        : time_manager{system_},
-          service_threads_manager{1, "ServiceThreadsManager"}, system{system_} {}
+        : time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"},
+          service_thread_barrier{2}, system{system_} {}
 
     void SetMulticore(bool is_multi) {
         is_multicore = is_multi;
@@ -737,7 +737,12 @@ struct KernelCore::Impl {
     }
 
     void ClearServiceThreads() {
-        service_threads_manager.QueueWork([this]() { service_threads.clear(); });
+        service_threads_manager.QueueWork([this] {
+            service_threads.clear();
+            default_service_thread.reset();
+            service_thread_barrier.Sync();
+        });
+        service_thread_barrier.Sync();
     }
 
     std::mutex server_objects_lock;
@@ -802,6 +807,7 @@ struct KernelCore::Impl {
     std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
     std::weak_ptr<ServiceThread> default_service_thread;
     Common::ThreadWorker service_threads_manager;
+    Common::Barrier service_thread_barrier;
 
     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index aa14d2cbc..dad93b38e 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -102,15 +102,19 @@ NVFlinger::~NVFlinger() {
         system.CoreTiming().UnscheduleEvent(single_composition_event, {});
     }
 
+    ShutdownLayers();
+
+    if (nvdrv) {
+        nvdrv->Close(disp_fd);
+    }
+}
+
+void NVFlinger::ShutdownLayers() {
     for (auto& display : displays) {
         for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
             display.GetLayer(layer).Core().NotifyShutdown();
         }
     }
-
-    if (nvdrv) {
-        nvdrv->Close(disp_fd);
-    }
 }
 
 void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 99509bc5b..b8191c595 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -48,6 +48,8 @@ public:
     explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
     ~NVFlinger();
 
+    void ShutdownLayers();
+
     /// Sets the NVDrv module instance to use to send buffers to the GPU.
     void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
 
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index dadaf897f..5db6588e4 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -303,4 +303,8 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
 
 Services::~Services() = default;
 
+void Services::KillNVNFlinger() {
+    nv_flinger->ShutdownLayers();
+}
+
 } // namespace Service
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 5bf197c51..ec9deeee4 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -238,6 +238,8 @@ public:
     explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
     ~Services();
 
+    void KillNVNFlinger();
+
 private:
     std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
     std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;