From d49e29d86610afaa142d250fbd618f422e2780ec Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 31 Dec 2020 02:13:02 -0800
Subject: [PATCH] hle: kernel: Move single core "phantom mode" out of KThread.

- This is a workaround that does not belong in a kernel primitive.
---
 src/core/cpu_manager.cpp       | 13 +++++++------
 src/core/hle/kernel/k_thread.h |  9 ---------
 src/core/hle/kernel/kernel.cpp | 21 ++++++++++++++++++++-
 src/core/hle/kernel/kernel.h   |  4 ++++
 4 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 018cd2e253..7192582503 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -217,9 +217,9 @@ void CpuManager::SingleCoreRunGuestLoop() {
             physical_core = &kernel.CurrentPhysicalCore();
         }
         system.ExitDynarmicProfile();
-        thread->SetPhantomMode(true);
+        kernel.SetIsPhantomModeForSingleCore(true);
         system.CoreTiming().Advance();
-        thread->SetPhantomMode(false);
+        kernel.SetIsPhantomModeForSingleCore(false);
         physical_core->ArmInterface().ClearExclusiveState();
         PreemptSingleCore();
         auto& scheduler = kernel.Scheduler(current_core);
@@ -255,22 +255,23 @@ void CpuManager::SingleCoreRunSuspendThread() {
 
 void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     {
-        auto& scheduler = system.Kernel().Scheduler(current_core);
+        auto& kernel = system.Kernel();
+        auto& scheduler = kernel.Scheduler(current_core);
         Kernel::KThread* current_thread = scheduler.GetCurrentThread();
         if (idle_count >= 4 || from_running_enviroment) {
             if (!from_running_enviroment) {
                 system.CoreTiming().Idle();
                 idle_count = 0;
             }
-            current_thread->SetPhantomMode(true);
+            kernel.SetIsPhantomModeForSingleCore(true);
             system.CoreTiming().Advance();
-            current_thread->SetPhantomMode(false);
+            kernel.SetIsPhantomModeForSingleCore(false);
         }
         current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
         system.CoreTiming().ResetTicks();
         scheduler.Unload(scheduler.GetCurrentThread());
 
-        auto& next_scheduler = system.Kernel().Scheduler(current_core);
+        auto& next_scheduler = kernel.Scheduler(current_core);
         Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
     }
 
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index d9fe2e3638..7dec9449ea 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -451,14 +451,6 @@ public:
         is_continuous_on_svc = is_continuous;
     }
 
-    bool IsPhantomMode() const {
-        return is_phantom_mode;
-    }
-
-    void SetPhantomMode(bool phantom) {
-        is_phantom_mode = phantom;
-    }
-
     bool HasExited() const {
         return has_exited;
     }
@@ -747,7 +739,6 @@ private:
     bool is_continuous_on_svc = false;
 
     bool will_be_terminated = false;
-    bool is_phantom_mode = false;
     bool has_exited = false;
 
     bool was_running = false;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6ae0bdeede..80a78e643b 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -62,6 +62,7 @@ struct KernelCore::Impl {
         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         service_thread_manager =
             std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
+        is_phantom_mode_for_singlecore = false;
 
         InitializePhysicalCores();
         InitializeSystemResourceLimit(kernel);
@@ -227,6 +228,15 @@ struct KernelCore::Impl {
         return this_id;
     }
 
+    bool IsPhantomModeForSingleCore() const {
+        return is_phantom_mode_for_singlecore;
+    }
+
+    void SetIsPhantomModeForSingleCore(bool value) {
+        ASSERT(!is_multicore);
+        is_phantom_mode_for_singlecore = value;
+    }
+
     [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
         Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
         result.host_handle = GetCurrentHostThreadID();
@@ -235,7 +245,7 @@ struct KernelCore::Impl {
         }
         const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
         const Kernel::KThread* current = sched.GetCurrentThread();
-        if (current != nullptr && !current->IsPhantomMode()) {
+        if (current != nullptr && !IsPhantomModeForSingleCore()) {
             result.guest_handle = current->GetGlobalHandle();
         } else {
             result.guest_handle = InvalidHandle;
@@ -345,6 +355,7 @@ struct KernelCore::Impl {
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
 
     bool is_multicore{};
+    bool is_phantom_mode_for_singlecore{};
     u32 single_core_thread_id{};
 
     std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
@@ -643,4 +654,12 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
     });
 }
 
+bool KernelCore::IsPhantomModeForSingleCore() const {
+    return impl->IsPhantomModeForSingleCore();
+}
+
+void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
+    impl->SetIsPhantomModeForSingleCore(value);
+}
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 41c5535829..fc58f3ecb5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -237,6 +237,10 @@ public:
      */
     void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
 
+    /// Workaround for single-core mode when preempting threads while idle.
+    bool IsPhantomModeForSingleCore() const;
+    void SetIsPhantomModeForSingleCore(bool value);
+
 private:
     friend class Object;
     friend class Process;