diff options
Diffstat (limited to 'src/core/cpu_manager.cpp')
| -rw-r--r-- | src/core/cpu_manager.cpp | 161 |
1 files changed, 70 insertions, 91 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index d69b2602a..9b1565ae1 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,51 +42,31 @@ void CpuManager::Shutdown() { } } -std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { - return GuestThreadFunction; -} - -std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() { - return IdleThreadFunction; -} - -std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() { - return ShutdownThreadFunction; -} - -void CpuManager::GuestThreadFunction(void* cpu_manager_) { - CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); - if (cpu_manager->is_multicore) { - cpu_manager->MultiCoreRunGuestThread(); +void CpuManager::GuestThreadFunction() { + if (is_multicore) { + MultiCoreRunGuestThread(); } else { - cpu_manager->SingleCoreRunGuestThread(); + SingleCoreRunGuestThread(); } } -void CpuManager::GuestRewindFunction(void* cpu_manager_) { - CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); - if (cpu_manager->is_multicore) { - cpu_manager->MultiCoreRunGuestLoop(); +void CpuManager::IdleThreadFunction() { + if (is_multicore) { + MultiCoreRunIdleThread(); } else { - cpu_manager->SingleCoreRunGuestLoop(); + SingleCoreRunIdleThread(); } } -void CpuManager::IdleThreadFunction(void* cpu_manager_) { - CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_); - if (cpu_manager->is_multicore) { - cpu_manager->MultiCoreRunIdleThread(); - } else { - cpu_manager->SingleCoreRunIdleThread(); - } +void CpuManager::ShutdownThreadFunction() { + ShutdownThread(); } -void CpuManager::ShutdownThreadFunction(void* cpu_manager) { - static_cast<CpuManager*>(cpu_manager)->ShutdownThread(); -} +void CpuManager::HandleInterrupt() { + auto& kernel = system.Kernel(); + auto core_index = kernel.CurrentPhysicalCoreIndex(); -void* CpuManager::GetStartFuncParameter() { - return this; + Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_index)); } /////////////////////////////////////////////////////////////////////////////// @@ -93,16 +74,9 @@ void* CpuManager::GetStartFuncParameter() { /////////////////////////////////////////////////////////////////////////////// void CpuManager::MultiCoreRunGuestThread() { + // Similar to UserModeThreadStarter in HOS auto& kernel = system.Kernel(); kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); - auto& host_context = thread->GetHostContext(); - host_context->SetRewindPoint(GuestRewindFunction, this); - MultiCoreRunGuestLoop(); -} - -void CpuManager::MultiCoreRunGuestLoop() { - auto& kernel = system.Kernel(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); @@ -110,18 +84,26 @@ void CpuManager::MultiCoreRunGuestLoop() { physical_core->Run(); physical_core = &kernel.CurrentPhysicalCore(); } - { - Kernel::KScopedDisableDispatch dd(kernel); - physical_core->ArmInterface().ClearExclusiveState(); - } + + HandleInterrupt(); } } 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(); + kernel.CurrentScheduler()->OnThreadStart(); + while (true) { - Kernel::KScopedDisableDispatch dd(kernel); - kernel.CurrentPhysicalCore().Idle(); + auto& physical_core = kernel.CurrentPhysicalCore(); + if (!physical_core.IsInterrupted()) { + physical_core.Idle(); + } + + HandleInterrupt(); } } @@ -132,80 +114,73 @@ void CpuManager::MultiCoreRunIdleThread() { void CpuManager::SingleCoreRunGuestThread() { auto& kernel = system.Kernel(); kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); - auto& host_context = thread->GetHostContext(); - host_context->SetRewindPoint(GuestRewindFunction, this); - 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(); + HandleInterrupt(); } } void CpuManager::SingleCoreRunIdleThread() { auto& kernel = system.Kernel(); + kernel.CurrentScheduler()->OnThreadStart(); + while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); PreemptSingleCore(false); system.CoreTiming().AddTicks(1000U); idle_count++; - auto& scheduler = physical_core.Scheduler(); - scheduler.RescheduleCurrentCore(); + HandleInterrupt(); } } -void CpuManager::PreemptSingleCore(bool from_running_enviroment) { - { - auto& kernel = system.Kernel(); - auto& scheduler = kernel.Scheduler(current_core); - Kernel::KThread* current_thread = scheduler.GetCurrentThread(); - 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.GetCurrentThread()); - - auto& next_scheduler = kernel.Scheduler(current_core); - Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); - } +void CpuManager::PreemptSingleCore(bool from_running_environment) { + auto& kernel = system.Kernel(); - // May have changed scheduler - { - auto& scheduler = system.Kernel().Scheduler(current_core); - scheduler.Reload(scheduler.GetCurrentThread()); - if (!scheduler.IsIdle()) { + 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. + if (!kernel.Scheduler(current_core).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(); + 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(); } @@ -237,8 +212,12 @@ void CpuManager::RunThread(std::size_t core) { system.GPU().ObtainContext(); } - auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); - Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); + auto& kernel = system.Kernel(); + auto& scheduler = *kernel.CurrentScheduler(); + auto* thread = scheduler.GetSchedulerCurrentThread(); + Kernel::SetCurrentThread(kernel, thread); + + Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext()); } } // namespace Core |
