Merge pull request #9398 from liamwhite/fail
general: improve handling of system startup failure
This commit is contained in:
commit
339a37f8cb
|
@ -11,6 +11,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/polyfill_thread.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ public:
|
||||||
explicit Barrier(std::size_t count_) : count(count_) {}
|
explicit Barrier(std::size_t count_) : count(count_) {}
|
||||||
|
|
||||||
/// Blocks until all "count" threads have called Sync()
|
/// Blocks until all "count" threads have called Sync()
|
||||||
void Sync() {
|
bool Sync(std::stop_token token = {}) {
|
||||||
std::unique_lock lk{mutex};
|
std::unique_lock lk{mutex};
|
||||||
const std::size_t current_generation = generation;
|
const std::size_t current_generation = generation;
|
||||||
|
|
||||||
|
@ -77,14 +78,16 @@ public:
|
||||||
generation++;
|
generation++;
|
||||||
waiting = 0;
|
waiting = 0;
|
||||||
condvar.notify_all();
|
condvar.notify_all();
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
condvar.wait(lk,
|
CondvarWait(condvar, lk, token,
|
||||||
[this, current_generation] { return current_generation != generation; });
|
[this, current_generation] { return current_generation != generation; });
|
||||||
|
return !token.stop_requested();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::condition_variable condvar;
|
std::condition_variable_any condvar;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::size_t count;
|
std::size_t count;
|
||||||
std::size_t waiting = 0;
|
std::size_t waiting = 0;
|
||||||
|
|
|
@ -389,7 +389,9 @@ struct System::Impl {
|
||||||
kernel.ShutdownCores();
|
kernel.ShutdownCores();
|
||||||
cpu_manager.Shutdown();
|
cpu_manager.Shutdown();
|
||||||
debugger.reset();
|
debugger.reset();
|
||||||
services->KillNVNFlinger();
|
if (services) {
|
||||||
|
services->KillNVNFlinger();
|
||||||
|
}
|
||||||
kernel.CloseServices();
|
kernel.CloseServices();
|
||||||
services.reset();
|
services.reset();
|
||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
|
|
|
@ -20,23 +20,20 @@ namespace Core {
|
||||||
CpuManager::CpuManager(System& system_) : system{system_} {}
|
CpuManager::CpuManager(System& system_) : system{system_} {}
|
||||||
CpuManager::~CpuManager() = default;
|
CpuManager::~CpuManager() = default;
|
||||||
|
|
||||||
void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
|
|
||||||
std::size_t core) {
|
|
||||||
cpu_manager.RunThread(core);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CpuManager::Initialize() {
|
void CpuManager::Initialize() {
|
||||||
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
||||||
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
||||||
|
|
||||||
for (std::size_t core = 0; core < num_cores; core++) {
|
for (std::size_t core = 0; core < num_cores; core++) {
|
||||||
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
|
core_data[core].host_thread =
|
||||||
|
std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuManager::Shutdown() {
|
void CpuManager::Shutdown() {
|
||||||
for (std::size_t core = 0; core < num_cores; core++) {
|
for (std::size_t core = 0; core < num_cores; core++) {
|
||||||
if (core_data[core].host_thread.joinable()) {
|
if (core_data[core].host_thread.joinable()) {
|
||||||
|
core_data[core].host_thread.request_stop();
|
||||||
core_data[core].host_thread.join();
|
core_data[core].host_thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +181,7 @@ void CpuManager::ShutdownThread() {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CpuManager::RunThread(std::size_t core) {
|
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
|
||||||
/// Initialization
|
/// Initialization
|
||||||
system.RegisterCoreThread(core);
|
system.RegisterCoreThread(core);
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -206,7 +203,9 @@ void CpuManager::RunThread(std::size_t core) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Running
|
// Running
|
||||||
gpu_barrier->Sync();
|
if (!gpu_barrier->Sync(token)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_async_gpu && !is_multicore) {
|
if (!is_async_gpu && !is_multicore) {
|
||||||
system.GPU().ObtainContext();
|
system.GPU().ObtainContext();
|
||||||
|
|
|
@ -81,12 +81,10 @@ private:
|
||||||
void SingleCoreRunGuestThread();
|
void SingleCoreRunGuestThread();
|
||||||
void SingleCoreRunIdleThread();
|
void SingleCoreRunIdleThread();
|
||||||
|
|
||||||
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
|
|
||||||
|
|
||||||
void GuestActivate();
|
void GuestActivate();
|
||||||
void HandleInterrupt();
|
void HandleInterrupt();
|
||||||
void ShutdownThread();
|
void ShutdownThread();
|
||||||
void RunThread(std::size_t core);
|
void RunThread(std::stop_token stop_token, std::size_t core);
|
||||||
|
|
||||||
struct CoreData {
|
struct CoreData {
|
||||||
std::shared_ptr<Common::Fiber> host_context;
|
std::shared_ptr<Common::Fiber> host_context;
|
||||||
|
|
|
@ -104,12 +104,16 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloseCurrentProcess() {
|
void CloseCurrentProcess() {
|
||||||
(*current_process).Finalize();
|
KProcess* old_process = current_process.exchange(nullptr);
|
||||||
// current_process->Close();
|
if (old_process == nullptr) {
|
||||||
// TODO: The current process should be destroyed based on accurate ref counting after
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// old_process->Close();
|
||||||
|
// TODO: The process should be destroyed based on accurate ref counting after
|
||||||
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
|
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
|
||||||
(*current_process).Destroy();
|
old_process->Finalize();
|
||||||
current_process = nullptr;
|
old_process->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
|
|
Reference in New Issue