From cec0d4f1918c640524fa0087549da2fab0960e24 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Feb 2018 14:46:11 -0500 Subject: kernel: Remove unused address_arbiter code. --- src/core/CMakeLists.txt | 2 - src/core/hle/kernel/address_arbiter.cpp | 91 --------------------------------- src/core/hle/kernel/address_arbiter.h | 60 ---------------------- src/core/hle/kernel/thread.cpp | 34 ------------ src/core/hle/kernel/thread.h | 12 ----- 5 files changed, 199 deletions(-) delete mode 100644 src/core/hle/kernel/address_arbiter.cpp delete mode 100644 src/core/hle/kernel/address_arbiter.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ce68194c5..2f1fd7880 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -28,8 +28,6 @@ add_library(core STATIC hle/config_mem.h hle/ipc.h hle/ipc_helpers.h - hle/kernel/address_arbiter.cpp - hle/kernel/address_arbiter.h hle/kernel/client_port.cpp hle/kernel/client_port.h hle/kernel/client_session.cpp diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp deleted file mode 100644 index 776d342f0..000000000 --- a/src/core/hle/kernel/address_arbiter.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/hle/kernel/address_arbiter.h" -#include "core/hle/kernel/errors.h" -#include "core/hle/kernel/thread.h" -#include "core/memory.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { - -AddressArbiter::AddressArbiter() {} -AddressArbiter::~AddressArbiter() {} - -SharedPtr AddressArbiter::Create(std::string name) { - SharedPtr address_arbiter(new AddressArbiter); - - address_arbiter->name = std::move(name); - - return address_arbiter; -} - -ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, - u64 nanoseconds) { - switch (type) { - - // Signal thread(s) waiting for arbitrate address... - case ArbitrationType::Signal: - // Negative value means resume all threads - if (value < 0) { - ArbitrateAllThreads(address); - } else { - // Resume first N threads - for (int i = 0; i < value; i++) - ArbitrateHighestPriorityThread(address); - } - break; - - // Wait current thread (acquire the arbiter)... - case ArbitrationType::WaitIfLessThan: - if ((s32)Memory::Read32(address) < value) { - Kernel::WaitCurrentThread_ArbitrateAddress(address); - } - break; - case ArbitrationType::WaitIfLessThanWithTimeout: - if ((s32)Memory::Read32(address) < value) { - Kernel::WaitCurrentThread_ArbitrateAddress(address); - GetCurrentThread()->WakeAfterDelay(nanoseconds); - } - break; - case ArbitrationType::DecrementAndWaitIfLessThan: { - s32 memory_value = Memory::Read32(address); - if (memory_value < value) { - // Only change the memory value if the thread should wait - Memory::Write32(address, (s32)memory_value - 1); - Kernel::WaitCurrentThread_ArbitrateAddress(address); - } - break; - } - case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { - s32 memory_value = Memory::Read32(address); - if (memory_value < value) { - // Only change the memory value if the thread should wait - Memory::Write32(address, (s32)memory_value - 1); - Kernel::WaitCurrentThread_ArbitrateAddress(address); - GetCurrentThread()->WakeAfterDelay(nanoseconds); - } - break; - } - - default: - LOG_ERROR(Kernel, "unknown type=%d", type); - return ERR_INVALID_ENUM_VALUE_FND; - } - - // The calls that use a timeout seem to always return a Timeout error even if they did not put - // the thread to sleep - if (type == ArbitrationType::WaitIfLessThanWithTimeout || - type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { - - return RESULT_TIMEOUT; - } - return RESULT_SUCCESS; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h deleted file mode 100644 index f902ddf2d..000000000 --- a/src/core/hle/kernel/address_arbiter.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/result.h" - -// Address arbiters are an underlying kernel synchronization object that can be created/used via -// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR -// applications use them as an underlying mechanism to implement thread-safe barriers, events, and -// semphores. - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { - -enum class ArbitrationType : u32 { - Signal, - WaitIfLessThan, - DecrementAndWaitIfLessThan, - WaitIfLessThanWithTimeout, - DecrementAndWaitIfLessThanWithTimeout, -}; - -class AddressArbiter final : public Object { -public: - /** - * Creates an address arbiter. - * - * @param name Optional name used for debugging. - * @returns The created AddressArbiter. - */ - static SharedPtr Create(std::string name = "Unknown"); - - std::string GetTypeName() const override { - return "Arbiter"; - } - std::string GetName() const override { - return name; - } - - static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - std::string name; ///< Name of address arbiter object (optional) - - ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); - -private: - AddressArbiter(); - ~AddressArbiter() override; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 130b669a0..0fcc65cbf 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -109,40 +109,6 @@ void Thread::Stop() { Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); } -Thread* ArbitrateHighestPriorityThread(u32 address) { - Thread* highest_priority_thread = nullptr; - u32 priority = THREADPRIO_LOWEST; - - // Iterate through threads, find highest priority thread that is waiting to be arbitrated... - for (auto& thread : thread_list) { - if (!CheckWait_AddressArbiter(thread.get(), address)) - continue; - - if (thread == nullptr) - continue; - - if (thread->current_priority <= priority) { - highest_priority_thread = thread.get(); - priority = thread->current_priority; - } - } - - // If a thread was arbitrated, resume it - if (nullptr != highest_priority_thread) { - highest_priority_thread->ResumeFromWait(); - } - - return highest_priority_thread; -} - -void ArbitrateAllThreads(u32 address) { - // Resume all threads found to be waiting on the address - for (auto& thread : thread_list) { - if (CheckWait_AddressArbiter(thread.get(), address)) - thread->ResumeFromWait(); - } -} - /** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index bbffaf4cf..aa80a51a9 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -259,18 +259,6 @@ bool HaveReadyThreads(); */ void Reschedule(); -/** - * Arbitrate the highest priority thread that is waiting - * @param address The address for which waiting threads should be arbitrated - */ -Thread* ArbitrateHighestPriorityThread(VAddr address); - -/** - * Arbitrate all threads currently waiting. - * @param address The address for which waiting threads should be arbitrated - */ -void ArbitrateAllThreads(VAddr address); - /** * Gets the current thread */ -- cgit v1.2.3 From 2d4a6883bcfa785e990c5dbf3fab9eb73a0ed277 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Feb 2018 14:52:09 -0500 Subject: core: Use shared_ptr for cpu_core. --- src/core/core.cpp | 6 +++--- src/core/core.h | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 613a98b4c..89bb2887e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -141,14 +141,14 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { switch (Settings::values.cpu_core) { case Settings::CpuCore::Unicorn: - cpu_core = std::make_unique(); + cpu_core = std::make_shared(); break; case Settings::CpuCore::Dynarmic: default: #ifdef ARCHITECTURE_x86_64 - cpu_core = std::make_unique(); + cpu_core = std::make_shared(); #else - cpu_core = std::make_unique(); + cpu_core = std::make_shared(); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif break; diff --git a/src/core/core.h b/src/core/core.h index f63cc47cc..e7599e18c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -140,9 +140,7 @@ private: /// AppLoader used to load the current executing application std::unique_ptr app_loader; - ///< ARM11 CPU core - std::unique_ptr cpu_core; - + std::shared_ptr cpu_core; std::unique_ptr gpu_core; /// When true, signals that a reschedule should happen -- cgit v1.2.3 From c78d495161355277d19bd9debc64161b1d4bb949 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Feb 2018 14:58:40 -0500 Subject: kernel: Add Scheduler, which encapsulates the scheduling loading from Thread module. --- src/core/CMakeLists.txt | 2 + src/core/hle/kernel/scheduler.cpp | 134 ++++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/scheduler.h | 74 +++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 src/core/hle/kernel/scheduler.cpp create mode 100644 src/core/hle/kernel/scheduler.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2f1fd7880..76f70a844 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -53,6 +53,8 @@ add_library(core STATIC hle/kernel/process.h hle/kernel/resource_limit.cpp hle/kernel/resource_limit.h + hle/kernel/scheduler.cpp + hle/kernel/scheduler.h hle/kernel/server_port.cpp hle/kernel/server_port.h hle/kernel/server_session.cpp diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp new file mode 100644 index 000000000..2fe0d5a38 --- /dev/null +++ b/src/core/hle/kernel/scheduler.cpp @@ -0,0 +1,134 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core_timing.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" + +namespace Kernel { + +Scheduler::Scheduler(std::shared_ptr cpu_core) : cpu_core(cpu_core) {} + +Scheduler::~Scheduler() { + for (auto& thread : thread_list) { + thread->Stop(); + } +} + +bool Scheduler::HaveReadyThreads() { + return ready_queue.get_first() != nullptr; +} + +Thread* Scheduler::GetCurrentThread() const { + return current_thread.get(); +} + +Thread* Scheduler::PopNextReadyThread() { + Thread* next = nullptr; + Thread* thread = GetCurrentThread(); + + if (thread && thread->status == THREADSTATUS_RUNNING) { + // We have to do better than the current thread. + // This call returns null when that's not possible. + next = ready_queue.pop_first_better(thread->current_priority); + if (!next) { + // Otherwise just keep going with the current thread + next = thread; + } + } else { + next = ready_queue.pop_first(); + } + + return next; +} + +void Scheduler::SwitchContext(Thread* new_thread) { + Thread* previous_thread = GetCurrentThread(); + + // Save context for previous thread + if (previous_thread) { + previous_thread->last_running_ticks = CoreTiming::GetTicks(); + cpu_core->SaveContext(previous_thread->context); + + if (previous_thread->status == THREADSTATUS_RUNNING) { + // This is only the case when a reschedule is triggered without the current thread + // yielding execution (i.e. an event triggered, system core time-sliced, etc) + ready_queue.push_front(previous_thread->current_priority, previous_thread); + previous_thread->status = THREADSTATUS_READY; + } + } + + // Load context of new thread + if (new_thread) { + ASSERT_MSG(new_thread->status == THREADSTATUS_READY, + "Thread must be ready to become running."); + + // Cancel any outstanding wakeup events for this thread + new_thread->CancelWakeupTimer(); + + auto previous_process = Kernel::g_current_process; + + current_thread = new_thread; + + ready_queue.remove(new_thread->current_priority, new_thread); + new_thread->status = THREADSTATUS_RUNNING; + + if (previous_process != current_thread->owner_process) { + Kernel::g_current_process = current_thread->owner_process; + SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); + } + + cpu_core->LoadContext(new_thread->context); + cpu_core->SetTlsAddress(new_thread->GetTLSAddress()); + } else { + current_thread = nullptr; + // Note: We do not reset the current process and current page table when idling because + // technically we haven't changed processes, our threads are just paused. + } +} + +void Scheduler::Reschedule() { + Thread* cur = GetCurrentThread(); + Thread* next = PopNextReadyThread(); + + if (cur && next) { + LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); + } else if (cur) { + LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); + } else if (next) { + LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); + } + + SwitchContext(next); +} + +void Scheduler::AddThread(SharedPtr thread, u32 priority) { + thread_list.push_back(thread); + ready_queue.prepare(priority); +} + +void Scheduler::RemoveThread(Thread* thread) { + thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), + thread_list.end()); +} + +void Scheduler::ScheduleThread(Thread* thread, u32 priority) { + ASSERT(thread->status == THREADSTATUS_READY); + ready_queue.push_back(priority, thread); +} + +void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { + ASSERT(thread->status == THREADSTATUS_READY); + ready_queue.remove(priority, thread); +} + +void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { + // If thread was ready, adjust queues + if (thread->status == THREADSTATUS_READY) + ready_queue.move(thread, thread->current_priority, priority); + else + ready_queue.prepare(priority); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h new file mode 100644 index 000000000..72e658ec6 --- /dev/null +++ b/src/core/hle/kernel/scheduler.h @@ -0,0 +1,74 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.h" +#include "common/thread_queue_list.h" +#include "core/arm/arm_interface.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +class Scheduler final { +public: + Scheduler(std::shared_ptr cpu_core); + ~Scheduler(); + + /// Returns whether there are any threads that are ready to run. + bool HaveReadyThreads(); + + /// Reschedules to the next available thread (call after current thread is suspended) + void Reschedule(); + + /// Gets the current running thread + Thread* GetCurrentThread() const; + + /// Adds a new thread to the scheduler + void AddThread(SharedPtr thread, u32 priority); + + /// Removes a thread from the scheduler + void RemoveThread(Thread* thread); + + /// Schedules a thread that has become "ready" + void ScheduleThread(Thread* thread, u32 priority); + + /// Unschedules a thread that was already scheduled + void UnscheduleThread(Thread* thread, u32 priority); + + /// Sets the priority of a thread in the scheduler + void SetThreadPriority(Thread* thread, u32 priority); + + /// Returns a list of all threads managed by the scheduler + const std::vector>& GetThreadList() const { + return thread_list; + } + +private: + /** + * Pops and returns the next thread from the thread queue + * @return A pointer to the next ready thread + */ + Thread* PopNextReadyThread(); + + /** + * Switches the CPU's active thread context to that of the specified thread + * @param new_thread The thread to switch to + */ + void SwitchContext(Thread* new_thread); + + /// Lists all thread ids that aren't deleted/etc. + std::vector> thread_list; + + /// Lists only ready thread ids. + Common::ThreadQueueList ready_queue; + + SharedPtr current_thread = nullptr; + + std::shared_ptr cpu_core; +}; + +} // namespace Kernel -- cgit v1.2.3 From ac81c02ed9401b137e83bece2edd6dee8d0a0af2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Feb 2018 15:17:16 -0500 Subject: kernel: Use Scheduler class for threading. --- src/core/core.cpp | 3 +- src/core/core.h | 6 ++ src/core/hle/kernel/svc.cpp | 4 +- src/core/hle/kernel/thread.cpp | 169 ++++------------------------------------ src/core/hle/kernel/thread.h | 15 ---- src/yuzu/debugger/wait_tree.cpp | 3 +- 6 files changed, 26 insertions(+), 174 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 89bb2887e..cef697dfe 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -133,7 +133,7 @@ void System::Reschedule() { } reschedule_pending = false; - Kernel::Reschedule(); + Core::System::GetInstance().Scheduler().Reschedule(); } System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { @@ -154,6 +154,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { break; } + scheduler = std::make_unique(cpu_core); gpu_core = std::make_unique(); telemetry_session = std::make_unique(); diff --git a/src/core/core.h b/src/core/core.h index e7599e18c..ada23b347 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/kernel/scheduler.h" #include "core/loader/loader.h" #include "core/memory.h" #include "core/perf_stats.h" @@ -107,6 +108,10 @@ public: return *gpu_core; } + Kernel::Scheduler& Scheduler() { + return *scheduler; + } + PerfStats perf_stats; FrameLimiter frame_limiter; @@ -141,6 +146,7 @@ private: std::unique_ptr app_loader; std::shared_ptr cpu_core; + std::unique_ptr scheduler; std::unique_ptr gpu_core; /// When true, signals that a reschedule should happen diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4d20ef134..cbd5b69aa 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -483,7 +483,7 @@ static void ExitProcess() { g_current_process->status = ProcessStatus::Exited; // Stop all the process threads that are currently waiting for objects. - auto& thread_list = GetThreadList(); + auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); for (auto& thread : thread_list) { if (thread->owner_process != g_current_process) continue; @@ -585,7 +585,7 @@ static void SleepThread(s64 nanoseconds) { // Don't attempt to yield execution if there are no available threads to run, // this way we avoid a useless reschedule to the idle thread. - if (nanoseconds == 0 && !HaveReadyThreads()) + if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) return; // Sleep current thread and check for next thread to schedule diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0fcc65cbf..dd0a8ae48 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -41,14 +41,6 @@ void Thread::Acquire(Thread* thread) { // us to simply use a pool index or similar. static Kernel::HandleTable wakeup_callback_handle_table; -// Lists all thread ids that aren't deleted/etc. -static std::vector> thread_list; - -// Lists only ready thread ids. -static Common::ThreadQueueList ready_queue; - -static SharedPtr current_thread; - // The first available thread id at startup static u32 next_thread_id; @@ -63,10 +55,6 @@ inline static u32 const NewThreadId() { Thread::Thread() {} Thread::~Thread() {} -Thread* GetCurrentThread() { - return current_thread.get(); -} - /** * Check if the specified thread is waiting on the specified address to be arbitrated * @param thread The thread to test @@ -86,7 +74,7 @@ void Thread::Stop() { // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) if (status == THREADSTATUS_READY) { - ready_queue.remove(current_priority, this); + Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority); } status = THREADSTATUS_DEAD; @@ -109,78 +97,6 @@ void Thread::Stop() { Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); } -/** - * Switches the CPU's active thread context to that of the specified thread - * @param new_thread The thread to switch to - */ -static void SwitchContext(Thread* new_thread) { - Thread* previous_thread = GetCurrentThread(); - - // Save context for previous thread - if (previous_thread) { - previous_thread->last_running_ticks = CoreTiming::GetTicks(); - Core::CPU().SaveContext(previous_thread->context); - - if (previous_thread->status == THREADSTATUS_RUNNING) { - // This is only the case when a reschedule is triggered without the current thread - // yielding execution (i.e. an event triggered, system core time-sliced, etc) - ready_queue.push_front(previous_thread->current_priority, previous_thread); - previous_thread->status = THREADSTATUS_READY; - } - } - - // Load context of new thread - if (new_thread) { - ASSERT_MSG(new_thread->status == THREADSTATUS_READY, - "Thread must be ready to become running."); - - // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); - - auto previous_process = Kernel::g_current_process; - - current_thread = new_thread; - - ready_queue.remove(new_thread->current_priority, new_thread); - new_thread->status = THREADSTATUS_RUNNING; - - if (previous_process != current_thread->owner_process) { - Kernel::g_current_process = current_thread->owner_process; - SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); - } - - Core::CPU().LoadContext(new_thread->context); - Core::CPU().SetTlsAddress(new_thread->GetTLSAddress()); - } else { - current_thread = nullptr; - // Note: We do not reset the current process and current page table when idling because - // technically we haven't changed processes, our threads are just paused. - } -} - -/** - * Pops and returns the next thread from the thread queue - * @return A pointer to the next ready thread - */ -static Thread* PopNextReadyThread() { - Thread* next; - Thread* thread = GetCurrentThread(); - - if (thread && thread->status == THREADSTATUS_RUNNING) { - // We have to do better than the current thread. - // This call returns null when that's not possible. - next = ready_queue.pop_first_better(thread->current_priority); - if (!next) { - // Otherwise just keep going with the current thread - next = thread; - } - } else { - next = ready_queue.pop_first(); - } - - return next; -} - void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); thread->status = THREADSTATUS_WAIT_SLEEP; @@ -195,8 +111,7 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { void ExitCurrentThread() { Thread* thread = GetCurrentThread(); thread->Stop(); - thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), - thread_list.end()); + Core::System::GetInstance().Scheduler().RemoveThread(thread); } /** @@ -274,31 +189,11 @@ void Thread::ResumeFromWait() { wakeup_callback = nullptr; - ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; + Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority); Core::System::GetInstance().PrepareReschedule(); } -/** - * Prints the thread queue for debugging purposes - */ -static void DebugThreadQueue() { - Thread* thread = GetCurrentThread(); - if (!thread) { - LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); - } else { - LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, - GetCurrentThread()->GetObjectId()); - } - - for (auto& t : thread_list) { - u32 priority = ready_queue.contains(t.get()); - if (priority != -1) { - LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId()); - } - } -} - /** * Finds a free location for the TLS section of a thread. * @param tls_slots The TLS page array of the thread's owner process. @@ -366,8 +261,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, SharedPtr thread(new Thread); - thread_list.push_back(thread); - ready_queue.prepare(priority); + Core::System::GetInstance().Scheduler().AddThread(thread, priority); thread->thread_id = NewThreadId(); thread->status = THREADSTATUS_DORMANT; @@ -438,12 +332,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, void Thread::SetPriority(u32 priority) { ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); - // If thread was ready, adjust queues - if (status == THREADSTATUS_READY) - ready_queue.move(this, current_priority, priority); - else - ready_queue.prepare(priority); - + Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); nominal_priority = current_priority = priority; } @@ -457,11 +346,7 @@ void Thread::UpdatePriority() { } void Thread::BoostPriority(u32 priority) { - // If thread was ready, adjust queues - if (status == THREADSTATUS_READY) - ready_queue.move(this, current_priority, priority); - else - ready_queue.prepare(priority); + Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); current_priority = priority; } @@ -487,25 +372,6 @@ SharedPtr SetupMainThread(VAddr entry_point, u32 priority, return thread; } -bool HaveReadyThreads() { - return ready_queue.get_first() != nullptr; -} - -void Reschedule() { - Thread* cur = GetCurrentThread(); - Thread* next = PopNextReadyThread(); - - if (cur && next) { - LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); - } else if (cur) { - LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); - } else if (next) { - LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); - } - - SwitchContext(next); -} - void Thread::SetWaitSynchronizationResult(ResultCode result) { context.cpu_registers[0] = result.raw; } @@ -528,25 +394,18 @@ VAddr Thread::GetCommandBufferAddress() const { //////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the current thread + */ +Thread* GetCurrentThread() { + return Core::System::GetInstance().Scheduler().GetCurrentThread(); +} + void ThreadingInit() { ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); - - current_thread = nullptr; next_thread_id = 1; } -void ThreadingShutdown() { - current_thread = nullptr; - - for (auto& t : thread_list) { - t->Stop(); - } - thread_list.clear(); - ready_queue.clear(); -} - -const std::vector>& GetThreadList() { - return thread_list; -} +void ThreadingShutdown() {} } // namespace Kernel diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index aa80a51a9..4fd2fc2f8 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -249,16 +249,6 @@ private: SharedPtr SetupMainThread(VAddr entry_point, u32 priority, SharedPtr owner_process); -/** - * Returns whether there are any threads that are ready to run. - */ -bool HaveReadyThreads(); - -/** - * Reschedules to the next available thread (call after current thread is suspended) - */ -void Reschedule(); - /** * Gets the current thread */ @@ -290,9 +280,4 @@ void ThreadingInit(); */ void ThreadingShutdown(); -/** - * Get a const reference to the thread list for debug use - */ -const std::vector>& GetThreadList(); - } // namespace Kernel diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index e4a6d16ae..7a62f57b5 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -5,6 +5,7 @@ #include "yuzu/debugger/wait_tree.h" #include "yuzu/util/util.h" +#include "core/core.h" #include "core/hle/kernel/condition_variable.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" @@ -50,7 +51,7 @@ std::size_t WaitTreeItem::Row() const { } std::vector> WaitTreeItem::MakeThreadItemList() { - const auto& threads = Kernel::GetThreadList(); + const auto& threads = Core::System::GetInstance().Scheduler().GetThreadList(); std::vector> item_list; item_list.reserve(threads.size()); for (std::size_t i = 0; i < threads.size(); ++i) { -- cgit v1.2.3 From 8db80d8389689af5f1b8bf7f8a01f98b9cea4c09 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 19 Feb 2018 16:46:42 -0500 Subject: scheduler: Cleanup based on PR feedback. --- src/core/core.cpp | 2 +- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/scheduler.h | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index cef697dfe..8c5dd3761 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -154,7 +154,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { break; } - scheduler = std::make_unique(cpu_core); + scheduler = std::make_unique(cpu_core.get()); gpu_core = std::make_unique(); telemetry_session = std::make_unique(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 2fe0d5a38..235068b22 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -8,7 +8,7 @@ namespace Kernel { -Scheduler::Scheduler(std::shared_ptr cpu_core) : cpu_core(cpu_core) {} +Scheduler::Scheduler(ARM_Interface* cpu_core) : cpu_core(cpu_core) {} Scheduler::~Scheduler() { for (auto& thread : thread_list) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 72e658ec6..27d0247d6 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include "common/common_types.h" #include "common/thread_queue_list.h" @@ -15,7 +14,7 @@ namespace Kernel { class Scheduler final { public: - Scheduler(std::shared_ptr cpu_core); + explicit Scheduler(ARM_Interface* cpu_core); ~Scheduler(); /// Returns whether there are any threads that are ready to run. @@ -68,7 +67,7 @@ private: SharedPtr current_thread = nullptr; - std::shared_ptr cpu_core; + ARM_Interface* cpu_core; }; } // namespace Kernel -- cgit v1.2.3