From 0624c880bd5af45ae9095465e079fa55458515f6 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 26 Jun 2022 18:52:16 -0400 Subject: kernel: use KScheduler from mesosphere --- src/core/cpu_manager.cpp | 161 ++++++++++++++++++----------------------------- 1 file changed, 61 insertions(+), 100 deletions(-) (limited to 'src/core/cpu_manager.cpp') diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 37d3d83b9..428194129 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -8,6 +8,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/cpu_manager.h" +#include "core/hle/kernel/k_interrupt_manager.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" @@ -41,44 +42,65 @@ void CpuManager::Shutdown() { } } -void CpuManager::GuestThreadFunction() { +void CpuManager::GuestActivateFunction() { if (is_multicore) { - MultiCoreRunGuestThread(); + MultiCoreGuestActivate(); } else { - SingleCoreRunGuestThread(); + SingleCoreGuestActivate(); } } -void CpuManager::GuestRewindFunction() { +void CpuManager::GuestThreadFunction() { if (is_multicore) { - MultiCoreRunGuestLoop(); + MultiCoreRunGuestThread(); } else { - SingleCoreRunGuestLoop(); + SingleCoreRunGuestThread(); } } -void CpuManager::IdleThreadFunction() { - if (is_multicore) { - MultiCoreRunIdleThread(); - } else { - SingleCoreRunIdleThread(); +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::ShutdownThreadFunction() { - ShutdownThread(); +void CpuManager::HandleInterrupt() { + auto& kernel = system.Kernel(); + auto core_index = kernel.CurrentPhysicalCoreIndex(); + + Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast(core_index)); } /////////////////////////////////////////////////////////////////////////////// /// MultiCore /// /////////////////////////////////////////////////////////////////////////////// +void CpuManager::MultiCoreGuestActivate() { + // Similar to the HorizonKernelMain callback in HOS + auto& kernel = system.Kernel(); + auto* scheduler = kernel.CurrentScheduler(); + + scheduler->Activate(); + UNREACHABLE(); +} + void CpuManager::MultiCoreRunGuestThread() { + // Similar to UserModeThreadStarter in HOS auto& kernel = system.Kernel(); - kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); - auto& host_context = thread->GetHostContext(); - host_context->SetRewindPoint([this] { GuestRewindFunction(); }); + auto* thread = kernel.GetCurrentEmuThread(); + thread->EnableDispatch(); + MultiCoreRunGuestLoop(); } @@ -91,18 +113,8 @@ void CpuManager::MultiCoreRunGuestLoop() { physical_core->Run(); physical_core = &kernel.CurrentPhysicalCore(); } - { - Kernel::KScopedDisableDispatch dd(kernel); - physical_core->ArmInterface().ClearExclusiveState(); - } - } -} -void CpuManager::MultiCoreRunIdleThread() { - auto& kernel = system.Kernel(); - while (true) { - Kernel::KScopedDisableDispatch dd(kernel); - kernel.CurrentPhysicalCore().Idle(); + HandleInterrupt(); } } @@ -110,83 +122,20 @@ void CpuManager::MultiCoreRunIdleThread() { /// SingleCore /// /////////////////////////////////////////////////////////////////////////////// -void CpuManager::SingleCoreRunGuestThread() { - auto& kernel = system.Kernel(); - kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); - auto& host_context = thread->GetHostContext(); - host_context->SetRewindPoint([this] { GuestRewindFunction(); }); - SingleCoreRunGuestLoop(); -} - -void CpuManager::SingleCoreRunGuestLoop() { - auto& kernel = system.Kernel(); - while (true) { - auto* physical_core = &kernel.CurrentPhysicalCore(); - if (!physical_core->IsInterrupted()) { - physical_core->Run(); - physical_core = &kernel.CurrentPhysicalCore(); - } - kernel.SetIsPhantomModeForSingleCore(true); - system.CoreTiming().Advance(); - kernel.SetIsPhantomModeForSingleCore(false); - physical_core->ArmInterface().ClearExclusiveState(); - PreemptSingleCore(); - auto& scheduler = kernel.Scheduler(current_core); - scheduler.RescheduleCurrentCore(); - } -} - -void CpuManager::SingleCoreRunIdleThread() { - auto& kernel = system.Kernel(); - while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); - PreemptSingleCore(false); - system.CoreTiming().AddTicks(1000U); - idle_count++; - auto& scheduler = physical_core.Scheduler(); - scheduler.RescheduleCurrentCore(); - } -} +void CpuManager::SingleCoreGuestActivate() {} -void CpuManager::PreemptSingleCore(bool from_running_enviroment) { - { - auto& kernel = system.Kernel(); - auto& scheduler = kernel.Scheduler(current_core); - Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread(); - if (idle_count >= 4 || from_running_enviroment) { - if (!from_running_enviroment) { - 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); - Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); - } +void CpuManager::SingleCoreRunGuestLoop() {} - // May have changed scheduler - { - auto& scheduler = system.Kernel().Scheduler(current_core); - scheduler.Reload(scheduler.GetSchedulerCurrentThread()); - if (!scheduler.IsIdle()) { - idle_count = 0; - } - } -} +void CpuManager::PreemptSingleCore(bool from_running_enviroment) {} void CpuManager::ShutdownThread() { auto& kernel = system.Kernel(); + auto* thread = kernel.GetCurrentEmuThread(); auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; - auto* current_thread = kernel.GetCurrentEmuThread(); - Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); + Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context); UNREACHABLE(); } @@ -218,9 +167,21 @@ void CpuManager::RunThread(std::size_t core) { system.GPU().ObtainContext(); } - auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread(); - Kernel::SetCurrentThread(system.Kernel(), current_thread); - Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); + auto& kernel = system.Kernel(); + + 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()); } } // namespace Core -- cgit v1.2.3 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 From da07e13e0798a4ebd423595830f04e2234a03942 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 7 Jul 2022 12:34:46 -0400 Subject: kernel: fix single-core preemption points --- src/core/cpu_manager.cpp | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'src/core/cpu_manager.cpp') diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 838d6be21..9b1565ae1 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -144,39 +144,25 @@ void CpuManager::SingleCoreRunIdleThread() { } 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()); - - auto& next_scheduler = kernel.Scheduler(current_core); + auto& kernel = system.Kernel(); - // Disable dispatch. We're about to preempt this thread. - Kernel::KScopedDisableDispatch dd{kernel}; - Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.GetSwitchFiber()); + 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(); + kernel.Scheduler(current_core).PreemptSingleCore(); // 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; - } + if (!kernel.Scheduler(current_core).IsIdle()) { + idle_count = 0; } } -- cgit v1.2.3