hle: kernel: k_scheduler: Use atomics for current_thread, etc.
This commit is contained in:
parent
f6b10fad63
commit
37f74d8741
2 changed files with 28 additions and 26 deletions
|
@ -80,7 +80,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
||||||
}
|
}
|
||||||
|
|
||||||
state.highest_priority_thread = highest_thread;
|
state.highest_priority_thread = highest_thread;
|
||||||
state.needs_scheduling = true;
|
state.needs_scheduling.store(true);
|
||||||
return (1ULL << core_id);
|
return (1ULL << core_id);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -609,7 +609,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
|
||||||
|
|
||||||
KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
|
KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
|
||||||
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
|
||||||
state.needs_scheduling = true;
|
state.needs_scheduling.store(true);
|
||||||
state.interrupt_task_thread_runnable = false;
|
state.interrupt_task_thread_runnable = false;
|
||||||
state.should_count_idle = false;
|
state.should_count_idle = false;
|
||||||
state.idle_count = 0;
|
state.idle_count = 0;
|
||||||
|
@ -620,10 +620,10 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core
|
||||||
KScheduler::~KScheduler() = default;
|
KScheduler::~KScheduler() = default;
|
||||||
|
|
||||||
KThread* KScheduler::GetCurrentThread() const {
|
KThread* KScheduler::GetCurrentThread() const {
|
||||||
if (current_thread) {
|
if (auto result = current_thread.load(); result) {
|
||||||
return current_thread;
|
return result;
|
||||||
}
|
}
|
||||||
return idle_thread;
|
return idle_thread.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KScheduler::GetLastContextSwitchTicks() const {
|
u64 KScheduler::GetLastContextSwitchTicks() const {
|
||||||
|
@ -638,7 +638,7 @@ void KScheduler::RescheduleCurrentCore() {
|
||||||
phys_core.ClearInterrupt();
|
phys_core.ClearInterrupt();
|
||||||
}
|
}
|
||||||
guard.lock();
|
guard.lock();
|
||||||
if (state.needs_scheduling) {
|
if (state.needs_scheduling.load()) {
|
||||||
Schedule();
|
Schedule();
|
||||||
} else {
|
} else {
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
|
@ -695,29 +695,29 @@ void KScheduler::Reload(KThread* thread) {
|
||||||
|
|
||||||
void KScheduler::SwitchContextStep2() {
|
void KScheduler::SwitchContextStep2() {
|
||||||
// Load context of new thread
|
// Load context of new thread
|
||||||
Reload(current_thread);
|
Reload(current_thread.load());
|
||||||
|
|
||||||
RescheduleCurrentCore();
|
RescheduleCurrentCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void KScheduler::ScheduleImpl() {
|
void KScheduler::ScheduleImpl() {
|
||||||
KThread* previous_thread = current_thread;
|
KThread* previous_thread = current_thread.load();
|
||||||
KThread* next_thread = state.highest_priority_thread;
|
KThread* next_thread = state.highest_priority_thread;
|
||||||
|
|
||||||
state.needs_scheduling = false;
|
state.needs_scheduling = false;
|
||||||
|
|
||||||
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
|
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
|
||||||
if (next_thread == nullptr) {
|
if (next_thread == nullptr) {
|
||||||
next_thread = idle_thread;
|
next_thread = idle_thread.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not actually switching thread, there's nothing to do.
|
// If we're not actually switching thread, there's nothing to do.
|
||||||
if (next_thread == current_thread) {
|
if (next_thread == current_thread.load()) {
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_thread = next_thread;
|
current_thread.store(next_thread);
|
||||||
|
|
||||||
Process* const previous_process = system.Kernel().CurrentProcess();
|
Process* const previous_process = system.Kernel().CurrentProcess();
|
||||||
|
|
||||||
|
@ -749,28 +749,29 @@ void KScheduler::SwitchToCurrent() {
|
||||||
while (true) {
|
while (true) {
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{guard};
|
std::scoped_lock lock{guard};
|
||||||
current_thread = state.highest_priority_thread;
|
current_thread.store(state.highest_priority_thread);
|
||||||
state.needs_scheduling = false;
|
state.needs_scheduling.store(false);
|
||||||
}
|
}
|
||||||
const auto is_switch_pending = [this] {
|
const auto is_switch_pending = [this] {
|
||||||
std::scoped_lock lock{guard};
|
std::scoped_lock lock{guard};
|
||||||
return state.needs_scheduling.load(std::memory_order_relaxed);
|
return state.needs_scheduling.load();
|
||||||
};
|
};
|
||||||
do {
|
do {
|
||||||
if (current_thread != nullptr) {
|
auto next_thread = current_thread.load();
|
||||||
current_thread->context_guard.lock();
|
if (next_thread != nullptr) {
|
||||||
if (current_thread->GetRawState() != ThreadState::Runnable) {
|
next_thread->context_guard.lock();
|
||||||
current_thread->context_guard.unlock();
|
if (next_thread->GetRawState() != ThreadState::Runnable) {
|
||||||
|
next_thread->context_guard.unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (current_thread->GetActiveCore() != core_id) {
|
if (next_thread->GetActiveCore() != core_id) {
|
||||||
current_thread->context_guard.unlock();
|
next_thread->context_guard.unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::shared_ptr<Common::Fiber>* next_context;
|
std::shared_ptr<Common::Fiber>* next_context;
|
||||||
if (current_thread != nullptr) {
|
if (next_thread != nullptr) {
|
||||||
next_context = ¤t_thread->GetHostContext();
|
next_context = &next_thread->GetHostContext();
|
||||||
} else {
|
} else {
|
||||||
next_context = &idle_thread->GetHostContext();
|
next_context = &idle_thread->GetHostContext();
|
||||||
}
|
}
|
||||||
|
@ -802,7 +803,7 @@ void KScheduler::Initialize() {
|
||||||
auto thread_res = KThread::Create(system, ThreadType::Main, name, 0,
|
auto thread_res = KThread::Create(system, ThreadType::Main, name, 0,
|
||||||
KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
|
KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
|
||||||
nullptr, std::move(init_func), init_func_parameter);
|
nullptr, std::move(init_func), init_func_parameter);
|
||||||
idle_thread = thread_res.Unwrap().get();
|
idle_thread = thread_res.Unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
|
KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
|
|
||||||
/// Returns true if the scheduler is idle
|
/// Returns true if the scheduler is idle
|
||||||
[[nodiscard]] bool IsIdle() const {
|
[[nodiscard]] bool IsIdle() const {
|
||||||
return GetCurrentThread() == idle_thread;
|
return GetCurrentThread() == idle_thread.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the timestamp for the last context switch in ticks.
|
/// Gets the timestamp for the last context switch in ticks.
|
||||||
|
@ -174,8 +174,9 @@ private:
|
||||||
void SwitchToCurrent();
|
void SwitchToCurrent();
|
||||||
|
|
||||||
KThread* prev_thread{};
|
KThread* prev_thread{};
|
||||||
KThread* current_thread{};
|
std::atomic<KThread*> current_thread{};
|
||||||
KThread* idle_thread{};
|
|
||||||
|
std::shared_ptr<KThread> idle_thread;
|
||||||
|
|
||||||
std::shared_ptr<Common::Fiber> switch_fiber{};
|
std::shared_ptr<Common::Fiber> switch_fiber{};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue