diff options
-rw-r--r-- | src/core/core.cpp | 15 | ||||
-rw-r--r-- | src/core/core.h | 2 | ||||
-rw-r--r-- | src/core/core_cpu.cpp | 29 | ||||
-rw-r--r-- | src/core/core_cpu.h | 17 |
4 files changed, 47 insertions, 16 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 066423f23..1e6be34c8 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -37,6 +37,9 @@ static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { System::ResultStatus System::RunLoop(bool tight_loop) { status = ResultStatus::Success; + // Update thread_to_cpu in case Core 0 is run from a different host thread + thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; + if (GDBStub::IsServerEnabled()) { GDBStub::HandlePacket(); @@ -186,17 +189,21 @@ void System::Shutdown() { gpu_core.reset(); // Close all CPU/threading state - thread_to_cpu.clear(); - for (auto& cpu_core : cpu_cores) { - cpu_core.reset(); - } + cpu_barrier->NotifyEnd(); for (auto& thread : cpu_core_threads) { thread->join(); thread.reset(); } + thread_to_cpu.clear(); + for (auto& cpu_core : cpu_cores) { + cpu_core.reset(); + } + cpu_barrier.reset(); + // Close core timing CoreTiming::Shutdown(); + // Close app loader app_loader.reset(); NGLOG_DEBUG(Core, "Shutdown OK"); diff --git a/src/core/core.h b/src/core/core.h index 3e0a7e6a7..561e7b48f 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -92,7 +92,7 @@ public: * @returns True if the emulated system is powered on, otherwise false. */ bool IsPoweredOn() const { - return cpu_cores[0] != nullptr; + return cpu_barrier && cpu_barrier->IsAlive(); } /** diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index a556f12e9..bd9869d28 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -19,6 +19,30 @@ namespace Core { +void CpuBarrier::NotifyEnd() { + std::unique_lock<std::mutex> lock(mutex); + end = true; + condition.notify_all(); +} + +bool CpuBarrier::Rendezvous() { + if (end) { + return false; + } else { + std::unique_lock<std::mutex> lock(mutex); + + --cores_waiting; + if (!cores_waiting) { + cores_waiting = NUM_CPU_CORES; + condition.notify_all(); + return true; + } + + condition.wait(lock); + return true; + } +} + Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index) : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} { @@ -38,7 +62,10 @@ Cpu::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index) void Cpu::RunLoop(bool tight_loop) { // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step - cpu_barrier->Rendezvous(); + if (!cpu_barrier->Rendezvous()) { + // If rendezvous failed, session has been killed + return; + } // If we don't have a currently active thread then don't execute instructions, // instead advance to the next event and try to yield to the next thread diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 06784c4ab..243f0b5e7 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -4,6 +4,7 @@ #pragma once +#include <atomic> #include <condition_variable> #include <memory> #include <mutex> @@ -22,23 +23,19 @@ constexpr unsigned NUM_CPU_CORES{4}; class CpuBarrier { public: - void Rendezvous() { - std::unique_lock<std::mutex> lock(mutex); + bool IsAlive() const { + return !end; + } - --cores_waiting; - if (!cores_waiting) { - cores_waiting = NUM_CPU_CORES; - condition.notify_all(); - return; - } + void NotifyEnd(); - condition.wait(lock); - } + bool Rendezvous(); private: unsigned cores_waiting{NUM_CPU_CORES}; std::mutex mutex; std::condition_variable condition; + std::atomic<bool> end{}; }; class Cpu { |