core: Support session close with multicore.

This commit is contained in:
bunnei 2018-05-03 00:16:12 -04:00
parent a434fdcb10
commit cba69fdcd4
4 changed files with 48 additions and 17 deletions

View file

@ -37,6 +37,9 @@ static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) {
System::ResultStatus System::RunLoop(bool tight_loop) { System::ResultStatus System::RunLoop(bool tight_loop) {
status = ResultStatus::Success; 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()) { if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket(); GDBStub::HandlePacket();
@ -186,17 +189,21 @@ void System::Shutdown() {
gpu_core.reset(); gpu_core.reset();
// Close all CPU/threading state // Close all CPU/threading state
thread_to_cpu.clear(); cpu_barrier->NotifyEnd();
for (auto& cpu_core : cpu_cores) {
cpu_core.reset();
}
for (auto& thread : cpu_core_threads) { for (auto& thread : cpu_core_threads) {
thread->join(); thread->join();
thread.reset(); thread.reset();
} }
thread_to_cpu.clear();
for (auto& cpu_core : cpu_cores) {
cpu_core.reset();
}
cpu_barrier.reset();
// Close core timing
CoreTiming::Shutdown(); CoreTiming::Shutdown();
// Close app loader
app_loader.reset(); app_loader.reset();
NGLOG_DEBUG(Core, "Shutdown OK"); NGLOG_DEBUG(Core, "Shutdown OK");

View file

@ -92,7 +92,7 @@ public:
* @returns True if the emulated system is powered on, otherwise false. * @returns True if the emulated system is powered on, otherwise false.
*/ */
bool IsPoweredOn() const { bool IsPoweredOn() const {
return cpu_cores[0] != nullptr; return cpu_barrier && cpu_barrier->IsAlive();
} }
/** /**

View file

@ -19,6 +19,30 @@
namespace Core { 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::Cpu(std::shared_ptr<CpuBarrier> cpu_barrier, size_t core_index)
: cpu_barrier{std::move(cpu_barrier)}, core_index{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) { void Cpu::RunLoop(bool tight_loop) {
// Wait for all other CPU cores to complete the previous slice, such that they run in lock-step // 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, // 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 // instead advance to the next event and try to yield to the next thread

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <atomic>
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@ -22,23 +23,19 @@ constexpr unsigned NUM_CPU_CORES{4};
class CpuBarrier { class CpuBarrier {
public: public:
void Rendezvous() { bool IsAlive() const {
std::unique_lock<std::mutex> lock(mutex); return !end;
--cores_waiting;
if (!cores_waiting) {
cores_waiting = NUM_CPU_CORES;
condition.notify_all();
return;
}
condition.wait(lock);
} }
void NotifyEnd();
bool Rendezvous();
private: private:
unsigned cores_waiting{NUM_CPU_CORES}; unsigned cores_waiting{NUM_CPU_CORES};
std::mutex mutex; std::mutex mutex;
std::condition_variable condition; std::condition_variable condition;
std::atomic<bool> end{};
}; };
class Cpu { class Cpu {