From da07e13e0798a4ebd423595830f04e2234a03942 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 7 Jul 2022 12:34:46 -0400 Subject: [PATCH] kernel: fix single-core preemption points --- src/core/cpu_manager.cpp | 40 ++++++++++------------------- src/core/cpu_manager.h | 1 - src/core/hle/kernel/k_scheduler.cpp | 13 ++++++++++ src/core/hle/kernel/k_scheduler.h | 5 +--- src/core/hle/kernel/k_thread.cpp | 6 ----- src/core/hle/kernel/k_thread.h | 1 - 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 838d6be21c..9b1565ae1d 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); + auto& kernel = system.Kernel(); - 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); + if (idle_count >= 4 || from_running_environment) { + if (!from_running_environment) { + system.CoreTiming().Idle(); + idle_count = 0; } - 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); - - // Disable dispatch. We're about to preempt this thread. - Kernel::KScopedDisableDispatch dd{kernel}; - Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.GetSwitchFiber()); + 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; } } diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 835505b922..95ea3ef390 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index cac96a7806..230ca3b953 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -103,7 +103,20 @@ void KScheduler::ScheduleOnInterrupt() { GetCurrentThread(kernel).EnableDispatch(); } +void KScheduler::PreemptSingleCore() { + GetCurrentThread(kernel).DisableDispatch(); + + auto* thread = GetCurrentThreadPointer(kernel); + auto& previous_scheduler = kernel.Scheduler(thread->GetCurrentCore()); + previous_scheduler.Unload(thread); + + Common::Fiber::YieldTo(thread->GetHostContext(), *m_switch_fiber); + + GetCurrentThread(kernel).EnableDispatch(); +} + void KScheduler::RescheduleCurrentCore() { + ASSERT(!kernel.IsPhantomModeForSingleCore()); ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1); GetCurrentThread(kernel).EnableDispatch(); diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 91e8709336..ac7421c9a9 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -49,6 +49,7 @@ public: void SetInterruptTaskRunnable(); void RequestScheduleOnInterrupt(); + void PreemptSingleCore(); u64 GetIdleCount() { return m_state.idle_count; @@ -62,10 +63,6 @@ public: return m_current_thread.load() == m_idle_thread; } - std::shared_ptr GetSwitchFiber() { - return m_switch_fiber; - } - KThread* GetPreviousThread() const { return m_state.prev_thread; } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index d5d390f046..3640d1d13b 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1204,12 +1204,6 @@ KScopedDisableDispatch::~KScopedDisableDispatch() { return; } - // Skip the reschedule if single-core. - if (!Settings::values.use_multi_core.GetValue()) { - GetCurrentThread(kernel).EnableDispatch(); - return; - } - if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { auto scheduler = kernel.CurrentScheduler(); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 1fc8f5f3e0..9ee20208eb 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -110,7 +110,6 @@ void SetCurrentThread(KernelCore& kernel, KThread* thread); [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); -size_t CaptureBacktrace(void** buffer, size_t max); class KThread final : public KAutoObjectWithSlabHeapAndContainer, public boost::intrusive::list_base_hook<> {