2022-04-23 04:59:50 -04:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2018-02-18 14:58:40 -05:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2019-12-07 22:09:20 -05:00
|
|
|
#include <atomic>
|
|
|
|
|
2018-02-18 14:58:40 -05:00
|
|
|
#include "common/common_types.h"
|
2020-12-03 19:43:18 -05:00
|
|
|
#include "core/hle/kernel/global_scheduler_context.h"
|
2020-12-02 21:08:35 -05:00
|
|
|
#include "core/hle/kernel/k_priority_queue.h"
|
|
|
|
#include "core/hle/kernel/k_scheduler_lock.h"
|
2020-12-04 01:26:42 -05:00
|
|
|
#include "core/hle/kernel/k_scoped_lock.h"
|
2021-02-13 04:29:32 -05:00
|
|
|
#include "core/hle/kernel/k_spin_lock.h"
|
2022-06-26 18:52:16 -04:00
|
|
|
#include "core/hle/kernel/k_thread.h"
|
2018-02-18 14:58:40 -05:00
|
|
|
|
2020-03-06 08:52:24 -05:00
|
|
|
namespace Common {
|
2020-03-08 12:51:24 -04:00
|
|
|
class Fiber;
|
2020-03-06 08:52:24 -05:00
|
|
|
}
|
|
|
|
|
2018-08-24 21:43:32 -04:00
|
|
|
namespace Core {
|
2019-03-04 16:02:59 -05:00
|
|
|
class System;
|
2020-12-03 19:43:18 -05:00
|
|
|
}
|
2018-07-31 08:06:09 -04:00
|
|
|
|
2018-02-18 14:58:40 -05:00
|
|
|
namespace Kernel {
|
|
|
|
|
2020-02-13 21:04:10 -05:00
|
|
|
class KernelCore;
|
2022-06-26 18:52:16 -04:00
|
|
|
class KInterruptTaskManager;
|
2021-04-24 01:04:28 -04:00
|
|
|
class KProcess;
|
2020-12-31 02:01:08 -05:00
|
|
|
class KThread;
|
2022-06-26 18:52:16 -04:00
|
|
|
class KScopedDisableDispatch;
|
|
|
|
class KScopedSchedulerLock;
|
|
|
|
class KScopedSchedulerLockAndSleep;
|
2019-03-29 17:01:17 -04:00
|
|
|
|
2020-12-02 21:08:35 -05:00
|
|
|
class KScheduler final {
|
2019-03-29 17:01:17 -04:00
|
|
|
public:
|
2022-06-26 18:52:16 -04:00
|
|
|
YUZU_NON_COPYABLE(KScheduler);
|
|
|
|
YUZU_NON_MOVEABLE(KScheduler);
|
2021-08-07 01:58:46 -04:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
using LockType = KAbstractSchedulerLock<KScheduler>;
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
explicit KScheduler(KernelCore& kernel);
|
|
|
|
~KScheduler();
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-07-05 23:27:25 -04:00
|
|
|
void Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id);
|
2022-06-26 18:52:16 -04:00
|
|
|
void Activate();
|
2022-07-05 23:27:25 -04:00
|
|
|
void OnThreadStart();
|
|
|
|
void Unload(KThread* thread);
|
|
|
|
void Reload(KThread* thread);
|
2020-03-10 11:50:33 -04:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
void SetInterruptTaskRunnable();
|
|
|
|
void RequestScheduleOnInterrupt();
|
2022-07-07 12:34:46 -04:00
|
|
|
void PreemptSingleCore();
|
2019-03-29 17:01:17 -04:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
u64 GetIdleCount() {
|
|
|
|
return m_state.idle_count;
|
2021-10-16 05:54:09 -04:00
|
|
|
}
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
KThread* GetIdleThread() const {
|
|
|
|
return m_idle_thread;
|
2022-06-30 16:54:05 -04:00
|
|
|
}
|
|
|
|
|
2022-07-05 23:27:25 -04:00
|
|
|
bool IsIdle() const {
|
|
|
|
return m_current_thread.load() == m_idle_thread;
|
|
|
|
}
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
KThread* GetPreviousThread() const {
|
|
|
|
return m_state.prev_thread;
|
2019-03-29 17:01:17 -04:00
|
|
|
}
|
2018-02-18 14:58:40 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
KThread* GetSchedulerCurrentThread() const {
|
|
|
|
return m_current_thread.load();
|
2020-03-10 11:50:33 -04:00
|
|
|
}
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
s64 GetLastContextSwitchTime() const {
|
|
|
|
return m_last_context_switch_time;
|
2020-06-27 18:20:06 -04:00
|
|
|
}
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
// Static public API.
|
|
|
|
static bool CanSchedule(KernelCore& kernel) {
|
2022-07-05 23:27:25 -04:00
|
|
|
return GetCurrentThread(kernel).GetDisableDispatchCount() == 0;
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
|
|
|
static bool IsSchedulerLockedByCurrentThread(KernelCore& kernel) {
|
2023-03-06 19:45:40 -05:00
|
|
|
return kernel.GlobalSchedulerContext().m_scheduler_lock.IsLockedByCurrentThread();
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
static bool IsSchedulerUpdateNeeded(KernelCore& kernel) {
|
2023-03-06 19:45:40 -05:00
|
|
|
return kernel.GlobalSchedulerContext().m_scheduler_update_needed;
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
|
|
|
static void SetSchedulerUpdateNeeded(KernelCore& kernel) {
|
2023-03-06 19:45:40 -05:00
|
|
|
kernel.GlobalSchedulerContext().m_scheduler_update_needed = true;
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
|
|
|
static void ClearSchedulerUpdateNeeded(KernelCore& kernel) {
|
2023-03-06 19:45:40 -05:00
|
|
|
kernel.GlobalSchedulerContext().m_scheduler_update_needed = false;
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
static void DisableScheduling(KernelCore& kernel);
|
|
|
|
static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling);
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
static u64 UpdateHighestPriorityThreads(KernelCore& kernel);
|
2021-01-20 16:42:27 -05:00
|
|
|
|
|
|
|
static void ClearPreviousThread(KernelCore& kernel, KThread* thread);
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2020-12-31 02:01:08 -05:00
|
|
|
static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state);
|
|
|
|
static void OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority);
|
|
|
|
static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread,
|
2020-12-02 21:08:35 -05:00
|
|
|
const KAffinityMask& old_affinity, s32 old_core);
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
static void RotateScheduledQueue(KernelCore& kernel, s32 core_id, s32 priority);
|
|
|
|
static void RescheduleCores(KernelCore& kernel, u64 cores_needing_scheduling);
|
2020-12-05 03:02:30 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
static void YieldWithoutCoreMigration(KernelCore& kernel);
|
|
|
|
static void YieldWithCoreMigration(KernelCore& kernel);
|
|
|
|
static void YieldToAnyThread(KernelCore& kernel);
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
private:
|
|
|
|
// Static private API.
|
|
|
|
static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel) {
|
2023-03-06 19:45:40 -05:00
|
|
|
return kernel.GlobalSchedulerContext().m_priority_queue;
|
2022-06-26 18:52:16 -04:00
|
|
|
}
|
|
|
|
static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel);
|
2019-10-27 22:01:45 -04:00
|
|
|
|
2022-07-11 10:13:13 -04:00
|
|
|
static void RescheduleCurrentHLEThread(KernelCore& kernel);
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
// Instanced private API.
|
2020-12-02 21:08:35 -05:00
|
|
|
void ScheduleImpl();
|
2022-07-05 23:27:25 -04:00
|
|
|
void ScheduleImplFiber();
|
2022-06-26 18:52:16 -04:00
|
|
|
void SwitchThread(KThread* next_thread);
|
2018-02-18 14:58:40 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
void Schedule();
|
|
|
|
void ScheduleOnInterrupt();
|
2020-03-06 08:52:24 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
void RescheduleOtherCores(u64 cores_needing_scheduling);
|
|
|
|
void RescheduleCurrentCore();
|
|
|
|
void RescheduleCurrentCoreImpl();
|
2021-01-21 14:26:00 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
u64 UpdateHighestPriorityThread(KThread* thread);
|
2020-12-02 21:08:35 -05:00
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
private:
|
|
|
|
friend class KScopedDisableDispatch;
|
2018-02-18 14:58:40 -05:00
|
|
|
|
2020-12-02 21:08:35 -05:00
|
|
|
struct SchedulingState {
|
2022-06-26 18:52:16 -04:00
|
|
|
std::atomic<bool> needs_scheduling{false};
|
|
|
|
bool interrupt_task_runnable{false};
|
|
|
|
bool should_count_idle{false};
|
|
|
|
u64 idle_count{0};
|
|
|
|
KThread* highest_priority_thread{nullptr};
|
|
|
|
void* idle_thread_stack{nullptr};
|
|
|
|
std::atomic<KThread*> prev_thread{nullptr};
|
|
|
|
KInterruptTaskManager* interrupt_task_manager{nullptr};
|
2020-12-02 21:08:35 -05:00
|
|
|
};
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
KernelCore& 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};
|
|
|
|
|
2022-07-05 23:27:25 -04:00
|
|
|
std::shared_ptr<Common::Fiber> m_switch_fiber{};
|
|
|
|
KThread* m_switch_cur_thread{};
|
|
|
|
KThread* m_switch_highest_priority_thread{};
|
|
|
|
bool m_switch_from_schedule{};
|
2018-02-18 14:58:40 -05:00
|
|
|
};
|
|
|
|
|
2022-06-26 18:52:16 -04:00
|
|
|
class KScopedSchedulerLock : public KScopedLock<KScheduler::LockType> {
|
2020-02-14 10:44:31 -05:00
|
|
|
public:
|
2022-06-26 18:52:16 -04:00
|
|
|
explicit KScopedSchedulerLock(KernelCore& kernel)
|
2023-03-06 19:45:40 -05:00
|
|
|
: KScopedLock(kernel.GlobalSchedulerContext().m_scheduler_lock) {}
|
2022-06-26 18:52:16 -04:00
|
|
|
~KScopedSchedulerLock() = default;
|
2020-02-14 10:44:31 -05:00
|
|
|
};
|
|
|
|
|
2018-02-18 14:58:40 -05:00
|
|
|
} // namespace Kernel
|