From ab9aae28bf5daa5fa7105bb4ef41b6d0b3c9cdc1 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sun, 8 Mar 2020 22:39:41 -0400
Subject: General: Initial Setup for Single Core.

---
 src/core/cpu_manager.cpp | 186 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 160 insertions(+), 26 deletions(-)

(limited to 'src/core/cpu_manager.cpp')

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 9a261968a7..e72f898083 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -26,9 +26,13 @@ void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
 
 void CpuManager::Initialize() {
     running_mode = true;
-    for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
-        core_data[core].host_thread =
-            std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
+    if (is_multicore) {
+        for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
+            core_data[core].host_thread =
+                std::make_unique<std::thread>(ThreadStart, std::ref(*this), core);
+        }
+    } else {
+        core_data[0].host_thread = std::make_unique<std::thread>(ThreadStart, std::ref(*this), 0);
     }
 }
 
@@ -41,52 +45,72 @@ void CpuManager::Shutdown() {
     }
 }
 
+std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
+    return std::function<void(void*)>(GuestThreadFunction);
+}
+
+std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
+    return std::function<void(void*)>(IdleThreadFunction);
+}
+
+std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
+    return std::function<void(void*)>(SuspendThreadFunction);
+}
+
 void CpuManager::GuestThreadFunction(void* cpu_manager_) {
     CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
-    cpu_manager->RunGuestThread();
+    if (cpu_manager->is_multicore) {
+        cpu_manager->MultiCoreRunGuestThread();
+    } else {
+        cpu_manager->SingleCoreRunGuestThread();
+    }
 }
 
 void CpuManager::GuestRewindFunction(void* cpu_manager_) {
     CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
-    cpu_manager->RunGuestLoop();
+    if (cpu_manager->is_multicore) {
+        cpu_manager->MultiCoreRunGuestLoop();
+    } else {
+        cpu_manager->SingleCoreRunGuestLoop();
+    }
 }
 
 void CpuManager::IdleThreadFunction(void* cpu_manager_) {
     CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
-    cpu_manager->RunIdleThread();
+    if (cpu_manager->is_multicore) {
+        cpu_manager->MultiCoreRunIdleThread();
+    } else {
+        cpu_manager->SingleCoreRunIdleThread();
+    }
 }
 
 void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
     CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
-    cpu_manager->RunSuspendThread();
-}
-
-std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
-    return std::function<void(void*)>(GuestThreadFunction);
-}
-
-std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
-    return std::function<void(void*)>(IdleThreadFunction);
-}
-
-std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
-    return std::function<void(void*)>(SuspendThreadFunction);
+    if (cpu_manager->is_multicore) {
+        cpu_manager->MultiCoreRunSuspendThread();
+    } else {
+        cpu_manager->SingleCoreRunSuspendThread();
+    }
 }
 
 void* CpuManager::GetStartFuncParamater() {
     return static_cast<void*>(this);
 }
 
