From 24d7aaf43c6b243f7123401545527ed7a25a3f26 Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Sat, 18 Jun 2022 16:54:33 -0400
Subject: [PATCH] kernel: wait for threads to stop on pause

---
 src/core/hle/kernel/k_thread.cpp | 13 +++++++++++++
 src/core/hle/kernel/k_thread.h   |  2 ++
 src/core/hle/kernel/kernel.cpp   |  7 +++++++
 3 files changed, 22 insertions(+)

diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 8d48a79014..b8aed18b18 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -748,6 +748,19 @@ void KThread::Continue() {
     KScheduler::OnThreadStateChanged(kernel, this, old_state);
 }
 
+void KThread::WaitUntilSuspended() {
+    // Make sure we have a suspend requested.
+    ASSERT(IsSuspendRequested());
+
+    // Loop until the thread is not executing on any core.
+    for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
+        KThread* core_thread{};
+        do {
+            core_thread = kernel.Scheduler(i).GetCurrentThread();
+        } while (core_thread == this);
+    }
+}
+
 ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
     // Lock ourselves.
     KScopedLightLock lk(activity_pause_lock);
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index f4d83f99a4..8c1f8a3447 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -207,6 +207,8 @@ public:
 
     void Continue();
 
+    void WaitUntilSuspended();
+
     constexpr void SetSyncedIndex(s32 index) {
         synced_index = index;
     }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 73593c7a0d..7d9267ddc6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1079,6 +1079,13 @@ void KernelCore::Suspend(bool suspended) {
 
     for (auto* process : GetProcessList()) {
         process->SetActivity(activity);
+
+        if (should_suspend) {
+            // Wait for execution to stop
+            for (auto* thread : process->GetThreadList()) {
+                thread->WaitUntilSuspended();
+            }
+        }
     }
 }