From f2ade343e2492c213ac93680a55e9bed712dac9a Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Thu, 19 Mar 2020 13:09:32 -0400
Subject: [PATCH] SingleCore: Move Host Timing from a sepparate thread to main
 cpu thread.

---
 src/core/core.cpp              |  2 ++
 src/core/core_timing.cpp       | 20 +++++++++++++-------
 src/core/core_timing.h         |  7 +++++++
 src/core/cpu_manager.cpp       | 17 +++++++++++++++--
 src/core/cpu_manager.h         |  1 +
 src/core/hle/kernel/kernel.cpp |  2 +-
 src/core/hle/kernel/thread.h   |  9 +++++++++
 7 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0f0eb885ad..2ca9c0be54 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -158,6 +158,8 @@ struct System::Impl {
         kernel.SetMulticore(is_multicore);
         cpu_manager.SetMulticore(is_multicore);
         cpu_manager.SetAsyncGpu(is_async_gpu);
+        core_timing.SetMulticore(is_multicore);
+        cpu_manager.SetRenderWindow(emu_window);
 
         core_timing.Initialize([&system]() { system.RegisterHostThread(); });
         kernel.Initialize();
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 3438f79cee..189d4aa34d 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -55,7 +55,9 @@ void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) {
     event_fifo_id = 0;
     const auto empty_timed_callback = [](u64, s64) {};
     ev_lost = CreateEvent("_lost_event", empty_timed_callback);
-    timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
+    if (is_multicore) {
+        timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
+    }
 }
 
 void CoreTiming::Shutdown() {
@@ -63,7 +65,9 @@ void CoreTiming::Shutdown() {
     shutting_down = true;
     pause_event.Set();
     event.Set();
-    timer_thread->join();
+    if (timer_thread) {
+        timer_thread->join();
+    }
     ClearPendingEvents();
     timer_thread.reset();
     has_started = false;
@@ -78,12 +82,14 @@ void CoreTiming::SyncPause(bool is_paused) {
         return;
     }
     Pause(is_paused);
-    if (!is_paused) {
-        pause_event.Set();
+    if (timer_thread) {
+        if (!is_paused) {
+            pause_event.Set();
+        }
+        event.Set();
+        while (paused_set != is_paused)
+            ;
     }
-    event.Set();
-    while (paused_set != is_paused)
-        ;
 }
 
 bool CoreTiming::IsRunning() const {
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 032eb08aad..03f9a5c764 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -67,6 +67,11 @@ public:
     /// Tears down all timing related functionality.
     void Shutdown();
 
+    /// Sets if emulation is multicore or single core, must be set before Initialize
+    void SetMulticore(bool is_multicore) {
+        this->is_multicore = is_multicore;
+    }
+
     /// Pauses/Unpauses the execution of the timer thread.
     void Pause(bool is_paused);
 
@@ -147,6 +152,8 @@ private:
     std::atomic<bool> has_started{};
     std::function<void(void)> on_thread_init{};
 
+    bool is_multicore{};
+
     std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{};
 };
 
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index d7bd162bc5..2aea95a257 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -242,8 +242,11 @@ void CpuManager::SingleCoreRunGuestLoop() {
                 break;
             }
         }
-        physical_core.ClearExclusive();
         system.ExitDynarmicProfile();
+        thread->SetPhantomMode(true);
+        system.CoreTiming().Advance();
+        thread->SetPhantomMode(false);
+        physical_core.ClearExclusive();
         PreemptSingleCore();
         auto& scheduler = kernel.Scheduler(current_core);
         scheduler.TryDoContextSwitch();
@@ -255,6 +258,7 @@ void CpuManager::SingleCoreRunIdleThread() {
     while (true) {
         auto& physical_core = kernel.CurrentPhysicalCore();
         PreemptSingleCore();
+        idle_count++;
         auto& scheduler = physical_core.Scheduler();
         scheduler.TryDoContextSwitch();
     }
@@ -280,15 +284,24 @@ void CpuManager::SingleCoreRunSuspendThread() {
 void CpuManager::PreemptSingleCore() {
     preemption_count = 0;
     std::size_t old_core = current_core;
-    current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
     auto& scheduler = system.Kernel().Scheduler(old_core);
     Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+    if (idle_count >= 4) {
+        current_thread->SetPhantomMode(true);
+        system.CoreTiming().Advance();
+        current_thread->SetPhantomMode(false);
+    }
+    current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
     scheduler.Unload();
     auto& next_scheduler = system.Kernel().Scheduler(current_core);
     Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
     /// May have changed scheduler
     auto& current_scheduler = system.Kernel().Scheduler(current_core);
     current_scheduler.Reload();
+    auto* currrent_thread2 = current_scheduler.GetCurrentThread();
+    if (!currrent_thread2->IsIdleThread()) {
+        idle_count = 0;
+    }
 }
 
 void CpuManager::SingleCorePause(bool paused) {
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index 37cef2b122..e6b8612f0e 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -104,6 +104,7 @@ private:
     bool is_multicore{};
     std::atomic<std::size_t> current_core{};
     std::size_t preemption_count{};
+    std::size_t idle_count{};
     static constexpr std::size_t max_cycle_runs = 5;
     Core::Frontend::EmuWindow* render_window;
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d2f5f9bf23..a19cd7a1ff 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -303,7 +303,7 @@ struct KernelCore::Impl {
         }
         const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler();
         const Kernel::Thread* current = sched.GetCurrentThread();
-        if (current != nullptr) {
+        if (current != nullptr && !current->IsPhantomMode()) {
             result.guest_handle = current->GetGlobalHandle();
         } else {
             result.guest_handle = InvalidHandle;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index f42d7bd136..f998890c4b 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -597,6 +597,14 @@ public:
         is_continuous_on_svc = is_continuous;
     }
 
+    bool IsPhantomMode() const {
+        return is_phantom_mode;
+    }
+
+    void SetPhantomMode(bool phantom) {
+        is_phantom_mode = phantom;
+    }
+
 private:
     friend class GlobalScheduler;
     friend class Scheduler;
@@ -699,6 +707,7 @@ private:
     bool is_continuous_on_svc = false;
 
     bool will_be_terminated = false;
+    bool is_phantom_mode = false;
 
     bool was_running = false;