-void CpuManager::RunGuestThread() {
+///////////////////////////////////////////////////////////////////////////////
+///                             MultiCore                                   ///
+///////////////////////////////////////////////////////////////////////////////
+
+void CpuManager::MultiCoreRunGuestThread() {
     auto& kernel = system.Kernel();
     {
         auto& sched = kernel.CurrentScheduler();
         sched.OnThreadStart();
     }
-    RunGuestLoop();
+    MultiCoreRunGuestLoop();
 }
 
-void CpuManager::RunGuestLoop() {
+void CpuManager::MultiCoreRunGuestLoop() {
     auto& kernel = system.Kernel();
     auto* thread = kernel.CurrentScheduler().GetCurrentThread();
     auto host_context = thread->GetHostContext();
@@ -103,7 +127,7 @@ void CpuManager::RunGuestLoop() {
     }
 }
 
-void CpuManager::RunIdleThread() {
+void CpuManager::MultiCoreRunIdleThread() {
     auto& kernel = system.Kernel();
     while (true) {
         auto& physical_core = kernel.CurrentPhysicalCore();
@@ -113,7 +137,7 @@ void CpuManager::RunIdleThread() {
     }
 }
 
-void CpuManager::RunSuspendThread() {
+void CpuManager::MultiCoreRunSuspendThread() {
     auto& kernel = system.Kernel();
     {
         auto& sched = kernel.CurrentScheduler();
@@ -130,7 +154,7 @@ void CpuManager::RunSuspendThread() {
     }
 }
 
-void CpuManager::Pause(bool paused) {
+void CpuManager::MultiCorePause(bool paused) {
     if (!paused) {
         bool all_not_barrier = false;
         while (!all_not_barrier) {
@@ -171,10 +195,120 @@ void CpuManager::Pause(bool paused) {
     paused_state = paused;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+///                             SingleCore                                   ///
+///////////////////////////////////////////////////////////////////////////////
+
+void CpuManager::SingleCoreRunGuestThread() {
+    auto& kernel = system.Kernel();
+    {
+        auto& sched = kernel.CurrentScheduler();
+        sched.OnThreadStart();
+    }
+    SingleCoreRunGuestLoop();
+}
+
+void CpuManager::SingleCoreRunGuestLoop() {
+    auto& kernel = system.Kernel();
+    auto* thread = kernel.CurrentScheduler().GetCurrentThread();
+    auto host_context = thread->GetHostContext();
+    host_context->SetRewindPoint(std::function<void(void*)>(GuestRewindFunction), this);
+    host_context.reset();
+    while (true) {
+        auto& physical_core = kernel.CurrentPhysicalCore();
+        while (!physical_core.IsInterrupted()) {
+            physical_core.Run();
+            preemption_count++;
+            if (preemption_count % max_cycle_runs == 0) {
+                break;
+            }
+        }
+        physical_core.ClearExclusive();
+        PreemptSingleCore();
+        auto& scheduler = physical_core.Scheduler();
+        scheduler.TryDoContextSwitch();
+    }
+}
+
+void CpuManager::SingleCoreRunIdleThread() {
+    auto& kernel = system.Kernel();
+    while (true) {
+        auto& physical_core = kernel.CurrentPhysicalCore();
+        PreemptSingleCore();
+        auto& scheduler = physical_core.Scheduler();
+        scheduler.TryDoContextSwitch();
+    }
+}
+
+void CpuManager::SingleCoreRunSuspendThread() {
+    auto& kernel = system.Kernel();
+    {
+        auto& sched = kernel.CurrentScheduler();
+        sched.OnThreadStart();
+    }
+    while (true) {
+        auto core = kernel.GetCurrentHostThreadID();
+        auto& scheduler = kernel.CurrentScheduler();
+        Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+        Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
+        ASSERT(scheduler.ContextSwitchPending());
+        ASSERT(core == kernel.GetCurrentHostThreadID());
+        scheduler.TryDoContextSwitch();
+    }
+}
+
+void CpuManager::PreemptSingleCore() {
+    preemption_count = 0;
+    std::size_t old_core = current_core;
+    current_core = (current_core + 1) % Core::Hardware::NUM_CPU_CORES;
+    auto& scheduler = system.Kernel().Scheduler(old_core);
+    Kernel::Thread* current_thread = system.Kernel().Scheduler(old_core).GetCurrentThread();
+    Kernel::Thread* next_thread = system.Kernel().Scheduler(current_core).GetCurrentThread();
+    Common::Fiber::YieldTo(current_thread->GetHostContext(), next_thread->GetHostContext());
+}
+
+void CpuManager::SingleCorePause(bool paused) {
+    if (!paused) {
+        bool all_not_barrier = false;
+        while (!all_not_barrier) {
+            all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load();
+        }
+        core_data[0].enter_barrier->Set();
+        if (paused_state.load()) {
+            bool all_barrier = false;
+            while (!all_barrier) {
+                all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
+            }
+            core_data[0].exit_barrier->Set();
+        }
+    } else {
+        /// Wait until all cores are paused.
+        bool all_barrier = false;
+        while (!all_barrier) {
+            all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
+        }
+        /// Don't release the barrier
+    }
+    paused_state = paused;
+}
+
+void CpuManager::Pause(bool paused) {
+    if (is_multicore) {
+        MultiCorePause(paused);
+    } else {
+        SingleCorePause(paused);
+    }
+}
+
 void CpuManager::RunThread(std::size_t core) {
     /// Initialization
     system.RegisterCoreThread(core);
-    std::string name = "yuzu:CoreHostThread_" + std::to_string(core);
+    std::string name;
+    if (is_multicore) {
+        name = "yuzu:CoreCPUThread_" + std::to_string(core);
+    } else {
+        name = "yuzu:CPUThread";
+    }
     MicroProfileOnThreadCreate(name.c_str());
     Common::SetCurrentThreadName(name.c_str());
     auto& data = core_data[core];
-- 
cgit v1.2.3-70-g09d2