From a9a83fa726b43a28f4e5a40516efd56fbf99009f Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Mon, 11 Jul 2022 10:13:13 -0400
Subject: [PATCH] kernel: Ensure all uses of disable_count are balanced

---
 src/core/hle/kernel/k_scheduler.cpp | 21 +++++++++++++--------
 src/core/hle/kernel/k_scheduler.h   |  2 ++
 src/core/hle/kernel/k_thread.cpp    |  8 ++++++--
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d9ba8e4092..c34ce7a178 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -63,14 +63,8 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
     auto* scheduler{kernel.CurrentScheduler()};
 
     if (!scheduler || kernel.IsPhantomModeForSingleCore()) {
-        // HACK: we cannot schedule from this thread, it is not a core thread
-        RescheduleCores(kernel, cores_needing_scheduling);
-        if (GetCurrentThread(kernel).GetDisableDispatchCount() == 1) {
-            // Special case to ensure dummy threads that are waiting block
-            GetCurrentThread(kernel).IfDummyThreadTryWait();
-        }
-        GetCurrentThread(kernel).EnableDispatch();
-        ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting);
+        KScheduler::RescheduleCores(kernel, cores_needing_scheduling);
+        KScheduler::RescheduleCurrentHLEThread(kernel);
         return;
     }
 
@@ -83,6 +77,17 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
     }
 }
 
+void KScheduler::RescheduleCurrentHLEThread(KernelCore& kernel) {
+    // HACK: we cannot schedule from this thread, it is not a core thread
+    ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
+
+    // Special case to ensure dummy threads that are waiting block
+    GetCurrentThread(kernel).IfDummyThreadTryWait();
+
+    ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting);
+    GetCurrentThread(kernel).EnableDispatch();
+}
+
 u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
     if (IsSchedulerUpdateNeeded(kernel)) {
         return UpdateHighestPriorityThreadsImpl(kernel);
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index ac7421c9a9..534321d8d5 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -119,6 +119,8 @@ private:
     }
     static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel);
 
+    static void RescheduleCurrentHLEThread(KernelCore& kernel);
+
     // Instanced private API.
     void ScheduleImpl();
     void ScheduleImplFiber();
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 985ce448e6..174afc80d7 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -1106,6 +1106,8 @@ void KThread::IfDummyThreadTryWait() {
         return;
     }
 
+    ASSERT(!kernel.IsPhantomModeForSingleCore());
+
     // Block until we are no longer waiting.
     std::unique_lock lk(dummy_wait_lock);
     dummy_wait_cv.wait(
@@ -1211,10 +1213,12 @@ KScopedDisableDispatch::~KScopedDisableDispatch() {
     }
 
     if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) {
-        auto scheduler = kernel.CurrentScheduler();
+        auto* scheduler = kernel.CurrentScheduler();
 
-        if (scheduler) {
+        if (scheduler && !kernel.IsPhantomModeForSingleCore()) {
             scheduler->RescheduleCurrentCore();
+        } else {
+            KScheduler::RescheduleCurrentHLEThread(kernel);
         }
     } else {
         GetCurrentThread(kernel).EnableDispatch();