From 18c796ab58ce7db4e4b0df67a6a471b91a5d0633 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 Mar 2019 17:01:46 -0400 Subject: Addapt thread class to the new Scheduler --- src/core/hle/kernel/thread.cpp | 242 +++++++++++++++++++++++++++++++---------- 1 file changed, 183 insertions(+), 59 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ec529e7f2d..d0fa7b3702 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -45,15 +45,7 @@ void Thread::Stop() { callback_handle); kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; - - // Clean up thread from ready queue - // This is only needed when the thread is terminated forcefully (SVC TerminateProcess) - if (status == ThreadStatus::Ready || status == ThreadStatus::Paused) { - scheduler->UnscheduleThread(this, current_priority); - } - - status = ThreadStatus::Dead; - + SetStatus(ThreadStatus::Dead); WakeupAllWaitingThreads(); // Clean up any dangling references in objects that this thread was waiting for @@ -132,13 +124,11 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; if (activity == ThreadActivity::Paused) { - status = ThreadStatus::Paused; + SetStatus(ThreadStatus::Paused); return; } - status = ThreadStatus::Ready; - - ChangeScheduler(); + SetStatus(ThreadStatus::Ready); } void Thread::CancelWait() { @@ -205,9 +195,9 @@ ResultVal> Thread::Create(KernelCore& kernel, std::string name thread->name = std::move(name); thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); thread->owner_process = &owner_process; + auto& scheduler = kernel.GlobalScheduler(); + scheduler.AddThread(thread); thread->tls_address = thread->owner_process->CreateTLSRegion(); - thread->scheduler = &system.Scheduler(processor_id); - thread->scheduler->AddThread(thread); thread->owner_process->RegisterThread(thread.get()); @@ -250,6 +240,22 @@ void Thread::SetStatus(ThreadStatus new_status) { return; } + switch (new_status) { + case ThreadStatus::Ready: + case ThreadStatus::Running: + SetSchedulingStatus(ThreadSchedStatus::Runnable); + break; + case ThreadStatus::Dormant: + SetSchedulingStatus(ThreadSchedStatus::None); + break; + case ThreadStatus::Dead: + SetSchedulingStatus(ThreadSchedStatus::Exited); + break; + default: + SetSchedulingStatus(ThreadSchedStatus::Paused); + break; + } + if (status == ThreadStatus::Running) { last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); } @@ -311,8 +317,7 @@ void Thread::UpdatePriority() { return; } - scheduler->SetThreadPriority(this, new_priority); - current_priority = new_priority; + SetCurrentPriority(new_priority); if (!lock_owner) { return; @@ -328,47 +333,7 @@ void Thread::UpdatePriority() { } void Thread::ChangeCore(u32 core, u64 mask) { - ideal_core = core; - affinity_mask = mask; - ChangeScheduler(); -} - -void Thread::ChangeScheduler() { - if (status != ThreadStatus::Ready) { - return; - } - - auto& system = Core::System::GetInstance(); - std::optional new_processor_id{GetNextProcessorId(affinity_mask)}; - - if (!new_processor_id) { - new_processor_id = processor_id; - } - if (ideal_core != -1 && system.Scheduler(ideal_core).GetCurrentThread() == nullptr) { - new_processor_id = ideal_core; - } - - ASSERT(*new_processor_id < 4); - - // Add thread to new core's scheduler - auto& next_scheduler = system.Scheduler(*new_processor_id); - - if (*new_processor_id != processor_id) { - // Remove thread from previous core's scheduler - scheduler->RemoveThread(this); - next_scheduler.AddThread(this); - } - - processor_id = *new_processor_id; - - // If the thread was ready, unschedule from the previous core and schedule on the new core - scheduler->UnscheduleThread(this, current_priority); - next_scheduler.ScheduleThread(this, current_priority); - - // Change thread's scheduler - scheduler = &next_scheduler; - - system.CpuCore(processor_id).PrepareReschedule(); + SetCoreAndAffinityMask(core, mask); } bool Thread::AllWaitObjectsReady() const { @@ -391,7 +356,7 @@ void Thread::SetActivity(ThreadActivity value) { if (status == ThreadStatus::Ready) { status = ThreadStatus::Paused; } else if (status == ThreadStatus::Running) { - status = ThreadStatus::Paused; + SetStatus(ThreadStatus::Paused); Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } } else if (status == ThreadStatus::Paused) { @@ -408,6 +373,165 @@ void Thread::Sleep(s64 nanoseconds) { WakeAfterDelay(nanoseconds); } +void Thread::YieldType0() { + auto& scheduler = kernel.GlobalScheduler(); + scheduler.YieldThread(this); +} + +void Thread::YieldType1() { + auto& scheduler = kernel.GlobalScheduler(); + scheduler.YieldThreadAndBalanceLoad(this); +} + +void Thread::YieldType2() { + auto& scheduler = kernel.GlobalScheduler(); + scheduler.YieldThreadAndWaitForLoadBalancing(this); +} + +void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { + u32 old_flags = scheduling_state; + scheduling_state = + (scheduling_state & ThreadSchedMasks::HighMask) | static_cast(new_status); + AdjustSchedulingOnStatus(old_flags); +} + +void Thread::SetCurrentPriority(u32 new_priority) { + u32 old_priority = current_priority; + current_priority = new_priority; + AdjustSchedulingOnPriority(old_priority); +} + +ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { + auto HighestSetCore = [](u64 mask, u32 max_cores) { + for (s32 core = max_cores - 1; core >= 0; core--) { + if (((mask >> core) & 1) != 0) + return core; + } + return -1; + }; + bool use_override = affinity_override_count != 0; + // The value -3 is "do not change the ideal core". + if (new_core == -3) { + new_core = use_override ? ideal_core_override : ideal_core; + if ((new_affinity_mask & (1 << new_core)) == 0) { + return ERR_INVALID_COMBINATION; + } + } + if (use_override) { + ideal_core_override = new_core; + affinity_mask_override = new_affinity_mask; + } else { + u64 old_affinity_mask = affinity_mask; + ideal_core = new_core; + affinity_mask = new_affinity_mask; + if (old_affinity_mask != new_affinity_mask) { + s32 old_core = processor_id; + if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { + if (ideal_core < 0) { + processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); + } else { + processor_id = ideal_core; + } + } + AdjustSchedulingOnAffinity(old_affinity_mask, old_core); + } + } + return RESULT_SUCCESS; +} + +void Thread::AdjustSchedulingOnStatus(u32 old_flags) { + if (old_flags == scheduling_state) + return; + + auto& scheduler = kernel.GlobalScheduler(); + if (static_cast(old_flags & ThreadSchedMasks::LowMask) == + ThreadSchedStatus::Runnable) { + // In this case the thread was running, now it's pausing/exitting + if (processor_id >= 0) + scheduler.Unschedule(current_priority, processor_id, this); + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) + scheduler.Unsuggest(current_priority, core, this); + } + } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + // The thread is now set to running from being stopped + if (processor_id >= 0) + scheduler.Schedule(current_priority, processor_id, this); + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) + scheduler.Suggest(current_priority, core, this); + } + } + + scheduler.SetReselectionPending(); +} + +void Thread::AdjustSchedulingOnPriority(u32 old_priority) { + if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + return; + } + auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + if (processor_id >= 0) { + scheduler.Unschedule(old_priority, processor_id, this); + } + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { + scheduler.Unsuggest(old_priority, core, this); + } + } + + // Add thread to the new priority queues. + Thread* current_thread = GetCurrentThread(); + + if (processor_id >= 0) { + if (current_thread == this) { + scheduler.SchedulePrepend(current_priority, processor_id, this); + } else { + scheduler.Schedule(current_priority, processor_id, this); + } + } + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { + scheduler.Suggest(current_priority, core, this); + } + } + + scheduler.SetReselectionPending(); +} + +void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { + auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || + current_priority >= THREADPRIO_COUNT) + return; + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (((old_affinity_mask >> core) & 1) != 0) { + if (core == old_core) { + scheduler.Unschedule(current_priority, core, this); + } else { + scheduler.Unsuggest(current_priority, core, this); + } + } + } + + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (((affinity_mask >> core) & 1) != 0) { + if (core == processor_id) { + scheduler.Schedule(current_priority, core, this); + } else { + scheduler.Suggest(current_priority, core, this); + } + } + } + + scheduler.SetReselectionPending(); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// /** -- cgit v1.2.3 From 5130168171d67075b2d64566d6d41bf17985c272 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 19 Jun 2019 09:11:18 -0400 Subject: Kernel: Style and Corrections --- src/core/core.cpp | 5 ++- src/core/core.h | 4 +- src/core/core_cpu.cpp | 2 +- src/core/core_cpu.h | 2 +- src/core/hle/kernel/address_arbiter.cpp | 1 - src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/mutex.cpp | 2 +- src/core/hle/kernel/scheduler.cpp | 78 ++++++++++++++++++++------------- src/core/hle/kernel/scheduler.h | 53 ++++++++++++---------- src/core/hle/kernel/svc.cpp | 15 ++++--- src/core/hle/kernel/thread.cpp | 54 +++++++++++++---------- src/core/hle/kernel/thread.h | 15 ++++--- 12 files changed, 137 insertions(+), 96 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 4a95630bd0..d79045eeaa 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -404,9 +404,10 @@ void System::PrepareReschedule() { CurrentCpuCore().PrepareReschedule(); } -void System::PrepareReschedule(s32 core_index) { - if (core_index >= 0) +void System::PrepareReschedule(const u32 core_index) { + if (core_index < GlobalScheduler().CpuCoresCount()) { CpuCore(core_index).PrepareReschedule(); + } } PerfStatsResults System::GetAndResetPerfStats() { diff --git a/src/core/core.h b/src/core/core.h index 0d1008895d..984074ce35 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -24,10 +24,10 @@ class VfsFilesystem; } // namespace FileSys namespace Kernel { +class GlobalScheduler; class KernelCore; class Process; class Scheduler; -class GlobalScheduler; } // namespace Kernel namespace Loader { @@ -186,7 +186,7 @@ public: void PrepareReschedule(); /// Prepare the core emulation for a reschedule - void PrepareReschedule(s32 core_index); + void PrepareReschedule(u32 core_index); /// Gets and resets core performance statistics PerfStatsResults GetAndResetPerfStats(); diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index 2a7c3af240..a6f63e437a 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -111,7 +111,7 @@ void Cpu::PrepareReschedule() { void Cpu::Reschedule() { // Lock the global kernel mutex when we manipulate the HLE state - std::lock_guard lock(HLE::g_hle_lock); + std::lock_guard lock(HLE::g_hle_lock); global_scheduler.SelectThread(core_index); scheduler->TryDoContextSwitch(); diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h index 0cde547878..80261daf75 100644 --- a/src/core/core_cpu.h +++ b/src/core/core_cpu.h @@ -12,8 +12,8 @@ #include "common/common_types.h" namespace Kernel { -class Scheduler; class GlobalScheduler; +class Scheduler; } // namespace Kernel namespace Core { diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index c66cd16ef3..4c1d3fd180 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -22,7 +22,6 @@ namespace Kernel { namespace { // Wake up num_to_wake (or all) threads in a vector. void WakeThreads(const std::vector>& waiting_threads, s32 num_to_wake) { - auto& system = Core::System::GetInstance(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b4fd1d3f32..600d6ec742 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -89,7 +89,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ } struct KernelCore::Impl { - explicit Impl(Core::System& system) : system{system} {} + explicit Impl(Core::System& system) : system{system}, global_scheduler{system} {} void Initialize(KernelCore& kernel) { Shutdown(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 57f2d8bf30..eb919246cd 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -140,7 +140,7 @@ ResultCode Mutex::Release(VAddr address) { thread->SetMutexWaitAddress(0); thread->SetWaitHandle(0); - Core::System::GetInstance().PrepareReschedule(); + system.PrepareReschedule(); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5376401526..df4e9b7994 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -1,6 +1,9 @@ // Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +// +// SelectThreads, Yield functions originally by TuxSH. +// licensed under GPLv2 or later under exception provided by the author. #include #include @@ -19,16 +22,15 @@ namespace Kernel { -/* - * SelectThreads, Yield functions originally by TuxSH. - * licensed under GPLv2 or later under exception provided by the author. - */ +GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} { + reselection_pending = false; +} void GlobalScheduler::AddThread(SharedPtr thread) { thread_list.push_back(std::move(thread)); } -void GlobalScheduler::RemoveThread(Thread* thread) { +void GlobalScheduler::RemoveThread(const Thread* thread) { thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); } @@ -37,7 +39,7 @@ void GlobalScheduler::RemoveThread(Thread* thread) { * UnloadThread selects a core and forces it to unload its current thread's context */ void GlobalScheduler::UnloadThread(s32 core) { - Scheduler& sched = Core::System::GetInstance().Scheduler(core); + Scheduler& sched = system.Scheduler(core); sched.UnloadThread(); } @@ -52,7 +54,7 @@ void GlobalScheduler::UnloadThread(s32 core) { * thread in another core and swap it with its current thread. */ void GlobalScheduler::SelectThread(u32 core) { - auto update_thread = [](Thread* thread, Scheduler& sched) { + const auto update_thread = [](Thread* thread, Scheduler& sched) { if (thread != sched.selected_thread) { if (thread == nullptr) { ++sched.idle_selection_count; @@ -62,7 +64,7 @@ void GlobalScheduler::SelectThread(u32 core) { sched.context_switch_pending = sched.selected_thread != sched.current_thread; std::atomic_thread_fence(std::memory_order_seq_cst); }; - Scheduler& sched = Core::System::GetInstance().Scheduler(core); + Scheduler& sched = system.Scheduler(core); Thread* current_thread = nullptr; // Step 1: Get top thread in schedule queue. current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); @@ -118,8 +120,8 @@ void GlobalScheduler::SelectThread(u32 core) { */ void GlobalScheduler::YieldThread(Thread* yielding_thread) { // Note: caller should use critical section, etc. - u32 core_id = static_cast(yielding_thread->GetProcessorID()); - u32 priority = yielding_thread->GetPriority(); + const u32 core_id = static_cast(yielding_thread->GetProcessorID()); + const u32 priority = yielding_thread->GetPriority(); // Yield the thread ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority), @@ -139,8 +141,8 @@ void GlobalScheduler::YieldThread(Thread* yielding_thread) { void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. - u32 core_id = static_cast(yielding_thread->GetProcessorID()); - u32 priority = yielding_thread->GetPriority(); + const u32 core_id = static_cast(yielding_thread->GetProcessorID()); + const u32 priority = yielding_thread->GetPriority(); // Yield the thread ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority), @@ -155,12 +157,13 @@ void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { Thread* next_thread = scheduled_queue[core_id].front(priority); Thread* winner = nullptr; for (auto& thread : suggested_queue[core_id]) { - s32 source_core = thread->GetProcessorID(); + const s32 source_core = thread->GetProcessorID(); if (source_core >= 0) { if (current_threads[source_core] != nullptr) { if (thread == current_threads[source_core] || - current_threads[source_core]->GetPriority() < min_regular_priority) + current_threads[source_core]->GetPriority() < min_regular_priority) { continue; + } } if (next_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks() || next_thread->GetPriority() < thread->GetPriority()) { @@ -174,8 +177,9 @@ void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) + if (winner->IsRunning()) { UnloadThread(winner->GetProcessorID()); + } TransferToCore(winner->GetPriority(), core_id, winner); } } else { @@ -195,7 +199,7 @@ void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. Thread* winner = nullptr; - u32 core_id = static_cast(yielding_thread->GetProcessorID()); + const u32 core_id = static_cast(yielding_thread->GetProcessorID()); // Remove the thread from its scheduled mlq, put it on the corresponding "suggested" one instead TransferToCore(yielding_thread->GetPriority(), -1, yielding_thread); @@ -209,9 +213,10 @@ void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front(); } for (auto& thread : suggested_queue[core_id]) { - s32 source_core = thread->GetProcessorID(); - if (source_core < 0 || thread == current_threads[source_core]) + const s32 source_core = thread->GetProcessorID(); + if (source_core < 0 || thread == current_threads[source_core]) { continue; + } if (current_threads[source_core] == nullptr || current_threads[source_core]->GetPriority() >= min_regular_priority) { winner = thread; @@ -220,8 +225,9 @@ void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) + if (winner->IsRunning()) { UnloadThread(winner->GetProcessorID()); + } TransferToCore(winner->GetPriority(), core_id, winner); } } else { @@ -232,6 +238,16 @@ void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread AskForReselectionOrMarkRedundant(yielding_thread, winner); } +void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) { + ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); + scheduled_queue[core].add(thread, priority); +} + +void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) { + ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); + scheduled_queue[core].add(thread, priority, false); +} + void GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) { if (current_thread == winner) { // TODO(blinkhawk): manage redundant operations, this is not implemented. @@ -244,13 +260,13 @@ void GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, T GlobalScheduler::~GlobalScheduler() = default; -Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 id) - : system(system), cpu_core(cpu_core), id(id) {} +Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id) + : system(system), cpu_core(cpu_core), core_id(core_id) {} -Scheduler::~Scheduler() {} +Scheduler::~Scheduler() = default; bool Scheduler::HaveReadyThreads() const { - return system.GlobalScheduler().HaveReadyThreads(id); + return system.GlobalScheduler().HaveReadyThreads(core_id); } Thread* Scheduler::GetCurrentThread() const { @@ -262,7 +278,7 @@ Thread* Scheduler::GetSelectedThread() const { } void Scheduler::SelectThreads() { - system.GlobalScheduler().SelectThread(id); + system.GlobalScheduler().SelectThread(core_id); } u64 Scheduler::GetLastContextSwitchTicks() const { @@ -270,13 +286,14 @@ u64 Scheduler::GetLastContextSwitchTicks() const { } void Scheduler::TryDoContextSwitch() { - if (context_switch_pending) + if (context_switch_pending) { SwitchContext(); + } } void Scheduler::UnloadThread() { Thread* const previous_thread = GetCurrentThread(); - Process* const previous_process = Core::CurrentProcess(); + Process* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -301,10 +318,11 @@ void Scheduler::SwitchContext() { Thread* const new_thread = GetSelectedThread(); context_switch_pending = false; - if (new_thread == previous_thread) + if (new_thread == previous_thread) { return; + } - Process* const previous_process = Core::CurrentProcess(); + Process* const previous_process = system.Kernel().CurrentProcess(); UpdateLastContextSwitchTime(previous_thread, previous_process); @@ -324,7 +342,7 @@ void Scheduler::SwitchContext() { // Load context of new thread if (new_thread) { - ASSERT_MSG(new_thread->GetProcessorID() == this->id, + ASSERT_MSG(new_thread->GetProcessorID() == this->core_id, "Thread must be assigned to this core."); ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, "Thread must be ready to become running."); @@ -353,7 +371,7 @@ void Scheduler::SwitchContext() { void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; - const u64 most_recent_switch_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); + const u64 most_recent_switch_ticks = system.CoreTiming().GetTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 82ed64b556..1c9d8a30f8 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -24,62 +24,70 @@ class GlobalScheduler final { public: static constexpr u32 NUM_CPU_CORES = 4; - GlobalScheduler() { - reselection_pending = false; - } + explicit GlobalScheduler(Core::System& system); ~GlobalScheduler(); /// Adds a new thread to the scheduler void AddThread(SharedPtr thread); /// Removes a thread from the scheduler - void RemoveThread(Thread* thread); + void RemoveThread(const Thread* thread); /// Returns a list of all threads managed by the scheduler const std::vector>& GetThreadList() const { return thread_list; } + // Add a thread to the suggested queue of a cpu core. Suggested threads may be + // picked if no thread is scheduled to run on the core. void Suggest(u32 priority, u32 core, Thread* thread) { suggested_queue[core].add(thread, priority); } + // Remove a thread to the suggested queue of a cpu core. Suggested threads may be + // picked if no thread is scheduled to run on the core. void Unsuggest(u32 priority, u32 core, Thread* thread) { suggested_queue[core].remove(thread, priority); } - void Schedule(u32 priority, u32 core, Thread* thread) { - ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); - scheduled_queue[core].add(thread, priority); - } + // Add a thread to the scheduling queue of a cpu core. The thread is added at the + // back the queue in its priority level + void Schedule(u32 priority, u32 core, Thread* thread); - void SchedulePrepend(u32 priority, u32 core, Thread* thread) { - ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); - scheduled_queue[core].add(thread, priority, false); - } + // Add a thread to the scheduling queue of a cpu core. The thread is added at the + // front the queue in its priority level + void SchedulePrepend(u32 priority, u32 core, Thread* thread); + // Reschedule an already scheduled thread based on a new priority void Reschedule(u32 priority, u32 core, Thread* thread) { scheduled_queue[core].remove(thread, priority); scheduled_queue[core].add(thread, priority); } + // Unschedule a thread. void Unschedule(u32 priority, u32 core, Thread* thread) { scheduled_queue[core].remove(thread, priority); } + // Transfers a thread into an specific core. If the destination_core is -1 + // it will be unscheduled from its source code and added into its suggested + // queue. void TransferToCore(u32 priority, s32 destination_core, Thread* thread) { - bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; - s32 source_core = thread->GetProcessorID(); - if (source_core == destination_core || !schedulable) + const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; + const s32 source_core = thread->GetProcessorID(); + if (source_core == destination_core || !schedulable) { return; + } thread->SetProcessorID(destination_core); - if (source_core >= 0) + if (source_core >= 0) { Unschedule(priority, source_core, thread); + } if (destination_core >= 0) { Unsuggest(priority, destination_core, thread); Schedule(priority, destination_core, thread); } - if (source_core >= 0) + if (source_core >= 0) { Suggest(priority, source_core, thread); + } } /* @@ -99,7 +107,7 @@ public: */ void SelectThread(u32 core); - bool HaveReadyThreads(u32 core_id) { + bool HaveReadyThreads(u32 core_id) const { return !scheduled_queue[core_id].empty(); } @@ -133,8 +141,8 @@ public: reselection_pending.store(true, std::memory_order_release); } - bool IsReselectionPending() { - return reselection_pending.load(std::memory_order_acquire); + bool IsReselectionPending() const { + return reselection_pending.load(); } private: @@ -147,11 +155,12 @@ private: /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; + Core::System& system; }; class Scheduler final { public: - explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, const u32 id); + explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, const u32 core_id); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -204,7 +213,7 @@ private: Core::ARM_Interface& cpu_core; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; - const u32 id; + const u32 core_id; bool context_switch_pending = false; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 560ac39455..d520ed0332 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1560,13 +1560,13 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - current_thread->YieldType0(); + current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - current_thread->YieldType1(); + current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - current_thread->YieldType2(); + current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1638,8 +1638,9 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var const auto& thread_list = scheduler.GetThreadList(); for (const auto& thread : thread_list) { - if (thread->GetCondVarWaitAddress() == condition_variable_addr) + if (thread->GetCondVarWaitAddress() == condition_variable_addr) { waiting_threads.push_back(thread); + } } // Sort them by priority, such that the highest priority ones come first. @@ -1747,9 +1748,11 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, const auto arbitration_type = static_cast(type); auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); - ResultCode result = address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); - if (result == RESULT_SUCCESS) + const ResultCode result = + address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); + if (result == RESULT_SUCCESS) { system.PrepareReschedule(); + } return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d0fa7b3702..8cf0a7ec77 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -373,43 +373,44 @@ void Thread::Sleep(s64 nanoseconds) { WakeAfterDelay(nanoseconds); } -void Thread::YieldType0() { +void Thread::YieldSimple() { auto& scheduler = kernel.GlobalScheduler(); scheduler.YieldThread(this); } -void Thread::YieldType1() { +void Thread::YieldAndBalanceLoad() { auto& scheduler = kernel.GlobalScheduler(); scheduler.YieldThreadAndBalanceLoad(this); } -void Thread::YieldType2() { +void Thread::YieldAndWaitForLoadBalancing() { auto& scheduler = kernel.GlobalScheduler(); scheduler.YieldThreadAndWaitForLoadBalancing(this); } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { - u32 old_flags = scheduling_state; + const u32 old_flags = scheduling_state; scheduling_state = (scheduling_state & ThreadSchedMasks::HighMask) | static_cast(new_status); AdjustSchedulingOnStatus(old_flags); } void Thread::SetCurrentPriority(u32 new_priority) { - u32 old_priority = current_priority; - current_priority = new_priority; + u32 old_priority = std::exchange(current_priority, new_priority); AdjustSchedulingOnPriority(old_priority); } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { - auto HighestSetCore = [](u64 mask, u32 max_cores) { + const auto HighestSetCore = [](u64 mask, u32 max_cores) { for (s32 core = max_cores - 1; core >= 0; core--) { - if (((mask >> core) & 1) != 0) + if (((mask >> core) & 1) != 0) { return core; + } } return -1; }; - bool use_override = affinity_override_count != 0; + + const bool use_override = affinity_override_count != 0; // The value -3 is "do not change the ideal core". if (new_core == -3) { new_core = use_override ? ideal_core_override : ideal_core; @@ -421,11 +422,10 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { ideal_core_override = new_core; affinity_mask_override = new_affinity_mask; } else { - u64 old_affinity_mask = affinity_mask; + const u64 old_affinity_mask = std::exchange(affinity_mask, new_affinity_mask); ideal_core = new_core; - affinity_mask = new_affinity_mask; if (old_affinity_mask != new_affinity_mask) { - s32 old_core = processor_id; + const s32 old_core = processor_id; if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { if (ideal_core < 0) { processor_id = HighestSetCore(affinity_mask, GlobalScheduler::NUM_CPU_CORES); @@ -440,28 +440,33 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { } void Thread::AdjustSchedulingOnStatus(u32 old_flags) { - if (old_flags == scheduling_state) + if (old_flags == scheduling_state) { return; + } auto& scheduler = kernel.GlobalScheduler(); if (static_cast(old_flags & ThreadSchedMasks::LowMask) == ThreadSchedStatus::Runnable) { // In this case the thread was running, now it's pausing/exitting - if (processor_id >= 0) + if (processor_id >= 0) { scheduler.Unschedule(current_priority, processor_id, this); + } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(current_priority, core, this); + } } } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { // The thread is now set to running from being stopped - if (processor_id >= 0) + if (processor_id >= 0) { scheduler.Schedule(current_priority, processor_id, this); + } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { - if (core != processor_id && ((affinity_mask >> core) & 1) != 0) + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); + } } } @@ -477,7 +482,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { scheduler.Unschedule(old_priority, processor_id, this); } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(old_priority, core, this); } @@ -494,7 +499,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } @@ -506,10 +511,11 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { auto& scheduler = Core::System::GetInstance().GlobalScheduler(); if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || - current_priority >= THREADPRIO_COUNT) + current_priority >= THREADPRIO_COUNT) { return; + } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { if (core == old_core) { scheduler.Unschedule(current_priority, core, this); @@ -519,7 +525,7 @@ void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { } } - for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (((affinity_mask >> core) & 1) != 0) { if (core == processor_id) { scheduler.Schedule(current_priority, core, this); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c426a72096..bf0cae959a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -75,7 +75,12 @@ enum class ThreadActivity : u32 { Paused = 1, }; -enum class ThreadSchedStatus : u32 { None = 0, Paused = 1, Runnable = 2, Exited = 3 }; +enum class ThreadSchedStatus : u32 { + None = 0, + Paused = 1, + Runnable = 2, + Exited = 3, +}; enum ThreadSchedFlags : u32 { ProcessPauseFlag = 1 << 4, @@ -403,15 +408,15 @@ public: void Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - void YieldType0(); + void YieldSimple(); /// Yields this thread and does a load rebalancing. - void YieldType1(); + void YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - void YieldType2(); + void YieldAndWaitForLoadBalancing(); - ThreadSchedStatus GetSchedulingStatus() { + ThreadSchedStatus GetSchedulingStatus() const { return static_cast(scheduling_state & ThreadSchedMasks::LowMask); } -- cgit v1.2.3 From acdce3b4df6305ecc41647b80177b09a72b2e2aa Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Sep 2019 10:23:43 -0400 Subject: Scheduler: Add protections for Yield bombing In case of redundant yields, the scheduler will now idle the core for it's timeslice, in order to avoid continuously yielding the same thing over and over. --- src/core/hle/kernel/scheduler.cpp | 16 +++++++++------- src/core/hle/kernel/scheduler.h | 8 ++++---- src/core/hle/kernel/svc.cpp | 13 +++++++++---- src/core/hle/kernel/thread.cpp | 12 ++++++------ src/core/hle/kernel/thread.h | 6 +++--- 5 files changed, 31 insertions(+), 24 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index df4e9b7994..451fd8077d 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -118,7 +118,7 @@ void GlobalScheduler::SelectThread(u32 core) { * YieldThread takes a thread and moves it to the back of the it's priority list * This operation can be redundant and no scheduling is changed if marked as so. */ -void GlobalScheduler::YieldThread(Thread* yielding_thread) { +bool GlobalScheduler::YieldThread(Thread* yielding_thread) { // Note: caller should use critical section, etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -129,7 +129,7 @@ void GlobalScheduler::YieldThread(Thread* yielding_thread) { scheduled_queue[core_id].yield(priority); Thread* winner = scheduled_queue[core_id].front(priority); - AskForReselectionOrMarkRedundant(yielding_thread, winner); + return AskForReselectionOrMarkRedundant(yielding_thread, winner); } /* @@ -138,7 +138,7 @@ void GlobalScheduler::YieldThread(Thread* yielding_thread) { * a better priority than the next thread in the core. * This operation can be redundant and no scheduling is changed if marked as so. */ -void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { +bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); @@ -186,7 +186,7 @@ void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { winner = next_thread; } - AskForReselectionOrMarkRedundant(yielding_thread, winner); + return AskForReselectionOrMarkRedundant(yielding_thread, winner); } /* @@ -195,7 +195,7 @@ void GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { * a suggested thread is obtained instead. * This operation can be redundant and no scheduling is changed if marked as so. */ -void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { +bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. Thread* winner = nullptr; @@ -235,7 +235,7 @@ void GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } } - AskForReselectionOrMarkRedundant(yielding_thread, winner); + return AskForReselectionOrMarkRedundant(yielding_thread, winner); } void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) { @@ -248,13 +248,15 @@ void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) { scheduled_queue[core].add(thread, priority, false); } -void GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) { +bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) { if (current_thread == winner) { // TODO(blinkhawk): manage redundant operations, this is not implemented. // as its mostly an optimization. // current_thread->SetRedundantSchedulerOperation(); + return true; } else { reselection_pending.store(true, std::memory_order_release); + return false; } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 1c9d8a30f8..8fcc86bae1 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -115,7 +115,7 @@ public: * YieldThread takes a thread and moves it to the back of the it's priority list * This operation can be redundant and no scheduling is changed if marked as so. */ - void YieldThread(Thread* thread); + bool YieldThread(Thread* thread); /* * YieldThreadAndBalanceLoad takes a thread and moves it to the back of the it's priority list. @@ -123,7 +123,7 @@ public: * a better priority than the next thread in the core. * This operation can be redundant and no scheduling is changed if marked as so. */ - void YieldThreadAndBalanceLoad(Thread* thread); + bool YieldThreadAndBalanceLoad(Thread* thread); /* * YieldThreadAndWaitForLoadBalancing takes a thread and moves it out of the scheduling queue @@ -131,7 +131,7 @@ public: * a suggested thread is obtained instead. * This operation can be redundant and no scheduling is changed if marked as so. */ - void YieldThreadAndWaitForLoadBalancing(Thread* thread); + bool YieldThreadAndWaitForLoadBalancing(Thread* thread); u32 CpuCoresCount() const { return NUM_CPU_CORES; @@ -146,7 +146,7 @@ public: } private: - void AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner); + bool AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner); static constexpr u32 min_regular_priority = 2; std::array, NUM_CPU_CORES> scheduled_queue; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d520ed0332..bd67fc96d7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1556,17 +1556,18 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { auto& scheduler = system.CurrentScheduler(); auto* const current_thread = scheduler.GetCurrentThread(); + bool redundant = false; if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - current_thread->YieldSimple(); + redundant = current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - current_thread->YieldAndBalanceLoad(); + redundant = current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - current_thread->YieldAndWaitForLoadBalancing(); + redundant = current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1575,7 +1576,11 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { current_thread->Sleep(nanoseconds); } - system.PrepareReschedule(current_thread->GetProcessorID()); + if (redundant) { + system.CoreTiming().Idle(); + } else { + system.PrepareReschedule(current_thread->GetProcessorID()); + } } /// Wait process wide key atomic diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8cf0a7ec77..ae62609e38 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -373,19 +373,19 @@ void Thread::Sleep(s64 nanoseconds) { WakeAfterDelay(nanoseconds); } -void Thread::YieldSimple() { +bool Thread::YieldSimple() { auto& scheduler = kernel.GlobalScheduler(); - scheduler.YieldThread(this); + return scheduler.YieldThread(this); } -void Thread::YieldAndBalanceLoad() { +bool Thread::YieldAndBalanceLoad() { auto& scheduler = kernel.GlobalScheduler(); - scheduler.YieldThreadAndBalanceLoad(this); + return scheduler.YieldThreadAndBalanceLoad(this); } -void Thread::YieldAndWaitForLoadBalancing() { +bool Thread::YieldAndWaitForLoadBalancing() { auto& scheduler = kernel.GlobalScheduler(); - scheduler.YieldThreadAndWaitForLoadBalancing(this); + return scheduler.YieldThreadAndWaitForLoadBalancing(this); } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index bf0cae959a..88255099f5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -408,13 +408,13 @@ public: void Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - void YieldSimple(); + bool YieldSimple(); /// Yields this thread and does a load rebalancing. - void YieldAndBalanceLoad(); + bool YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - void YieldAndWaitForLoadBalancing(); + bool YieldAndWaitForLoadBalancing(); ThreadSchedStatus GetSchedulingStatus() const { return static_cast(scheduling_state & ThreadSchedMasks::LowMask); -- cgit v1.2.3 From 3da21e4b4f8bb03f3ccfda697104179b09695214 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 10 Oct 2019 08:04:14 -0400 Subject: Kernel: Corrections to Wait Objects clearing in which a thread could still be signalled after a timeout or a cancel. --- src/core/hle/kernel/thread.cpp | 1 + src/core/hle/kernel/thread.h | 3 +++ src/core/hle/kernel/wait_object.cpp | 3 --- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ae62609e38..563a99bfc7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -133,6 +133,7 @@ void Thread::ResumeFromWait() { void Thread::CancelWait() { ASSERT(GetStatus() == ThreadStatus::WaitSynch); + ClearWaitObjects(); SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4d220c4f98..ceb4d51591 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -319,6 +319,9 @@ public: } void ClearWaitObjects() { + for (const auto& waiting_object : wait_objects) { + waiting_object->RemoveWaitingThread(this); + } wait_objects.clear(); } diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 50ed2a2f15..0f833fb3ac 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -85,9 +85,6 @@ void WaitObject::WakeupWaitingThread(SharedPtr thread) { const std::size_t index = thread->GetWaitObjectIndex(this); - for (const auto& object : thread->GetWaitObjects()) { - object->RemoveWaitingThread(thread.get()); - } thread->ClearWaitObjects(); thread->CancelWakeupTimer(); -- cgit v1.2.3 From 8363d07df8198bf01d37ed77532b87fc74d09339 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 10 Oct 2019 08:50:41 -0400 Subject: Kernel: Correct Paused scheduling --- src/core/hle/kernel/thread.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 563a99bfc7..0871a2f004 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -354,9 +354,7 @@ void Thread::SetActivity(ThreadActivity value) { if (value == ThreadActivity::Paused) { // Set status if not waiting - if (status == ThreadStatus::Ready) { - status = ThreadStatus::Paused; - } else if (status == ThreadStatus::Running) { + if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { SetStatus(ThreadStatus::Paused); Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } -- cgit v1.2.3 From 0d57b899dd870b78bd89a427f823cb25cced3ccd Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 08:02:34 -0400 Subject: Kernel_Thread: Eliminate most global accessors. --- src/core/hle/kernel/thread.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0871a2f004..7208bbb110 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -41,8 +41,8 @@ Thread::~Thread() = default; void Thread::Stop() { // Cancel any outstanding wakeup events for this thread - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + kernel.System().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), + callback_handle); kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; SetStatus(ThreadStatus::Dead); @@ -68,13 +68,13 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); - Core::System::GetInstance().CoreTiming().ScheduleEvent( - cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); + kernel.System().CoreTiming().ScheduleEvent(cycles, kernel.ThreadWakeupCallbackEventType(), + callback_handle); } void Thread::CancelWakeupTimer() { - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + kernel.System().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), + callback_handle); } static std::optional GetNextProcessorId(u64 mask) { @@ -176,7 +176,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::string name return ResultCode(-1); } - auto& system = Core::System::GetInstance(); + auto& system = kernel.System(); SharedPtr thread(new Thread(kernel)); thread->thread_id = kernel.CreateNewThreadID(); @@ -258,7 +258,7 @@ void Thread::SetStatus(ThreadStatus new_status) { } if (status == ThreadStatus::Running) { - last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); + last_running_ticks = kernel.System().CoreTiming().GetTicks(); } status = new_status; @@ -356,7 +356,7 @@ void Thread::SetActivity(ThreadActivity value) { // Set status if not waiting if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { SetStatus(ThreadStatus::Paused); - Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); + kernel.System().CpuCore(processor_id).PrepareReschedule(); } } else if (status == ThreadStatus::Paused) { // Ready to reschedule @@ -476,7 +476,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { return; } - auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + auto& scheduler = kernel.System().GlobalScheduler(); if (processor_id >= 0) { scheduler.Unschedule(old_priority, processor_id, this); } @@ -508,7 +508,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { - auto& scheduler = Core::System::GetInstance().GlobalScheduler(); + auto& scheduler = kernel.System().GlobalScheduler(); if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || current_priority >= THREADPRIO_COUNT) { return; -- cgit v1.2.3 From a88238d68d6a968cb91102c71f324f4493c0f909 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 10:13:25 -0400 Subject: Kernel: Address Feedback. --- src/core/hle/kernel/kernel.h | 2 +- src/core/hle/kernel/scheduler.cpp | 53 +++++++++++++++++++++++++++---- src/core/hle/kernel/scheduler.h | 65 +++++++++++++++------------------------ src/core/hle/kernel/svc.cpp | 12 ++++---- src/core/hle/kernel/thread.cpp | 17 +++++----- src/core/hle/kernel/thread.h | 16 +++++++--- 6 files changed, 98 insertions(+), 67 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0fc4d1f363..9fb8f52ec9 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -21,11 +21,11 @@ namespace Kernel { class AddressArbiter; class ClientPort; +class GlobalScheduler; class HandleTable; class Process; class ResourceLimit; class Thread; -class GlobalScheduler; /// Represents a single instance of the kernel. class KernelCore { diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 122106267a..dabeb05d68 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -23,7 +23,7 @@ namespace Kernel { GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} { - reselection_pending = false; + is_reselection_pending = false; } void GlobalScheduler::AddThread(SharedPtr thread) { @@ -61,7 +61,7 @@ void GlobalScheduler::SelectThread(u32 core) { } sched.selected_thread = thread; } - sched.context_switch_pending = sched.selected_thread != sched.current_thread; + sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; std::atomic_thread_fence(std::memory_order_seq_cst); }; Scheduler& sched = system.Scheduler(core); @@ -318,10 +318,18 @@ void GlobalScheduler::PreemptThreads() { } } - reselection_pending.store(true, std::memory_order_release); + is_reselection_pending.store(true, std::memory_order_release); } } +void GlobalScheduler::Suggest(u32 priority, u32 core, Thread* thread) { + suggested_queue[core].add(thread, priority); +} + +void GlobalScheduler::Unsuggest(u32 priority, u32 core, Thread* thread) { + suggested_queue[core].remove(thread, priority); +} + void GlobalScheduler::Schedule(u32 priority, u32 core, Thread* thread) { ASSERT_MSG(thread->GetProcessorID() == core, "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority); @@ -332,12 +340,40 @@ void GlobalScheduler::SchedulePrepend(u32 priority, u32 core, Thread* thread) { scheduled_queue[core].add(thread, priority, false); } +void GlobalScheduler::Reschedule(u32 priority, u32 core, Thread* thread) { + scheduled_queue[core].remove(thread, priority); + scheduled_queue[core].add(thread, priority); +} + +void GlobalScheduler::Unschedule(u32 priority, u32 core, Thread* thread) { + scheduled_queue[core].remove(thread, priority); +} + +void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* thread) { + const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; + const s32 source_core = thread->GetProcessorID(); + if (source_core == destination_core || !schedulable) { + return; + } + thread->SetProcessorID(destination_core); + if (source_core >= 0) { + Unschedule(priority, source_core, thread); + } + if (destination_core >= 0) { + Unsuggest(priority, destination_core, thread); + Schedule(priority, destination_core, thread); + } + if (source_core >= 0) { + Suggest(priority, source_core, thread); + } +} + bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner) { if (current_thread == winner) { current_thread->IncrementYieldCount(); return true; } else { - reselection_pending.store(true, std::memory_order_release); + is_reselection_pending.store(true, std::memory_order_release); return false; } } @@ -378,7 +414,7 @@ u64 Scheduler::GetLastContextSwitchTicks() const { } void Scheduler::TryDoContextSwitch() { - if (context_switch_pending) { + if (is_context_switch_pending ) { SwitchContext(); } } @@ -409,7 +445,7 @@ void Scheduler::SwitchContext() { Thread* const previous_thread = GetCurrentThread(); Thread* const new_thread = GetSelectedThread(); - context_switch_pending = false; + is_context_switch_pending = false; if (new_thread == previous_thread) { return; } @@ -477,4 +513,9 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { last_context_switch_time = most_recent_switch_ticks; } +void Scheduler::Shutdown() { + current_thread = nullptr; + selected_thread = nullptr; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 617553ae36..fcae28e0a4 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -39,15 +39,11 @@ public: // Add a thread to the suggested queue of a cpu core. Suggested threads may be // picked if no thread is scheduled to run on the core. - void Suggest(u32 priority, u32 core, Thread* thread) { - suggested_queue[core].add(thread, priority); - } + void Suggest(u32 priority, u32 core, Thread* thread); // Remove a thread to the suggested queue of a cpu core. Suggested threads may be // picked if no thread is scheduled to run on the core. - void Unsuggest(u32 priority, u32 core, Thread* thread) { - suggested_queue[core].remove(thread, priority); - } + void Unsuggest(u32 priority, u32 core, Thread* thread); // Add a thread to the scheduling queue of a cpu core. The thread is added at the // back the queue in its priority level @@ -58,37 +54,15 @@ public: void SchedulePrepend(u32 priority, u32 core, Thread* thread); // Reschedule an already scheduled thread based on a new priority - void Reschedule(u32 priority, u32 core, Thread* thread) { - scheduled_queue[core].remove(thread, priority); - scheduled_queue[core].add(thread, priority); - } + void Reschedule(u32 priority, u32 core, Thread* thread); // Unschedule a thread. - void Unschedule(u32 priority, u32 core, Thread* thread) { - scheduled_queue[core].remove(thread, priority); - } + void Unschedule(u32 priority, u32 core, Thread* thread); // Transfers a thread into an specific core. If the destination_core is -1 // it will be unscheduled from its source code and added into its suggested // queue. - void TransferToCore(u32 priority, s32 destination_core, Thread* thread) { - const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; - const s32 source_core = thread->GetProcessorID(); - if (source_core == destination_core || !schedulable) { - return; - } - thread->SetProcessorID(destination_core); - if (source_core >= 0) { - Unschedule(priority, source_core, thread); - } - if (destination_core >= 0) { - Unsuggest(priority, destination_core, thread); - Schedule(priority, destination_core, thread); - } - if (source_core >= 0) { - Suggest(priority, source_core, thread); - } - } + void TransferToCore(u32 priority, s32 destination_core, Thread* thread); /* * UnloadThread selects a core and forces it to unload its current thread's context @@ -133,6 +107,12 @@ public: */ bool YieldThreadAndWaitForLoadBalancing(Thread* thread); + /* + * PreemptThreads this operation rotates the scheduling queues of threads at + * a preemption priority and then does some core rebalancing. Preemption priorities + * can be found in the array 'preemption_priorities'. This operation happens + * every 10ms. + */ void PreemptThreads(); u32 CpuCoresCount() const { @@ -140,11 +120,11 @@ public: } void SetReselectionPending() { - reselection_pending.store(true, std::memory_order_release); + is_reselection_pending.store(true, std::memory_order_release); } bool IsReselectionPending() const { - return reselection_pending.load(); + return is_reselection_pending.load(std::memory_order_acquire); } void Shutdown(); @@ -155,8 +135,10 @@ private: static constexpr u32 min_regular_priority = 2; std::array, NUM_CPU_CORES> scheduled_queue; std::array, NUM_CPU_CORES> suggested_queue; - std::atomic reselection_pending; + std::atomic is_reselection_pending; + // `preemption_priorities` are the priority levels at which the global scheduler + // preempts threads every 10 ms. They are ordered from Core 0 to Core 3 std::array preemption_priorities = {59, 59, 59, 62}; /// Lists all thread ids that aren't deleted/etc. @@ -166,7 +148,7 @@ private: class Scheduler final { public: - explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, const u32 core_id); + explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, u32 core_id); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -175,26 +157,27 @@ public: /// Reschedules to the next available thread (call after current thread is suspended) void TryDoContextSwitch(); + /// Unloads currently running thread void UnloadThread(); + /// Select the threads in top of the scheduling multilist. void SelectThreads(); /// Gets the current running thread Thread* GetCurrentThread() const; + /// Gets the currently selected thread from the top of the multilevel queue Thread* GetSelectedThread() const; /// Gets the timestamp for the last context switch in ticks. u64 GetLastContextSwitchTicks() const; bool ContextSwitchPending() const { - return context_switch_pending; + return is_context_switch_pending; } - void Shutdown() { - current_thread = nullptr; - selected_thread = nullptr; - } + /// Shutdowns the scheduler. + void Shutdown(); private: friend class GlobalScheduler; @@ -226,7 +209,7 @@ private: u64 idle_selection_count = 0; const u32 core_id; - bool context_switch_pending = false; + bool is_context_switch_pending = false; }; } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 151acf33a2..f64236be1a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1556,18 +1556,18 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { auto& scheduler = system.CurrentScheduler(); auto* const current_thread = scheduler.GetCurrentThread(); - bool redundant = false; + bool is_redundant = false; if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - redundant = current_thread->YieldSimple(); + is_redundant = current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - redundant = current_thread->YieldAndBalanceLoad(); + is_redundant = current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - redundant = current_thread->YieldAndWaitForLoadBalancing(); + is_redundant = current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1576,9 +1576,9 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { current_thread->Sleep(nanoseconds); } - if (redundant) { + if (is_redundant) { // If it's redundant, the core is pretty much idle. Some games keep idling - // a core while it's doing nothing, we advance timing to avoid costly continuos + // a core while it's doing nothing, we advance timing to avoid costly continuous // calls. system.CoreTiming().AddTicks(2000); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 7208bbb110..8663fe5eed 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -389,13 +389,13 @@ bool Thread::YieldAndWaitForLoadBalancing() { void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { const u32 old_flags = scheduling_state; - scheduling_state = - (scheduling_state & ThreadSchedMasks::HighMask) | static_cast(new_status); + scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | + static_cast(new_status); AdjustSchedulingOnStatus(old_flags); } void Thread::SetCurrentPriority(u32 new_priority) { - u32 old_priority = std::exchange(current_priority, new_priority); + const u32 old_priority = std::exchange(current_priority, new_priority); AdjustSchedulingOnPriority(old_priority); } @@ -410,10 +410,9 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { }; const bool use_override = affinity_override_count != 0; - // The value -3 is "do not change the ideal core". - if (new_core == -3) { + if (new_core == static_cast(CoreFlags::DontChangeIdealCore)) { new_core = use_override ? ideal_core_override : ideal_core; - if ((new_affinity_mask & (1 << new_core)) == 0) { + if ((new_affinity_mask & (1ULL << new_core)) == 0) { return ERR_INVALID_COMBINATION; } } @@ -444,14 +443,14 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { } auto& scheduler = kernel.GlobalScheduler(); - if (static_cast(old_flags & ThreadSchedMasks::LowMask) == + if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == ThreadSchedStatus::Runnable) { // In this case the thread was running, now it's pausing/exitting if (processor_id >= 0) { scheduler.Unschedule(current_priority, processor_id, this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Unsuggest(current_priority, core, this); } @@ -462,7 +461,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { scheduler.Schedule(current_priority, processor_id, this); } - for (u32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { + for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { scheduler.Suggest(current_priority, core, this); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index ceb4d51591..e0f3b62047 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -82,19 +82,25 @@ enum class ThreadSchedStatus : u32 { Exited = 3, }; -enum ThreadSchedFlags : u32 { +enum class ThreadSchedFlags : u32 { ProcessPauseFlag = 1 << 4, ThreadPauseFlag = 1 << 5, ProcessDebugPauseFlag = 1 << 6, KernelInitPauseFlag = 1 << 8, }; -enum ThreadSchedMasks : u32 { +enum class ThreadSchedMasks : u32 { LowMask = 0x000f, HighMask = 0xfff0, ForcePauseMask = 0x0070, }; +enum class CoreFlags : s32 { + IgnoreIdealCore = -1, + ProcessIdealCore = -2, + DontChangeIdealCore = -3, +}; + class Thread final : public WaitObject { public: using MutexWaitingThreads = std::vector>; @@ -428,7 +434,8 @@ public: } ThreadSchedStatus GetSchedulingStatus() const { - return static_cast(scheduling_state & ThreadSchedMasks::LowMask); + return static_cast(scheduling_state & + static_cast(ThreadSchedMasks::LowMask)); } bool IsRunning() const { @@ -471,7 +478,8 @@ private: u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. u64 last_running_ticks = 0; ///< CPU tick when thread was last running - u64 yield_count = 0; ///< Number of innecessaries yields occured. + u64 yield_count = 0; ///< Number of redundant yields carried by this thread. + ///< a redundant yield is one where no scheduling is changed s32 processor_id = 0; -- cgit v1.2.3 From ac9dd91f1ec3a1607f0413308623f903f31d477c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 10:21:33 -0400 Subject: Kernel: Reverse global accessor removal. --- src/core/hle/kernel/kernel.cpp | 8 -------- src/core/hle/kernel/kernel.h | 6 ------ src/core/hle/kernel/thread.cpp | 16 ++++++++-------- src/core/hle/kernel/wait_object.cpp | 2 +- 4 files changed, 9 insertions(+), 23 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0d6286f845..f94ac150d0 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -232,14 +232,6 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { return impl->global_scheduler; } -Core::System& KernelCore::System() { - return impl->system; -} - -const Core::System& KernelCore::System() const { - return impl->system; -} - void KernelCore::AddNamedPort(std::string name, SharedPtr port) { impl->named_ports.emplace(std::move(name), std::move(port)); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9fb8f52ec9..c4397fc77a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -82,12 +82,6 @@ public: /// Gets the sole instance of the global scheduler const Kernel::GlobalScheduler& GlobalScheduler() const; - /// Gets the sole instance of the system - Core::System& System(); - - /// Gets the sole instance of the system - const Core::System& System() const; - /// Adds a port to the named port table void AddNamedPort(std::string name, SharedPtr port); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8663fe5eed..0c11da1e0e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -41,7 +41,7 @@ Thread::~Thread() = default; void Thread::Stop() { // Cancel any outstanding wakeup events for this thread - kernel.System().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), + Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; @@ -68,12 +68,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); - kernel.System().CoreTiming().ScheduleEvent(cycles, kernel.ThreadWakeupCallbackEventType(), + Core::System::GetInstance().CoreTiming().ScheduleEvent(cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); } void Thread::CancelWakeupTimer() { - kernel.System().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), + Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle); } @@ -176,7 +176,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::string name return ResultCode(-1); } - auto& system = kernel.System(); + auto& system = Core::System::GetInstance(); SharedPtr thread(new Thread(kernel)); thread->thread_id = kernel.CreateNewThreadID(); @@ -258,7 +258,7 @@ void Thread::SetStatus(ThreadStatus new_status) { } if (status == ThreadStatus::Running) { - last_running_ticks = kernel.System().CoreTiming().GetTicks(); + last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); } status = new_status; @@ -356,7 +356,7 @@ void Thread::SetActivity(ThreadActivity value) { // Set status if not waiting if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { SetStatus(ThreadStatus::Paused); - kernel.System().CpuCore(processor_id).PrepareReschedule(); + Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); } } else if (status == ThreadStatus::Paused) { // Ready to reschedule @@ -475,7 +475,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { return; } - auto& scheduler = kernel.System().GlobalScheduler(); + auto& scheduler = Core::System::GetInstance().GlobalScheduler(); if (processor_id >= 0) { scheduler.Unschedule(old_priority, processor_id, this); } @@ -507,7 +507,7 @@ void Thread::AdjustSchedulingOnPriority(u32 old_priority) { } void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { - auto& scheduler = kernel.System().GlobalScheduler(); + auto& scheduler = Core::System::GetInstance().GlobalScheduler(); if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || current_priority >= THREADPRIO_COUNT) { return; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 0f833fb3ac..c00cef0629 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -95,7 +95,7 @@ void WaitObject::WakeupWaitingThread(SharedPtr thread) { } if (resume) { thread->ResumeFromWait(); - kernel.System().PrepareReschedule(thread->GetProcessorID()); + Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID()); } } -- cgit v1.2.3 From 5acd086b18daabb7b45e720a4df142e38c9a4bce Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 10:28:44 -0400 Subject: Kernel: Clang Format --- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/thread.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index dabeb05d68..e6dcb96394 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -414,7 +414,7 @@ u64 Scheduler::GetLastContextSwitchTicks() const { } void Scheduler::TryDoContextSwitch() { - if (is_context_switch_pending ) { + if (is_context_switch_pending) { SwitchContext(); } } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0c11da1e0e..3408658e5a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -42,7 +42,7 @@ Thread::~Thread() = default; void Thread::Stop() { // Cancel any outstanding wakeup events for this thread Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + callback_handle); kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); callback_handle = 0; SetStatus(ThreadStatus::Dead); @@ -68,13 +68,13 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); - Core::System::GetInstance().CoreTiming().ScheduleEvent(cycles, kernel.ThreadWakeupCallbackEventType(), - callback_handle); + Core::System::GetInstance().CoreTiming().ScheduleEvent( + cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); } void Thread::CancelWakeupTimer() { Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - callback_handle); + callback_handle); } static std::optional GetNextProcessorId(u64 mask) { -- cgit v1.2.3 From 3300a7631d42b34784fa010812c60459623fab50 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 10:38:55 -0400 Subject: Kernel: Address Feedback 2 --- src/core/hle/kernel/thread.cpp | 6 +++--- src/core/hle/kernel/thread.h | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3408658e5a..aeb20b24b0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -410,7 +410,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { }; const bool use_override = affinity_override_count != 0; - if (new_core == static_cast(CoreFlags::DontChangeIdealCore)) { + if (new_core == THREADDONTCHANGE_IDEAL) { new_core = use_override ? ideal_core_override : ideal_core; if ((new_affinity_mask & (1ULL << new_core)) == 0) { return ERR_INVALID_COMBINATION; @@ -452,7 +452,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(current_priority, core, this); + scheduler.Unsuggest(current_priority, static_cast(core), this); } } } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { @@ -463,7 +463,7 @@ void Thread::AdjustSchedulingOnStatus(u32 old_flags) { for (s32 core = 0; core < GlobalScheduler::NUM_CPU_CORES; core++) { if (core != processor_id && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, core, this); + scheduler.Suggest(current_priority, static_cast(core), this); } } } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e0f3b62047..7ee437e174 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -35,6 +35,9 @@ enum ThreadProcessorId : s32 { /// Run thread on the ideal core specified by the process. THREADPROCESSORID_IDEAL = -2, + /// when setting Core and Affiny, keeps the ideal core intact + THREADDONTCHANGE_IDEAL = -3, + /// Indicates that the preferred processor ID shouldn't be updated in /// a core mask setting operation. THREADPROCESSORID_DONT_UPDATE = -3, @@ -95,12 +98,6 @@ enum class ThreadSchedMasks : u32 { ForcePauseMask = 0x0070, }; -enum class CoreFlags : s32 { - IgnoreIdealCore = -1, - ProcessIdealCore = -2, - DontChangeIdealCore = -3, -}; - class Thread final : public WaitObject { public: using MutexWaitingThreads = std::vector>; -- cgit v1.2.3 From 4f8fa2dd29e05945b8f6b04a14c23f4277190c12 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 12 Oct 2019 10:55:34 -0400 Subject: Kernel Thread: Cleanup THREADPROCESSORID_DONT_UPDATE. --- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/thread.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index aeb20b24b0..962530d2d2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -410,7 +410,7 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { }; const bool use_override = affinity_override_count != 0; - if (new_core == THREADDONTCHANGE_IDEAL) { + if (new_core == THREADPROCESSORID_DONT_UPDATE) { new_core = use_override ? ideal_core_override : ideal_core; if ((new_affinity_mask & (1ULL << new_core)) == 0) { return ERR_INVALID_COMBINATION; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7ee437e174..c9870873d5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -35,9 +35,6 @@ enum ThreadProcessorId : s32 { /// Run thread on the ideal core specified by the process. THREADPROCESSORID_IDEAL = -2, - /// when setting Core and Affiny, keeps the ideal core intact - THREADDONTCHANGE_IDEAL = -3, - /// Indicates that the preferred processor ID shouldn't be updated in /// a core mask setting operation. THREADPROCESSORID_DONT_UPDATE = -3, -- cgit v1.2.3