From 21945ae127480c8332c1110ceada2df4a42a5848 Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 5 Jul 2022 23:27:25 -0400 Subject: kernel: fix issues with single core mode --- src/core/cpu_manager.cpp | 152 +++++++++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 51 deletions(-) (limited to 'src/core/cpu_manager.cpp') diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 428194129..838d6be21 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -42,19 +42,19 @@ void CpuManager::Shutdown() { } } -void CpuManager::GuestActivateFunction() { +void CpuManager::GuestThreadFunction() { if (is_multicore) { - MultiCoreGuestActivate(); + MultiCoreRunGuestThread(); } else { - SingleCoreGuestActivate(); + SingleCoreRunGuestThread(); } } -void CpuManager::GuestThreadFunction() { +void CpuManager::IdleThreadFunction() { if (is_multicore) { - MultiCoreRunGuestThread(); + MultiCoreRunIdleThread(); } else { - SingleCoreRunGuestThread(); + SingleCoreRunIdleThread(); } } @@ -62,19 +62,6 @@ void CpuManager::ShutdownThreadFunction() { ShutdownThread(); } -void CpuManager::WaitForAndHandleInterrupt() { - auto& kernel = system.Kernel(); - auto& physical_core = kernel.CurrentPhysicalCore(); - - ASSERT(Kernel::GetCurrentThread(kernel).GetDisableDispatchCount() == 1); - - if (!physical_core.IsInterrupted()) { - physical_core.Idle(); - } - - HandleInterrupt(); -} - void CpuManager::HandleInterrupt() { auto& kernel = system.Kernel(); auto core_index = kernel.CurrentPhysicalCoreIndex(); @@ -86,49 +73,121 @@ void CpuManager::HandleInterrupt() { /// MultiCore /// /////////////////////////////////////////////////////////////////////////////// -void CpuManager::MultiCoreGuestActivate() { - // Similar to the HorizonKernelMain callback in HOS +void CpuManager::MultiCoreRunGuestThread() { + // Similar to UserModeThreadStarter in HOS auto& kernel = system.Kernel(); - auto* scheduler = kernel.CurrentScheduler(); + kernel.CurrentScheduler()->OnThreadStart(); - scheduler->Activate(); - UNREACHABLE(); + while (true) { + auto* physical_core = &kernel.CurrentPhysicalCore(); + while (!physical_core->IsInterrupted()) { + physical_core->Run(); + physical_core = &kernel.CurrentPhysicalCore(); + } + + HandleInterrupt(); + } } -void CpuManager::MultiCoreRunGuestThread() { - // Similar to UserModeThreadStarter in HOS +void CpuManager::MultiCoreRunIdleThread() { + // Not accurate to HOS. Remove this entire method when singlecore is removed. + // See notes in KScheduler::ScheduleImpl for more information about why this + // is inaccurate. + auto& kernel = system.Kernel(); - auto* thread = kernel.GetCurrentEmuThread(); - thread->EnableDispatch(); + kernel.CurrentScheduler()->OnThreadStart(); + + while (true) { + auto& physical_core = kernel.CurrentPhysicalCore(); + if (!physical_core.IsInterrupted()) { + physical_core.Idle(); + } - MultiCoreRunGuestLoop(); + HandleInterrupt(); + } } -void CpuManager::MultiCoreRunGuestLoop() { +/////////////////////////////////////////////////////////////////////////////// +/// SingleCore /// +/////////////////////////////////////////////////////////////////////////////// + +void CpuManager::SingleCoreRunGuestThread() { auto& kernel = system.Kernel(); + kernel.CurrentScheduler()->OnThreadStart(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); - while (!physical_core->IsInterrupted()) { + if (!physical_core->IsInterrupted()) { physical_core->Run(); physical_core = &kernel.CurrentPhysicalCore(); } + kernel.SetIsPhantomModeForSingleCore(true); + system.CoreTiming().Advance(); + kernel.SetIsPhantomModeForSingleCore(false); + + PreemptSingleCore(); HandleInterrupt(); } } -/////////////////////////////////////////////////////////////////////////////// -/// SingleCore /// -/////////////////////////////////////////////////////////////////////////////// +void CpuManager::SingleCoreRunIdleThread() { + auto& kernel = system.Kernel(); + kernel.CurrentScheduler()->OnThreadStart(); + + while (true) { + PreemptSingleCore(false); + system.CoreTiming().AddTicks(1000U); + idle_count++; + HandleInterrupt(); + } +} -void CpuManager::SingleCoreGuestActivate() {} +void CpuManager::PreemptSingleCore(bool from_running_environment) { + { + auto& kernel = system.Kernel(); + auto& scheduler = kernel.Scheduler(current_core); + + Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread(); + if (idle_count >= 4 || from_running_environment) { + if (!from_running_environment) { + system.CoreTiming().Idle(); + idle_count = 0; + } + kernel.SetIsPhantomModeForSingleCore(true); + system.CoreTiming().Advance(); + kernel.SetIsPhantomModeForSingleCore(false); + } + current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); + system.CoreTiming().ResetTicks(); + scheduler.Unload(scheduler.GetSchedulerCurrentThread()); -void CpuManager::SingleCoreRunGuestThread() {} + auto& next_scheduler = kernel.Scheduler(current_core); -void CpuManager::SingleCoreRunGuestLoop() {} + // Disable dispatch. We're about to preempt this thread. + Kernel::KScopedDisableDispatch dd{kernel}; + Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.GetSwitchFiber()); + } -void CpuManager::PreemptSingleCore(bool from_running_enviroment) {} + // We've now been scheduled again, and we may have exchanged schedulers. + // Reload the scheduler in case it's different. + { + auto& scheduler = system.Kernel().Scheduler(current_core); + scheduler.Reload(scheduler.GetSchedulerCurrentThread()); + if (!scheduler.IsIdle()) { + idle_count = 0; + } + } +} + +void CpuManager::GuestActivate() { + // Similar to the HorizonKernelMain callback in HOS + auto& kernel = system.Kernel(); + auto* scheduler = kernel.CurrentScheduler(); + + scheduler->Activate(); + UNREACHABLE(); +} void CpuManager::ShutdownThread() { auto& kernel = system.Kernel(); @@ -168,20 +227,11 @@ void CpuManager::RunThread(std::size_t core) { } auto& kernel = system.Kernel(); + auto& scheduler = *kernel.CurrentScheduler(); + auto* thread = scheduler.GetSchedulerCurrentThread(); + Kernel::SetCurrentThread(kernel, thread); - auto* main_thread = Kernel::KThread::Create(kernel); - main_thread->SetName(fmt::format("MainThread:{}", core)); - ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, static_cast(core)) - .IsSuccess()); - - auto* idle_thread = Kernel::KThread::Create(kernel); - ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast(core)) - .IsSuccess()); - - kernel.SetCurrentEmuThread(main_thread); - kernel.CurrentScheduler()->Initialize(idle_thread); - - Common::Fiber::YieldTo(data.host_context, *main_thread->GetHostContext()); + Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext()); } } // namespace Core -- cgit v1.2.3