From c0d3aef28c0a0c68c18de30228f29e30f0e52533 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 30 Dec 2020 23:01:08 -0800 Subject: core: hle: kernel: Rename Thread to KThread. --- src/core/hle/kernel/k_scheduler.cpp | 70 ++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 12b5619fb..0f7a541c8 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -17,15 +17,15 @@ #include "core/cpu_manager.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { -static void IncrementScheduledCount(Kernel::Thread* thread) { +static void IncrementScheduledCount(Kernel::KThread* thread) { if (auto process = thread->GetOwnerProcess(); process) { process->IncrementScheduledCount(); } @@ -56,9 +56,9 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul } } -u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) { +u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { std::scoped_lock lock{guard}; - if (Thread* prev_highest_thread = this->state.highest_priority_thread; + if (KThread* prev_highest_thread = this->state.highest_priority_thread; prev_highest_thread != highest_thread) { if (prev_highest_thread != nullptr) { IncrementScheduledCount(prev_highest_thread); @@ -90,13 +90,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { ClearSchedulerUpdateNeeded(kernel); u64 cores_needing_scheduling = 0, idle_cores = 0; - Thread* top_threads[Core::Hardware::NUM_CPU_CORES]; + KThread* top_threads[Core::Hardware::NUM_CPU_CORES]; auto& priority_queue = GetPriorityQueue(kernel); /// We want to go over all cores, finding the highest priority thread and determining if /// scheduling is needed for that core. for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - Thread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); + KThread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); if (top_thread != nullptr) { // If the thread has no waiters, we need to check if the process has a thread pinned. // TODO(bunnei): Implement thread pinning @@ -112,7 +112,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. while (idle_cores != 0) { const auto core_id = static_cast(std::countr_zero(idle_cores)); - if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { + if (KThread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; size_t num_candidates = 0; @@ -120,7 +120,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (Thread* top_thread = + if (KThread* top_thread = (suggested_core >= 0) ? top_threads[suggested_core] : nullptr; top_thread != suggested) { // Make sure we're not dealing with threads too high priority for migration. @@ -152,7 +152,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { // Check if there's some other thread that can run on the candidate core. const s32 candidate_core = migration_candidates[i]; suggested = top_threads[candidate_core]; - if (Thread* next_on_candidate_core = + if (KThread* next_on_candidate_core = priority_queue.GetScheduledNext(candidate_core, suggested); next_on_candidate_core != nullptr) { // The candidate core can run some other thread! We'll migrate its current @@ -182,7 +182,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { return cores_needing_scheduling; } -void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) { +void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Check if the state has changed, because if it hasn't there's nothing to do. @@ -205,7 +205,7 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, Thread } } -void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) { +void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // If the thread is runnable, we want to change its priority in the queue. @@ -217,7 +217,7 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 } } -void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread, +void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread, const KAffinityMask& old_affinity, s32 old_core) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -237,8 +237,8 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { auto& priority_queue = GetPriorityQueue(kernel); // Rotate the front of the queue to the end. - Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority); - Thread* next_thread = nullptr; + KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); + KThread* next_thread = nullptr; if (top_thread != nullptr) { next_thread = priority_queue.MoveToScheduledBack(top_thread); if (next_thread != top_thread) { @@ -249,11 +249,11 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // While we have a suggested thread, try to migrate it! { - Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority); + KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority); while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -285,7 +285,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // Now that we might have migrated a thread with the same priority, check if we can do better. { - Thread* best_thread = priority_queue.GetScheduledFront(core_id); + KThread* best_thread = priority_queue.GetScheduledFront(core_id); if (best_thread == GetCurrentThread()) { best_thread = priority_queue.GetScheduledNext(core_id, best_thread); } @@ -293,7 +293,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // If the best thread we can choose has a priority the same or worse than ours, try to // migrate a higher priority thread. if (best_thread != nullptr && best_thread->GetPriority() >= priority) { - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { // If the suggestion's priority is the same as ours, don't bother. if (suggested->GetPriority() >= best_thread->GetPriority()) { @@ -302,7 +302,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -380,7 +380,7 @@ void KScheduler::YieldWithoutCoreMigration() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -398,7 +398,7 @@ void KScheduler::YieldWithoutCoreMigration() { const auto cur_state = cur_thread.GetRawState(); if (cur_state == ThreadState::Runnable) { // Put the current thread at the back of the queue. - Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); + KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); IncrementScheduledCount(std::addressof(cur_thread)); // If the next thread is different, we have an update to perform. @@ -421,7 +421,7 @@ void KScheduler::YieldWithCoreMigration() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -442,17 +442,17 @@ void KScheduler::YieldWithCoreMigration() { const s32 core_id = cur_thread.GetActiveCore(); // Put the current thread at the back of the queue. - Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); + KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread)); IncrementScheduledCount(std::addressof(cur_thread)); // While we have a suggested thread, try to migrate it! bool recheck = false; - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { // Check if the suggested thread is the thread running on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (Thread* running_on_suggested_core = + if (KThread* running_on_suggested_core = (suggested_core >= 0) ? kernel.Scheduler(suggested_core).state.highest_priority_thread : nullptr; @@ -511,7 +511,7 @@ void KScheduler::YieldToAnyThread() { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - Thread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = *GetCurrentThread(); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -539,11 +539,11 @@ void KScheduler::YieldToAnyThread() { // If there's nothing scheduled, we can try to perform a migration. if (priority_queue.GetScheduledFront(core_id) == nullptr) { // While we have a suggested thread, try to migrate it! - Thread* suggested = priority_queue.GetSuggestedFront(core_id); + KThread* suggested = priority_queue.GetSuggestedFront(core_id); while (suggested != nullptr) { // Check if the suggested thread is the top thread on its core. const s32 suggested_core = suggested->GetActiveCore(); - if (Thread* top_on_suggested_core = + if (KThread* top_on_suggested_core = (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core) : nullptr; top_on_suggested_core != suggested) { @@ -594,7 +594,7 @@ KScheduler::KScheduler(Core::System& system, std::size_t core_id) KScheduler::~KScheduler() = default; -Thread* KScheduler::GetCurrentThread() const { +KThread* KScheduler::GetCurrentThread() const { if (current_thread) { return current_thread; } @@ -624,7 +624,7 @@ void KScheduler::OnThreadStart() { SwitchContextStep2(); } -void KScheduler::Unload(Thread* thread) { +void KScheduler::Unload(KThread* thread) { if (thread) { thread->SetIsRunning(false); if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { @@ -643,7 +643,7 @@ void KScheduler::Unload(Thread* thread) { } } -void KScheduler::Reload(Thread* thread) { +void KScheduler::Reload(KThread* thread) { if (thread) { ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); @@ -674,7 +674,7 @@ void KScheduler::SwitchContextStep2() { } void KScheduler::ScheduleImpl() { - Thread* previous_thread = current_thread; + KThread* previous_thread = current_thread; current_thread = state.highest_priority_thread; this->state.needs_scheduling = false; @@ -744,7 +744,7 @@ void KScheduler::SwitchToCurrent() { } } -void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { +void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; @@ -765,8 +765,8 @@ void KScheduler::Initialize() { std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); ThreadType type = static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); - auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, - nullptr, std::move(init_func), init_func_parameter); + auto thread_res = KThread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, + nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); { -- cgit v1.2.3 From eea346ba8eed49111d34e2fb1eee8a1ad53c4614 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 31 Dec 2020 00:46:09 -0800 Subject: hle: kernel: KThread: Remove thread types that do not exist. --- src/core/hle/kernel/k_scheduler.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 0f7a541c8..edc5df733 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -627,11 +627,11 @@ void KScheduler::OnThreadStart() { void KScheduler::Unload(KThread* thread) { if (thread) { thread->SetIsRunning(false); - if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) { + if (thread->IsContinuousOnSVC()) { system.ArmInterface(core_id).ExceptionalExit(); thread->SetContinuousOnSVC(false); } - if (!thread->IsHLEThread() && !thread->HasExited()) { + if (!thread->HasExited()) { Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(thread->GetContext32()); cpu_core.SaveContext(thread->GetContext64()); @@ -655,14 +655,13 @@ void KScheduler::Reload(KThread* thread) { if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } - if (!thread->IsHLEThread()) { - Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); - cpu_core.LoadContext(thread->GetContext32()); - cpu_core.LoadContext(thread->GetContext64()); - cpu_core.SetTlsAddress(thread->GetTLSAddress()); - cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ClearExclusiveState(); - } + + Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(thread->GetContext32()); + cpu_core.LoadContext(thread->GetContext64()); + cpu_core.SetTlsAddress(thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); } } @@ -722,7 +721,7 @@ void KScheduler::SwitchToCurrent() { return state.needs_scheduling.load(std::memory_order_relaxed); }; do { - if (current_thread != nullptr && !current_thread->IsHLEThread()) { + if (current_thread != nullptr) { current_thread->context_guard.lock(); if (current_thread->GetRawState() != ThreadState::Runnable) { current_thread->context_guard.unlock(); @@ -764,9 +763,9 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - ThreadType type = static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); - auto thread_res = KThread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, - nullptr, std::move(init_func), init_func_parameter); + auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, name, 0, THREADPRIO_LOWEST, 0, + static_cast(core_id), 0, nullptr, std::move(init_func), + init_func_parameter); idle_thread = thread_res.Unwrap().get(); { -- cgit v1.2.3 From 0530292b9768637aa6e2875e931c1066af4aa80e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 1 Jan 2021 01:04:30 -0800 Subject: hle: kernel: KThread: Fix ThreadType definition. --- src/core/hle/kernel/k_scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index edc5df733..0f34a8a69 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -763,7 +763,7 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, name, 0, THREADPRIO_LOWEST, 0, + auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, THREADPRIO_LOWEST, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); -- cgit v1.2.3 From 1e55498110800623c63e3ef03bfbff6b6de1c522 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 1 Jan 2021 02:06:06 -0800 Subject: hle: kernel: KThread: Reorganize thread priority defaults. --- src/core/hle/kernel/k_scheduler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 0f34a8a69..0e6300760 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -763,9 +763,9 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, THREADPRIO_LOWEST, 0, - static_cast(core_id), 0, nullptr, std::move(init_func), - init_func_parameter); + auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, + Svc::LowestThreadPriority, 0, static_cast(core_id), 0, + nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); { -- cgit v1.2.3 From 4dbf3f4880cac69db21cc8f18582814dc986c854 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 3 Jan 2021 01:49:18 -0800 Subject: hle: kernel: KThread: Clean up thread priorities. --- src/core/hle/kernel/k_scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 0e6300760..233022023 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -764,7 +764,7 @@ void KScheduler::Initialize() { std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, - Svc::LowestThreadPriority, 0, static_cast(core_id), 0, + KThread::IdleThreadPriority, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); -- cgit v1.2.3 From cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 20 Jan 2021 13:42:27 -0800 Subject: hle: kernel: Recode implementation of KThread to be more accurate. --- src/core/hle/kernel/k_scheduler.cpp | 144 ++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 63 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 233022023..5bdbd9a9b 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -31,11 +31,15 @@ static void IncrementScheduledCount(Kernel::KThread* thread) { } } -void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, - Core::EmuThreadHandle global_thread) { - const u32 current_core = global_thread.host_handle; - bool must_context_switch = global_thread.guest_handle != InvalidHandle && - (current_core < Core::Hardware::NUM_CPU_CORES); +void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule) { + auto scheduler = kernel.CurrentScheduler(); + + u32 current_core{0xF}; + bool must_context_switch{}; + if (scheduler) { + current_core = scheduler->core_id; + must_context_switch = true; + } while (cores_pending_reschedule != 0) { const auto core = static_cast(std::countr_zero(cores_pending_reschedule)); @@ -58,26 +62,25 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { std::scoped_lock lock{guard}; - if (KThread* prev_highest_thread = this->state.highest_priority_thread; + if (KThread* prev_highest_thread = state.highest_priority_thread; prev_highest_thread != highest_thread) { if (prev_highest_thread != nullptr) { IncrementScheduledCount(prev_highest_thread); prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks()); } - if (this->state.should_count_idle) { + if (state.should_count_idle) { if (highest_thread != nullptr) { - // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { - // process->SetRunningThread(this->core_id, highest_thread, - // this->state.idle_count); - //} + if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { + process->SetRunningThread(core_id, highest_thread, state.idle_count); + } } else { - this->state.idle_count++; + state.idle_count++; } } - this->state.highest_priority_thread = highest_thread; - this->state.needs_scheduling = true; - return (1ULL << this->core_id); + state.highest_priority_thread = highest_thread; + state.needs_scheduling = true; + return (1ULL << core_id); } else { return 0; } @@ -99,7 +102,20 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { KThread* top_thread = priority_queue.GetScheduledFront(static_cast(core_id)); if (top_thread != nullptr) { // If the thread has no waiters, we need to check if the process has a thread pinned. - // TODO(bunnei): Implement thread pinning + if (top_thread->GetNumKernelWaiters() == 0) { + if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { + if (KThread* pinned = parent->GetPinnedThread(static_cast(core_id)); + pinned != nullptr && pinned != top_thread) { + // We prefer our parent's pinned thread if possible. However, we also don't + // want to schedule un-runnable threads. + if (pinned->GetRawState() == ThreadState::Runnable) { + top_thread = pinned; + } else { + top_thread = nullptr; + } + } + } + } } else { idle_cores |= (1ULL << core_id); } @@ -182,6 +198,19 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { return cores_needing_scheduling; } +void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) { + // Get an atomic reference to the core scheduler's previous thread. + std::atomic_ref prev_thread(kernel.Scheduler(static_cast(i)).prev_thread); + static_assert(std::atomic_ref::is_always_lock_free); + + // Atomically clear the previous thread if it's our target. + KThread* compare = thread; + prev_thread.compare_exchange_strong(compare, nullptr); + } +} + void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); @@ -352,12 +381,14 @@ void KScheduler::DisableScheduling(KernelCore& kernel) { } } -void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling, - Core::EmuThreadHandle global_thread) { +void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { - scheduler->GetCurrentThread()->EnableDispatch(); + ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); + if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { + scheduler->GetCurrentThread()->EnableDispatch(); + } } - RescheduleCores(kernel, cores_needing_scheduling, global_thread); + RescheduleCores(kernel, cores_needing_scheduling); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { @@ -372,15 +403,13 @@ KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) { return kernel.GlobalSchedulerContext().priority_queue; } -void KScheduler::YieldWithoutCoreMigration() { - auto& kernel = system.Kernel(); - +void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = Kernel::GetCurrentThread(kernel); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -413,15 +442,13 @@ void KScheduler::YieldWithoutCoreMigration() { } } -void KScheduler::YieldWithCoreMigration() { - auto& kernel = system.Kernel(); - +void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = Kernel::GetCurrentThread(kernel); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -503,15 +530,13 @@ void KScheduler::YieldWithCoreMigration() { } } -void KScheduler::YieldToAnyThread() { - auto& kernel = system.Kernel(); - +void KScheduler::YieldToAnyThread(KernelCore& kernel) { // Validate preconditions. ASSERT(CanSchedule(kernel)); ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = *GetCurrentThread(); + KThread& cur_thread = Kernel::GetCurrentThread(kernel); Process& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -581,15 +606,14 @@ void KScheduler::YieldToAnyThread() { } } -KScheduler::KScheduler(Core::System& system, std::size_t 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(OnSwitch, this); - this->state.needs_scheduling = true; - this->state.interrupt_task_thread_runnable = false; - this->state.should_count_idle = false; - this->state.idle_count = 0; - this->state.idle_thread_stack = nullptr; - this->state.highest_priority_thread = nullptr; + state.needs_scheduling = true; + state.interrupt_task_thread_runnable = false; + state.should_count_idle = false; + state.idle_count = 0; + state.idle_thread_stack = nullptr; + state.highest_priority_thread = nullptr; } KScheduler::~KScheduler() = default; @@ -613,7 +637,7 @@ void KScheduler::RescheduleCurrentCore() { phys_core.ClearInterrupt(); } guard.lock(); - if (this->state.needs_scheduling) { + if (state.needs_scheduling) { Schedule(); } else { guard.unlock(); @@ -625,32 +649,34 @@ void KScheduler::OnThreadStart() { } void KScheduler::Unload(KThread* thread) { + LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); + if (thread) { - thread->SetIsRunning(false); - if (thread->IsContinuousOnSVC()) { + if (thread->IsCallingSvc()) { system.ArmInterface(core_id).ExceptionalExit(); - thread->SetContinuousOnSVC(false); + thread->ClearIsCallingSvc(); } - if (!thread->HasExited()) { + if (!thread->IsTerminationRequested()) { + prev_thread = thread; + Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(thread->GetContext32()); cpu_core.SaveContext(thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); + } else { + prev_thread = nullptr; } - thread->context_guard.unlock(); } } void KScheduler::Reload(KThread* thread) { + LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr"); + if (thread) { ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); - // Cancel any outstanding wakeup events for this thread - thread->SetIsRunning(true); - thread->SetWasRunning(false); - auto* const thread_owner_process = thread->GetOwnerProcess(); if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); @@ -676,7 +702,7 @@ void KScheduler::ScheduleImpl() { KThread* previous_thread = current_thread; current_thread = state.highest_priority_thread; - this->state.needs_scheduling = false; + state.needs_scheduling = false; if (current_thread == previous_thread) { guard.unlock(); @@ -714,7 +740,7 @@ void KScheduler::SwitchToCurrent() { { std::scoped_lock lock{guard}; current_thread = state.highest_priority_thread; - this->state.needs_scheduling = false; + state.needs_scheduling = false; } const auto is_switch_pending = [this] { std::scoped_lock lock{guard}; @@ -722,13 +748,10 @@ void KScheduler::SwitchToCurrent() { }; do { if (current_thread != nullptr) { - current_thread->context_guard.lock(); if (current_thread->GetRawState() != ThreadState::Runnable) { - current_thread->context_guard.unlock(); break; } - if (static_cast(current_thread->GetProcessorID()) != core_id) { - current_thread->context_guard.unlock(); + if (static_cast(current_thread->GetActiveCore()) != core_id) { break; } } @@ -749,7 +772,7 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { - thread->UpdateCPUTimeTicks(update_ticks); + thread->AddCpuTime(core_id, update_ticks); } if (process != nullptr) { @@ -763,15 +786,10 @@ void KScheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); std::function init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, + auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); idle_thread = thread_res.Unwrap().get(); - - { - KScopedSchedulerLock lock{system.Kernel()}; - idle_thread->SetState(ThreadState::Runnable); - } } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) -- cgit v1.2.3 From ca78f77827376af1cd42f655dca6f8d1d2725200 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 20 Jan 2021 16:47:57 -0800 Subject: hle: kernel: KScheduler: Introduce thread context_guard. --- src/core/hle/kernel/k_scheduler.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 5bdbd9a9b..e99122f4c 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -668,6 +668,7 @@ void KScheduler::Unload(KThread* thread) { } else { prev_thread = nullptr; } + thread->context_guard.unlock(); } } @@ -700,15 +701,23 @@ void KScheduler::SwitchContextStep2() { void KScheduler::ScheduleImpl() { KThread* previous_thread = current_thread; - current_thread = state.highest_priority_thread; + KThread* next_thread = state.highest_priority_thread; state.needs_scheduling = false; - if (current_thread == previous_thread) { + // We never want to schedule a null thread, so use the idle thread if we don't have a next. + if (next_thread == nullptr) { + next_thread = idle_thread; + } + + // If we're not actually switching thread, there's nothing to do. + if (next_thread == current_thread) { guard.unlock(); return; } + current_thread = next_thread; + Process* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -748,10 +757,13 @@ void KScheduler::SwitchToCurrent() { }; do { if (current_thread != nullptr) { + current_thread->context_guard.lock(); if (current_thread->GetRawState() != ThreadState::Runnable) { + current_thread->context_guard.unlock(); break; } - if (static_cast(current_thread->GetActiveCore()) != core_id) { + if (current_thread->GetActiveCore() != core_id) { + current_thread->context_guard.unlock(); break; } } -- cgit v1.2.3 From f6b10fad6365be68e9c93b1396249c66910e785f Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 20 Jan 2021 22:27:38 -0800 Subject: hle: kernel: k_scheduler: Fix for single core mode. --- src/core/hle/kernel/k_scheduler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index e99122f4c..e8e3b3dc5 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -38,7 +38,8 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul bool must_context_switch{}; if (scheduler) { current_core = scheduler->core_id; - must_context_switch = true; + // TODO(bunnei): Should be set to true when we deprecate single core + must_context_switch = !kernel.IsPhantomModeForSingleCore(); } while (cores_pending_reschedule != 0) { -- cgit v1.2.3 From 37f74d87417c8cb491fee1681cc05fb7baa5e516 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 21 Jan 2021 11:26:00 -0800 Subject: hle: kernel: k_scheduler: Use atomics for current_thread, etc. --- src/core/hle/kernel/k_scheduler.cpp | 47 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index e8e3b3dc5..fbdc061df 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -80,7 +80,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { } state.highest_priority_thread = highest_thread; - state.needs_scheduling = true; + state.needs_scheduling.store(true); return (1ULL << core_id); } else { 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) { switch_fiber = std::make_shared(OnSwitch, this); - state.needs_scheduling = true; + state.needs_scheduling.store(true); state.interrupt_task_thread_runnable = false; state.should_count_idle = false; state.idle_count = 0; @@ -620,10 +620,10 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core KScheduler::~KScheduler() = default; KThread* KScheduler::GetCurrentThread() const { - if (current_thread) { - return current_thread; + if (auto result = current_thread.load(); result) { + return result; } - return idle_thread; + return idle_thread.get(); } u64 KScheduler::GetLastContextSwitchTicks() const { @@ -638,7 +638,7 @@ void KScheduler::RescheduleCurrentCore() { phys_core.ClearInterrupt(); } guard.lock(); - if (state.needs_scheduling) { + if (state.needs_scheduling.load()) { Schedule(); } else { guard.unlock(); @@ -695,29 +695,29 @@ void KScheduler::Reload(KThread* thread) { void KScheduler::SwitchContextStep2() { // Load context of new thread - Reload(current_thread); + Reload(current_thread.load()); RescheduleCurrentCore(); } void KScheduler::ScheduleImpl() { - KThread* previous_thread = current_thread; + KThread* previous_thread = current_thread.load(); KThread* next_thread = state.highest_priority_thread; state.needs_scheduling = false; // We never want to schedule a null thread, so use the idle thread if we don't have a next. 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 (next_thread == current_thread) { + if (next_thread == current_thread.load()) { guard.unlock(); return; } - current_thread = next_thread; + current_thread.store(next_thread); Process* const previous_process = system.Kernel().CurrentProcess(); @@ -749,28 +749,29 @@ void KScheduler::SwitchToCurrent() { while (true) { { std::scoped_lock lock{guard}; - current_thread = state.highest_priority_thread; - state.needs_scheduling = false; + current_thread.store(state.highest_priority_thread); + state.needs_scheduling.store(false); } const auto is_switch_pending = [this] { std::scoped_lock lock{guard}; - return state.needs_scheduling.load(std::memory_order_relaxed); + return state.needs_scheduling.load(); }; do { - if (current_thread != nullptr) { - current_thread->context_guard.lock(); - if (current_thread->GetRawState() != ThreadState::Runnable) { - current_thread->context_guard.unlock(); + auto next_thread = current_thread.load(); + if (next_thread != nullptr) { + next_thread->context_guard.lock(); + if (next_thread->GetRawState() != ThreadState::Runnable) { + next_thread->context_guard.unlock(); break; } - if (current_thread->GetActiveCore() != core_id) { - current_thread->context_guard.unlock(); + if (next_thread->GetActiveCore() != core_id) { + next_thread->context_guard.unlock(); break; } } std::shared_ptr* next_context; - if (current_thread != nullptr) { - next_context = ¤t_thread->GetHostContext(); + if (next_thread != nullptr) { + next_context = &next_thread->GetHostContext(); } else { next_context = &idle_thread->GetHostContext(); } @@ -802,7 +803,7 @@ void KScheduler::Initialize() { auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); - idle_thread = thread_res.Unwrap().get(); + idle_thread = thread_res.Unwrap(); } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) -- cgit v1.2.3 From 6e953f7f0294d945ba9d6f08350d5dccb0d76075 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 21 Jan 2021 13:00:16 -0800 Subject: hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling. --- src/core/hle/kernel/k_scheduler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/k_scheduler.cpp') diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index fbdc061df..bb5f43b53 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -623,7 +623,7 @@ KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { return result; } - return idle_thread.get(); + return idle_thread; } u64 KScheduler::GetLastContextSwitchTicks() const { @@ -708,7 +708,7 @@ void KScheduler::ScheduleImpl() { // We never want to schedule a null thread, so use the idle thread if we don't have a next. if (next_thread == nullptr) { - next_thread = idle_thread.get(); + next_thread = idle_thread; } // If we're not actually switching thread, there's nothing to do. @@ -803,7 +803,7 @@ void KScheduler::Initialize() { auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); - idle_thread = thread_res.Unwrap(); + idle_thread = thread_res.Unwrap().get(); } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) -- cgit v1.2.3