core: Support session close with multicore.
This commit is contained in:
parent
a434fdcb10
commit
cba69fdcd4
|
@ -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");
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in New Issue