mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-06-06 01:13:45 -04:00
scheduler takes kernel ptr
This commit is contained in:
parent
219bffec19
commit
1fd762fd31
9 changed files with 150 additions and 182 deletions
|
|
@ -438,7 +438,6 @@ public:
|
|||
/// Applies any changes to settings to this core instance.
|
||||
void ApplySettings();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,30 +41,28 @@ void CpuManager::Shutdown() {
|
|||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction() {
|
||||
void CpuManager::GuestThreadFunction(Kernel::KernelCore& kernel) {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestThread();
|
||||
MultiCoreRunGuestThread(kernel);
|
||||
} else {
|
||||
SingleCoreRunGuestThread();
|
||||
SingleCoreRunGuestThread(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::IdleThreadFunction() {
|
||||
void CpuManager::IdleThreadFunction(Kernel::KernelCore& kernel) {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunIdleThread();
|
||||
MultiCoreRunIdleThread(kernel);
|
||||
} else {
|
||||
SingleCoreRunIdleThread();
|
||||
SingleCoreRunIdleThread(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThreadFunction() {
|
||||
ShutdownThread();
|
||||
void CpuManager::ShutdownThreadFunction(Kernel::KernelCore& kernel) {
|
||||
ShutdownThread(kernel);
|
||||
}
|
||||
|
||||
void CpuManager::HandleInterrupt() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::HandleInterrupt(Kernel::KernelCore& kernel) {
|
||||
auto core_index = kernel.CurrentPhysicalCoreIndex();
|
||||
|
||||
Kernel::KInterruptManager::HandleInterrupt(kernel, s32(core_index));
|
||||
}
|
||||
|
||||
|
|
@ -72,11 +70,10 @@ void CpuManager::HandleInterrupt() {
|
|||
/// MultiCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::MultiCoreRunGuestThread() {
|
||||
void CpuManager::MultiCoreRunGuestThread(Kernel::KernelCore& kernel) {
|
||||
// Similar to UserModeThreadStarter in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* thread = Kernel::GetCurrentThreadPointer(kernel);
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
|
||||
while (true) {
|
||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||
|
|
@ -84,26 +81,21 @@ void CpuManager::MultiCoreRunGuestThread() {
|
|||
physical_core->RunThread(kernel, thread);
|
||||
physical_core = &kernel.CurrentPhysicalCore();
|
||||
}
|
||||
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::MultiCoreRunIdleThread() {
|
||||
void CpuManager::MultiCoreRunIdleThread(Kernel::KernelCore& kernel) {
|
||||
// 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();
|
||||
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
while (true) {
|
||||
auto& physical_core = kernel.CurrentPhysicalCore();
|
||||
if (!physical_core.IsInterrupted()) {
|
||||
physical_core.Idle();
|
||||
}
|
||||
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,10 +103,9 @@ void CpuManager::MultiCoreRunIdleThread() {
|
|||
/// SingleCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::SingleCoreRunGuestThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::SingleCoreRunGuestThread(Kernel::KernelCore& kernel) {
|
||||
auto* thread = Kernel::GetCurrentThreadPointer(kernel);
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
|
||||
while (true) {
|
||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||
|
|
@ -127,26 +118,22 @@ void CpuManager::SingleCoreRunGuestThread() {
|
|||
system.CoreTiming().Advance();
|
||||
kernel.SetIsPhantomModeForSingleCore(false);
|
||||
|
||||
PreemptSingleCore();
|
||||
HandleInterrupt();
|
||||
PreemptSingleCore(kernel);
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::SingleCoreRunIdleThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
kernel.CurrentScheduler()->OnThreadStart();
|
||||
|
||||
void CpuManager::SingleCoreRunIdleThread(Kernel::KernelCore& kernel) {
|
||||
kernel.CurrentScheduler()->OnThreadStart(kernel);
|
||||
while (true) {
|
||||
PreemptSingleCore(false);
|
||||
PreemptSingleCore(kernel, false);
|
||||
system.CoreTiming().AddTicks(1000U);
|
||||
idle_count++;
|
||||
HandleInterrupt();
|
||||
HandleInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
void CpuManager::PreemptSingleCore(Kernel::KernelCore& kernel, bool from_running_environment) {
|
||||
if (idle_count >= 4 || from_running_environment) {
|
||||
if (!from_running_environment) {
|
||||
system.CoreTiming().Idle();
|
||||
|
|
@ -158,7 +145,7 @@ void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
|||
}
|
||||
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
|
||||
system.CoreTiming().ResetTicks();
|
||||
kernel.Scheduler(current_core).PreemptSingleCore();
|
||||
kernel.Scheduler(current_core).PreemptSingleCore(kernel);
|
||||
|
||||
// We've now been scheduled again, and we may have exchanged schedulers.
|
||||
// Reload the scheduler in case it's different.
|
||||
|
|
@ -167,20 +154,16 @@ void CpuManager::PreemptSingleCore(bool from_running_environment) {
|
|||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestActivate() {
|
||||
void CpuManager::GuestActivate(Kernel::KernelCore& kernel) {
|
||||
// Similar to the HorizonKernelMain callback in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* scheduler = kernel.CurrentScheduler();
|
||||
|
||||
scheduler->Activate();
|
||||
scheduler->Activate(kernel);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
void CpuManager::ShutdownThread(Kernel::KernelCore& kernel) {
|
||||
auto* thread = kernel.GetCurrentEmuThread();
|
||||
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
|
||||
|
||||
Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
#include "common/thread.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class Event;
|
||||
class Fiber;
|
||||
|
|
@ -54,39 +58,39 @@ public:
|
|||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
std::function<void()> GetGuestActivateFunc() {
|
||||
return [this] { GuestActivate(); };
|
||||
std::function<void()> GetGuestActivateFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { GuestActivate(kernel); };
|
||||
}
|
||||
std::function<void()> GetGuestThreadFunc() {
|
||||
return [this] { GuestThreadFunction(); };
|
||||
std::function<void()> GetGuestThreadFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { GuestThreadFunction(kernel); };
|
||||
}
|
||||
std::function<void()> GetIdleThreadStartFunc() {
|
||||
return [this] { IdleThreadFunction(); };
|
||||
std::function<void()> GetIdleThreadStartFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { IdleThreadFunction(kernel); };
|
||||
}
|
||||
std::function<void()> GetShutdownThreadStartFunc() {
|
||||
return [this] { ShutdownThreadFunction(); };
|
||||
std::function<void()> GetShutdownThreadStartFunc(Kernel::KernelCore& kernel) {
|
||||
return [this, &kernel] { ShutdownThreadFunction(kernel); };
|
||||
}
|
||||
|
||||
void PreemptSingleCore(bool from_running_environment = true);
|
||||
void PreemptSingleCore(Kernel::KernelCore& kernel, bool from_running_environment = true);
|
||||
|
||||
std::size_t CurrentCore() const {
|
||||
return current_core.load();
|
||||
}
|
||||
|
||||
private:
|
||||
void GuestThreadFunction();
|
||||
void IdleThreadFunction();
|
||||
void ShutdownThreadFunction();
|
||||
void GuestThreadFunction(Kernel::KernelCore& kernel);
|
||||
void IdleThreadFunction(Kernel::KernelCore& kernel);
|
||||
void ShutdownThreadFunction(Kernel::KernelCore& kernel);
|
||||
|
||||
void MultiCoreRunGuestThread();
|
||||
void MultiCoreRunIdleThread();
|
||||
void MultiCoreRunGuestThread(Kernel::KernelCore& kernel);
|
||||
void MultiCoreRunIdleThread(Kernel::KernelCore& kernel);
|
||||
|
||||
void SingleCoreRunGuestThread();
|
||||
void SingleCoreRunIdleThread();
|
||||
void SingleCoreRunGuestThread(Kernel::KernelCore& kernel);
|
||||
void SingleCoreRunIdleThread(Kernel::KernelCore& kernel);
|
||||
|
||||
void GuestActivate();
|
||||
void HandleInterrupt();
|
||||
void ShutdownThread();
|
||||
void GuestActivate(Kernel::KernelCore& kernel);
|
||||
void HandleInterrupt(Kernel::KernelCore& kernel);
|
||||
void ShutdownThread(Kernel::KernelCore& kernel);
|
||||
void RunThread(std::stop_token stop_token, std::size_t core);
|
||||
|
||||
static constexpr std::size_t max_cycle_runs = 5;
|
||||
|
|
@ -97,7 +101,7 @@ private:
|
|||
std::jthread host_thread;
|
||||
};
|
||||
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
|
||||
System& system;
|
||||
Core::System& system;
|
||||
std::atomic<std::size_t> current_core{};
|
||||
std::size_t idle_count{};
|
||||
std::size_t num_cores{};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) {
|
|||
}
|
||||
|
||||
// Request interrupt scheduling.
|
||||
kernel.CurrentScheduler()->RequestScheduleOnInterrupt();
|
||||
kernel.CurrentScheduler()->RequestScheduleOnInterrupt(kernel);
|
||||
}
|
||||
|
||||
void SendInterProcessorInterrupt(KernelCore& kernel, u64 core_mask) {
|
||||
|
|
|
|||
|
|
@ -30,28 +30,26 @@ static void IncrementScheduledCount(Kernel::KThread* thread) {
|
|||
}
|
||||
}
|
||||
|
||||
KScheduler::KScheduler(KernelCore& kernel) : m_kernel{kernel} {
|
||||
m_switch_fiber = std::make_shared<Common::Fiber>([this] {
|
||||
KScheduler::KScheduler(KernelCore& kernel) {
|
||||
m_switch_fiber = std::make_shared<Common::Fiber>([this, &kernel] {
|
||||
while (true) {
|
||||
ScheduleImplFiber();
|
||||
ScheduleImplFiber(kernel);
|
||||
}
|
||||
});
|
||||
|
||||
m_state.needs_scheduling = true;
|
||||
}
|
||||
|
||||
KScheduler::~KScheduler() = default;
|
||||
|
||||
void KScheduler::SetInterruptTaskRunnable() {
|
||||
void KScheduler::SetInterruptTaskRunnable(KernelCore& kernel) {
|
||||
m_state.interrupt_task_runnable = true;
|
||||
m_state.needs_scheduling = true;
|
||||
}
|
||||
|
||||
void KScheduler::RequestScheduleOnInterrupt() {
|
||||
void KScheduler::RequestScheduleOnInterrupt(KernelCore& kernel) {
|
||||
m_state.needs_scheduling = true;
|
||||
|
||||
if (CanSchedule(m_kernel)) {
|
||||
ScheduleOnInterrupt();
|
||||
if (CanSchedule(kernel)) {
|
||||
ScheduleOnInterrupt(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,12 +69,12 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli
|
|||
return;
|
||||
}
|
||||
|
||||
scheduler->RescheduleOtherCores(cores_needing_scheduling);
|
||||
scheduler->RescheduleOtherCores(kernel, cores_needing_scheduling);
|
||||
|
||||
if (GetCurrentThread(kernel).GetDisableDispatchCount() > 1) {
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
} else {
|
||||
scheduler->RescheduleCurrentCore();
|
||||
scheduler->RescheduleCurrentCore(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,55 +97,55 @@ u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
|
|||
}
|
||||
}
|
||||
|
||||
void KScheduler::Schedule() {
|
||||
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
|
||||
ASSERT(m_core_id == GetCurrentCoreId(m_kernel));
|
||||
void KScheduler::Schedule(KernelCore& kernel) {
|
||||
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
|
||||
ASSERT(m_core_id == GetCurrentCoreId(kernel));
|
||||
|
||||
ScheduleImpl();
|
||||
ScheduleImpl(kernel);
|
||||
}
|
||||
|
||||
void KScheduler::ScheduleOnInterrupt() {
|
||||
GetCurrentThread(m_kernel).DisableDispatch(m_kernel);
|
||||
Schedule();
|
||||
GetCurrentThread(m_kernel).EnableDispatch(m_kernel);
|
||||
void KScheduler::ScheduleOnInterrupt(KernelCore& kernel) {
|
||||
GetCurrentThread(kernel).DisableDispatch(kernel);
|
||||
Schedule(kernel);
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
}
|
||||
|
||||
void KScheduler::PreemptSingleCore() {
|
||||
GetCurrentThread(m_kernel).DisableDispatch(m_kernel);
|
||||
void KScheduler::PreemptSingleCore(KernelCore& kernel) {
|
||||
GetCurrentThread(kernel).DisableDispatch(kernel);
|
||||
|
||||
auto* thread = GetCurrentThreadPointer(m_kernel);
|
||||
auto& previous_scheduler = m_kernel.Scheduler(thread->GetCurrentCore());
|
||||
previous_scheduler.Unload(thread);
|
||||
auto* thread = GetCurrentThreadPointer(kernel);
|
||||
auto& previous_scheduler = kernel.Scheduler(thread->GetCurrentCore());
|
||||
previous_scheduler.Unload(kernel, thread);
|
||||
|
||||
Common::Fiber::YieldTo(thread->GetHostContext(), *m_switch_fiber);
|
||||
|
||||
GetCurrentThread(m_kernel).EnableDispatch(m_kernel);
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
}
|
||||
|
||||
void KScheduler::RescheduleCurrentCore() {
|
||||
ASSERT(!m_kernel.IsPhantomModeForSingleCore());
|
||||
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
|
||||
void KScheduler::RescheduleCurrentCore(KernelCore& kernel) {
|
||||
ASSERT(!kernel.IsPhantomModeForSingleCore());
|
||||
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
|
||||
|
||||
GetCurrentThread(m_kernel).EnableDispatch(m_kernel);
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
|
||||
if (m_state.needs_scheduling.load()) {
|
||||
// Disable interrupts, and then check again if rescheduling is needed.
|
||||
// KScopedInterruptDisable intr_disable;
|
||||
|
||||
m_kernel.CurrentScheduler()->RescheduleCurrentCoreImpl();
|
||||
kernel.CurrentScheduler()->RescheduleCurrentCoreImpl(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void KScheduler::RescheduleCurrentCoreImpl() {
|
||||
void KScheduler::RescheduleCurrentCoreImpl(KernelCore& kernel) {
|
||||
// Check that scheduling is needed.
|
||||
if (m_state.needs_scheduling.load()) [[likely]] {
|
||||
GetCurrentThread(m_kernel).DisableDispatch(m_kernel);
|
||||
Schedule();
|
||||
GetCurrentThread(m_kernel).EnableDispatch(m_kernel);
|
||||
GetCurrentThread(kernel).DisableDispatch(kernel);
|
||||
Schedule(kernel);
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id) {
|
||||
void KScheduler::Initialize(KernelCore& kernel, KThread* main_thread, KThread* idle_thread, s32 core_id) {
|
||||
// Set core ID/idle thread/interrupt task manager.
|
||||
m_core_id = core_id;
|
||||
m_idle_thread = idle_thread;
|
||||
|
|
@ -156,39 +154,39 @@ void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core
|
|||
|
||||
// Insert the main thread into the priority queue.
|
||||
// {
|
||||
// KScopedSchedulerLock lk{m_kernel};
|
||||
// GetPriorityQueue(m_kernel).PushBack(GetCurrentThreadPointer(m_kernel));
|
||||
// SetSchedulerUpdateNeeded(m_kernel);
|
||||
// KScopedSchedulerLock lk{kernel};
|
||||
// GetPriorityQueue(kernel).PushBack(GetCurrentThreadPointer(kernel));
|
||||
// SetSchedulerUpdateNeeded(kernel);
|
||||
// }
|
||||
|
||||
// Bind interrupt handler.
|
||||
// kernel.GetInterruptManager().BindHandler(
|
||||
// GetSchedulerInterruptHandler(m_kernel), KInterruptName::Scheduler, m_core_id,
|
||||
// GetSchedulerInterruptHandler(kernel), KInterruptName::Scheduler, m_core_id,
|
||||
// KInterruptController::PriorityLevel::Scheduler, false, false);
|
||||
|
||||
// Set the current thread.
|
||||
m_current_thread = main_thread;
|
||||
}
|
||||
|
||||
void KScheduler::Activate() {
|
||||
ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
|
||||
void KScheduler::Activate(KernelCore& kernel) {
|
||||
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
|
||||
|
||||
// m_state.should_count_idle = KTargetSystem::IsDebugMode();
|
||||
m_is_active = true;
|
||||
RescheduleCurrentCore();
|
||||
RescheduleCurrentCore(kernel);
|
||||
}
|
||||
|
||||
void KScheduler::OnThreadStart() {
|
||||
GetCurrentThread(m_kernel).EnableDispatch(m_kernel);
|
||||
void KScheduler::OnThreadStart(KernelCore& kernel) {
|
||||
GetCurrentThread(kernel).EnableDispatch(kernel);
|
||||
}
|
||||
|
||||
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
||||
u64 KScheduler::UpdateHighestPriorityThread(KernelCore& kernel, KThread* highest_thread) {
|
||||
if (KThread* prev_highest_thread = m_state.highest_priority_thread;
|
||||
prev_highest_thread != highest_thread) [[likely]] {
|
||||
if (prev_highest_thread != nullptr) [[likely]] {
|
||||
IncrementScheduledCount(prev_highest_thread);
|
||||
prev_highest_thread->SetLastScheduledTick(
|
||||
m_kernel.System().CoreTiming().GetClockTicks());
|
||||
kernel.System().CoreTiming().GetClockTicks());
|
||||
}
|
||||
if (m_state.should_count_idle) {
|
||||
if (highest_thread != nullptr) [[likely]] {
|
||||
|
|
@ -245,8 +243,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
|||
}
|
||||
|
||||
top_threads[core_id] = top_thread;
|
||||
cores_needing_scheduling |=
|
||||
kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]);
|
||||
cores_needing_scheduling |= kernel.Scheduler(core_id).UpdateHighestPriorityThread(kernel, top_threads[core_id]);
|
||||
}
|
||||
|
||||
// Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
|
||||
|
|
@ -274,8 +271,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
|||
suggested->SetActiveCore(core_id);
|
||||
priority_queue.ChangeCore(suggested_core, suggested);
|
||||
top_threads[core_id] = suggested;
|
||||
cores_needing_scheduling |=
|
||||
kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]);
|
||||
cores_needing_scheduling |= kernel.Scheduler(core_id).UpdateHighestPriorityThread(kernel, top_threads[core_id]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -298,17 +294,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
|||
// The candidate core can run some other thread! We'll migrate its current
|
||||
// top thread to us.
|
||||
top_threads[candidate_core] = next_on_candidate_core;
|
||||
cores_needing_scheduling |=
|
||||
kernel.Scheduler(candidate_core)
|
||||
.UpdateHighestPriorityThread(top_threads[candidate_core]);
|
||||
cores_needing_scheduling |= kernel.Scheduler(candidate_core).UpdateHighestPriorityThread(kernel, top_threads[candidate_core]);
|
||||
|
||||
// Perform the migration.
|
||||
suggested->SetActiveCore(core_id);
|
||||
priority_queue.ChangeCore(candidate_core, suggested);
|
||||
top_threads[core_id] = suggested;
|
||||
cores_needing_scheduling |=
|
||||
kernel.Scheduler(core_id).UpdateHighestPriorityThread(
|
||||
top_threads[core_id]);
|
||||
cores_needing_scheduling |= kernel.Scheduler(core_id).UpdateHighestPriorityThread(kernel, top_threads[core_id]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -331,9 +323,9 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
|
|||
return cores_needing_scheduling;
|
||||
}
|
||||
|
||||
void KScheduler::SwitchThread(KThread* next_thread) {
|
||||
KProcess* const cur_process = GetCurrentProcessPointer(m_kernel);
|
||||
KThread* const cur_thread = GetCurrentThreadPointer(m_kernel);
|
||||
void KScheduler::SwitchThread(KernelCore& kernel, KThread* next_thread) {
|
||||
KProcess* const cur_process = GetCurrentProcessPointer(kernel);
|
||||
KThread* const cur_thread = GetCurrentThreadPointer(kernel);
|
||||
|
||||
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
|
||||
if (next_thread == nullptr) {
|
||||
|
|
@ -355,7 +347,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
|
|||
|
||||
// Update the CPU time tracking variables.
|
||||
const s64 prev_tick = m_last_context_switch_time;
|
||||
const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks();
|
||||
const s64 cur_tick = kernel.System().CoreTiming().GetClockTicks();
|
||||
const s64 tick_diff = cur_tick - prev_tick;
|
||||
cur_thread->AddCpuTime(m_core_id, tick_diff);
|
||||
if (cur_process != nullptr) {
|
||||
|
|
@ -379,23 +371,23 @@ void KScheduler::SwitchThread(KThread* next_thread) {
|
|||
// }
|
||||
|
||||
// Set the new thread.
|
||||
SetCurrentThread(m_kernel, next_thread);
|
||||
SetCurrentThread(kernel, next_thread);
|
||||
m_current_thread = next_thread;
|
||||
|
||||
// Set the new Thread Local region.
|
||||
// cpu::SwitchThreadLocalRegion(GetInteger(next_thread->GetThreadLocalRegionAddress()));
|
||||
|
||||
// Update the thread's cpu time differential in TLS, if relevant.
|
||||
next_thread->UpdateTlsThreadCpuTime(m_kernel, cur_tick);
|
||||
next_thread->UpdateTlsThreadCpuTime(kernel, cur_tick);
|
||||
}
|
||||
|
||||
void KScheduler::ScheduleImpl() {
|
||||
void KScheduler::ScheduleImpl(KernelCore& kernel) {
|
||||
// First, clear the needs scheduling bool.
|
||||
m_state.needs_scheduling.store(false, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
|
||||
// Load the appropriate thread pointers for scheduling.
|
||||
KThread* const cur_thread{GetCurrentThreadPointer(m_kernel)};
|
||||
KThread* const cur_thread{GetCurrentThreadPointer(kernel)};
|
||||
KThread* highest_priority_thread{m_state.highest_priority_thread};
|
||||
|
||||
// Check whether there are runnable interrupt tasks.
|
||||
|
|
@ -423,7 +415,7 @@ void KScheduler::ScheduleImpl() {
|
|||
// Returning from ScheduleImpl occurs after this thread has been scheduled again.
|
||||
}
|
||||
|
||||
void KScheduler::ScheduleImplFiber() {
|
||||
void KScheduler::ScheduleImplFiber(KernelCore& kernel) {
|
||||
KThread* const cur_thread{m_switch_cur_thread};
|
||||
KThread* highest_priority_thread{m_switch_highest_priority_thread};
|
||||
|
||||
|
|
@ -437,7 +429,7 @@ void KScheduler::ScheduleImplFiber() {
|
|||
m_switch_from_schedule = false;
|
||||
|
||||
// Save the original thread context.
|
||||
Unload(cur_thread);
|
||||
Unload(kernel, cur_thread);
|
||||
|
||||
// The current thread's context has been entirely taken care of.
|
||||
// Now we want to loop until we successfully switch the thread context.
|
||||
|
|
@ -468,7 +460,7 @@ void KScheduler::ScheduleImplFiber() {
|
|||
|
||||
// It's time to switch the thread.
|
||||
// Switch to the highest priority thread.
|
||||
SwitchThread(highest_priority_thread);
|
||||
SwitchThread(kernel, highest_priority_thread);
|
||||
|
||||
// Check if we need scheduling. If we do, then we can't complete the switch and should
|
||||
// retry.
|
||||
|
|
@ -493,14 +485,14 @@ void KScheduler::ScheduleImplFiber() {
|
|||
}
|
||||
|
||||
// Reload the guest thread context.
|
||||
Reload(highest_priority_thread);
|
||||
Reload(kernel, highest_priority_thread);
|
||||
|
||||
// Reload the host thread.
|
||||
Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->m_host_context);
|
||||
}
|
||||
|
||||
void KScheduler::Unload(KThread* thread) {
|
||||
m_kernel.PhysicalCore(m_core_id).SaveContext(thread);
|
||||
void KScheduler::Unload(KernelCore& kernel, KThread* thread) {
|
||||
kernel.PhysicalCore(m_core_id).SaveContext(thread);
|
||||
|
||||
// Check if the thread is terminated by checking the DPC flags.
|
||||
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
|
||||
|
|
@ -509,8 +501,8 @@ void KScheduler::Unload(KThread* thread) {
|
|||
}
|
||||
}
|
||||
|
||||
void KScheduler::Reload(KThread* thread) {
|
||||
m_kernel.PhysicalCore(m_core_id).LoadContext(thread);
|
||||
void KScheduler::Reload(KernelCore& kernel, KThread* thread) {
|
||||
kernel.PhysicalCore(m_core_id).LoadContext(thread);
|
||||
}
|
||||
|
||||
void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
|
||||
|
|
@ -877,9 +869,9 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
|||
}
|
||||
}
|
||||
|
||||
void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
|
||||
void KScheduler::RescheduleOtherCores(KernelCore& kernel, u64 cores_needing_scheduling) {
|
||||
if (const u64 core_mask = cores_needing_scheduling & ~(1ULL << m_core_id); core_mask != 0) {
|
||||
RescheduleCores(m_kernel, core_mask);
|
||||
RescheduleCores(kernel, core_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -41,15 +44,15 @@ public:
|
|||
explicit KScheduler(KernelCore& kernel);
|
||||
~KScheduler();
|
||||
|
||||
void Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id);
|
||||
void Activate();
|
||||
void OnThreadStart();
|
||||
void Unload(KThread* thread);
|
||||
void Reload(KThread* thread);
|
||||
void Initialize(KernelCore& kernel, KThread* main_thread, KThread* idle_thread, s32 core_id);
|
||||
void Activate(KernelCore& kernel);
|
||||
void OnThreadStart(KernelCore& kernel);
|
||||
void Unload(KernelCore& kernel, KThread* thread);
|
||||
void Reload(KernelCore& kernel, KThread* thread);
|
||||
|
||||
void SetInterruptTaskRunnable();
|
||||
void RequestScheduleOnInterrupt();
|
||||
void PreemptSingleCore();
|
||||
void SetInterruptTaskRunnable(KernelCore& kernel);
|
||||
void RequestScheduleOnInterrupt(KernelCore& kernel);
|
||||
void PreemptSingleCore(KernelCore& kernel);
|
||||
|
||||
u64 GetIdleCount() {
|
||||
return m_state.idle_count;
|
||||
|
|
@ -122,18 +125,18 @@ private:
|
|||
static void RescheduleCurrentHLEThread(KernelCore& kernel);
|
||||
|
||||
// Instanced private API.
|
||||
void ScheduleImpl();
|
||||
void ScheduleImplFiber();
|
||||
void SwitchThread(KThread* next_thread);
|
||||
void ScheduleImpl(KernelCore& kernel);
|
||||
void ScheduleImplFiber(KernelCore& kernel);
|
||||
void SwitchThread(KernelCore& kernel, KThread* next_thread);
|
||||
|
||||
void Schedule();
|
||||
void ScheduleOnInterrupt();
|
||||
void Schedule(KernelCore& kernel);
|
||||
void ScheduleOnInterrupt(KernelCore& kernel);
|
||||
|
||||
void RescheduleOtherCores(u64 cores_needing_scheduling);
|
||||
void RescheduleCurrentCore();
|
||||
void RescheduleCurrentCoreImpl();
|
||||
void RescheduleOtherCores(KernelCore& kernel, u64 cores_needing_scheduling);
|
||||
void RescheduleCurrentCore(KernelCore& kernel);
|
||||
void RescheduleCurrentCoreImpl(KernelCore& kernel);
|
||||
|
||||
u64 UpdateHighestPriorityThread(KThread* thread);
|
||||
u64 UpdateHighestPriorityThread(KernelCore& kernel, KThread* thread);
|
||||
|
||||
private:
|
||||
friend class KScopedDisableDispatch;
|
||||
|
|
@ -149,14 +152,12 @@ private:
|
|||
KInterruptTaskManager* interrupt_task_manager{nullptr};
|
||||
};
|
||||
|
||||
KernelCore& m_kernel;
|
||||
SchedulingState m_state;
|
||||
bool m_is_active{false};
|
||||
s32 m_core_id{0};
|
||||
s64 m_last_context_switch_time{0};
|
||||
KThread* m_idle_thread{nullptr};
|
||||
std::atomic<KThread*> m_current_thread{nullptr};
|
||||
|
||||
std::shared_ptr<Common::Fiber> m_switch_fiber{};
|
||||
KThread* m_switch_cur_thread{};
|
||||
KThread* m_switch_highest_priority_thread{};
|
||||
|
|
|
|||
|
|
@ -287,37 +287,27 @@ namespace Kernel {
|
|||
}
|
||||
|
||||
Result KThread::InitializeMainThread(Core::System& system, KThread* thread, s32 virt_core) {
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, {}, {}, {}, IdleThreadPriority, virt_core, {},
|
||||
ThreadType::Main, system.GetCpuManager().GetGuestActivateFunc()));
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, system.GetCpuManager().GetGuestActivateFunc(system.Kernel())));
|
||||
}
|
||||
|
||||
Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, {}, {}, {}, IdleThreadPriority, virt_core, {},
|
||||
ThreadType::Main, system.GetCpuManager().GetIdleThreadStartFunc()));
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main, system.GetCpuManager().GetIdleThreadStartFunc(system.Kernel())));
|
||||
}
|
||||
|
||||
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
|
||||
KThreadFunction func, uintptr_t arg, s32 virt_core) {
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, func, arg, {}, {}, virt_core, nullptr,
|
||||
ThreadType::HighPriority,
|
||||
system.GetCpuManager().GetShutdownThreadStartFunc()));
|
||||
Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread, KThreadFunction func, uintptr_t arg, s32 virt_core) {
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority, system.GetCpuManager().GetShutdownThreadStartFunc(system.Kernel())));
|
||||
}
|
||||
|
||||
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
|
||||
uintptr_t arg, KProcessAddress user_stack_top, s32 prio,
|
||||
s32 virt_core, KProcess* owner) {
|
||||
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess* owner) {
|
||||
system.Kernel().GlobalSchedulerContext().AddThread(thread);
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, func, arg, user_stack_top, prio, virt_core, owner,
|
||||
ThreadType::User, system.GetCpuManager().GetGuestThreadFunc()));
|
||||
R_RETURN(InitializeThread(system.Kernel(), thread, func, arg, user_stack_top, prio, virt_core, owner, ThreadType::User, system.GetCpuManager().GetGuestThreadFunc(system.Kernel())));
|
||||
}
|
||||
|
||||
Result KThread::InitializeServiceThread(Core::System& system, KThread* thread,
|
||||
std::function<void()>&& func, s32 prio, s32 virt_core,
|
||||
KProcess* owner) {
|
||||
Result KThread::InitializeServiceThread(Core::System& system, KThread* thread, std::function<void()>&& func, s32 prio, s32 virt_core, KProcess* owner) {
|
||||
system.Kernel().GlobalSchedulerContext().AddThread(thread);
|
||||
std::function<void()> func2{[&system, func_{std::move(func)}] {
|
||||
// Similar to UserModeThreadStarter.
|
||||
system.Kernel().CurrentScheduler()->OnThreadStart();
|
||||
system.Kernel().CurrentScheduler()->OnThreadStart(system.Kernel());
|
||||
|
||||
// Run the guest function.
|
||||
func_();
|
||||
|
|
@ -1449,7 +1439,7 @@ namespace Kernel {
|
|||
auto* scheduler = m_kernel.CurrentScheduler();
|
||||
|
||||
if (scheduler && !m_kernel.IsPhantomModeForSingleCore()) {
|
||||
scheduler->RescheduleCurrentCore();
|
||||
scheduler->RescheduleCurrentCore(m_kernel);
|
||||
} else {
|
||||
KScheduler::RescheduleCurrentHLEThread(m_kernel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class KHardwareTimer;
|
|||
|
||||
class KThreadQueue {
|
||||
public:
|
||||
explicit KThreadQueue(KernelCore& kernel) : m_kernel{kernel}, m_hardware_timer{} {}
|
||||
explicit KThreadQueue(KernelCore& kernel) : m_hardware_timer{} {}
|
||||
virtual ~KThreadQueue() = default;
|
||||
|
||||
void SetHardwareTimer(KHardwareTimer* timer) {
|
||||
|
|
@ -27,7 +27,6 @@ public:
|
|||
virtual void CancelWait(KernelCore& kernel, KThread* waiting_thread, Result wait_result, bool cancel_timer_task);
|
||||
|
||||
private:
|
||||
KernelCore& m_kernel;
|
||||
KHardwareTimer* m_hardware_timer{};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ struct KernelCore::Impl {
|
|||
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess());
|
||||
KThread::Register(system.Kernel(), idle_thread);
|
||||
|
||||
schedulers[i]->Initialize(main_thread, idle_thread, core);
|
||||
schedulers[i]->Initialize(system.Kernel(), main_thread, idle_thread, core);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue