General: Recover Prometheus project from harddrive failure

This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host 
Timing, Reworks the Kernel's Scheduler, Introduce Idle State and 
Suspended State, Recreates the bootmanager, Initializes Multicore 
system.
This commit is contained in:
Fernando Sahmkow 2020-02-24 22:04:12 -04:00
parent a83f0b607e
commit 7ee76003ad
57 changed files with 1349 additions and 824 deletions

View file

@ -2,80 +2,192 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/fiber.h"
#include "common/thread.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
namespace Core {
CpuManager::CpuManager(System& system) : system{system} {}
CpuManager::~CpuManager() = default;
void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
cpu_manager.RunThread(core);
}
void CpuManager::Initialize() {
for (std::size_t index = 0; index < core_managers.size(); ++index) {
core_managers[index] = std::make_unique<CoreManager>(system, index);
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);
}
}
void CpuManager::Shutdown() {
for (auto& cpu_core : core_managers) {
cpu_core.reset();
running_mode = false;
Pause(false);
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
core_data[core].host_thread->join();
}
}
CoreManager& CpuManager::GetCoreManager(std::size_t index) {
return *core_managers.at(index);
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
cpu_manager->RunGuestThread();
}
const CoreManager& CpuManager::GetCoreManager(std::size_t index) const {
return *core_managers.at(index);
void CpuManager::IdleThreadFunction(void* cpu_manager_) {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
cpu_manager->RunIdleThread();
}
CoreManager& CpuManager::GetCurrentCoreManager() {
// Otherwise, use single-threaded mode active_core variable
return *core_managers[active_core];
void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
cpu_manager->RunSuspendThread();
}
const CoreManager& CpuManager::GetCurrentCoreManager() const {
// Otherwise, use single-threaded mode active_core variable
return *core_managers[active_core];
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
return std::function<void(void*)>(GuestThreadFunction);
}
void CpuManager::RunLoop(bool tight_loop) {
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
return std::function<void(void*)>(IdleThreadFunction);
}
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return;
std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
return std::function<void(void*)>(SuspendThreadFunction);
}
void* CpuManager::GetStartFuncParamater() {
return static_cast<void*>(this);
}
void CpuManager::RunGuestThread() {
auto& kernel = system.Kernel();
{
auto& sched = kernel.CurrentScheduler();
sched.OnThreadStart();
}
while (true) {
auto& physical_core = kernel.CurrentPhysicalCore();
LOG_CRITICAL(Core_ARM, "Running Guest Thread");
physical_core.Idle();
LOG_CRITICAL(Core_ARM, "Leaving Guest Thread");
// physical_core.Run();
auto& scheduler = physical_core.Scheduler();
scheduler.TryDoContextSwitch();
}
}
void CpuManager::RunIdleThread() {
auto& kernel = system.Kernel();
while (true) {
auto& physical_core = kernel.CurrentPhysicalCore();
LOG_CRITICAL(Core_ARM, "Running Idle Thread");
physical_core.Idle();
auto& scheduler = physical_core.Scheduler();
scheduler.TryDoContextSwitch();
}
}
void CpuManager::RunSuspendThread() {
LOG_CRITICAL(Core_ARM, "Suspending Thread Entered");
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();
LOG_CRITICAL(Core_ARM, "Suspending Core {}", core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
LOG_CRITICAL(Core_ARM, "Unsuspending Core {}", core);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.TryDoContextSwitch();
}
}
void CpuManager::Pause(bool paused) {
if (!paused) {
bool all_not_barrier = false;
while (!all_not_barrier) {
all_not_barrier = true;
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
all_not_barrier &=
!core_data[core].is_running.load() && core_data[core].initialized.load();
}
}
}
auto& core_timing = system.CoreTiming();
core_timing.ResetRun();
bool keep_running{};
do {
keep_running = false;
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
core_timing.SwitchContext(active_core);
if (core_timing.CanCurrentContextRun()) {
core_managers[active_core]->RunLoop(tight_loop);
}
keep_running |= core_timing.CanCurrentContextRun();
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
core_data[core].enter_barrier->Set();
}
} while (keep_running);
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
if (paused_state.load()) {
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
all_barrier &=
core_data[core].is_paused.load() && core_data[core].initialized.load();
}
}
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
core_data[core].exit_barrier->Set();
}
}
} else {
/// Wait until all cores are paused.
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
all_barrier &=
core_data[core].is_paused.load() && core_data[core].initialized.load();
}
}
/// Don't release the barrier
}
paused_state = paused;
}
void CpuManager::RunThread(std::size_t core) {
/// Initialization
system.RegisterCoreThread(core);
std::string name = "yuzu:CoreHostThread_" + std::to_string(core);
Common::SetCurrentThreadName(name.c_str());
auto& data = core_data[core];
data.enter_barrier = std::make_unique<Common::Event>();
data.exit_barrier = std::make_unique<Common::Event>();
data.host_context = Common::Fiber::ThreadToFiber();
data.is_running = false;
data.initialized = true;
/// Running
while (running_mode) {
data.is_running = false;
data.enter_barrier->Wait();
auto& scheduler = system.Kernel().CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
data.is_running = true;
Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
data.is_running = false;
data.is_paused = true;
data.exit_barrier->Wait();
data.is_paused = false;
}
/// Time to cleanup
data.host_context->Exit();
data.enter_barrier.reset();
data.exit_barrier.reset();
data.initialized = false;
}
} // namespace Core