summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-02-19 23:23:05 +0100
committerGitHub <noreply@github.com>2018-02-19 23:23:05 +0100
commit23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9 (patch)
tree48ce770db1df193eba107183d52f03543c81f355
parentMerge pull request #203 from Subv/ensure_save_data (diff)
parentscheduler: Cleanup based on PR feedback. (diff)
downloadyuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar.gz
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar.bz2
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar.lz
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar.xz
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.tar.zst
yuzu-23fe6f5be33ecf329a95c6b0e5f7e4c75917cef9.zip
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp91
-rw-r--r--src/core/hle/kernel/address_arbiter.h60
-rw-r--r--src/core/hle/kernel/scheduler.cpp134
-rw-r--r--src/core/hle/kernel/scheduler.h73
-rw-r--r--src/core/hle/kernel/svc.cpp4
-rw-r--r--src/core/hle/kernel/thread.cpp203
-rw-r--r--src/core/hle/kernel/thread.h27
-rw-r--r--src/yuzu/debugger/wait_tree.cpp3
11 files changed, 239 insertions, 379 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ce68194c5..76f70a844 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
@@ -55,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/core.cpp b/src/core/core.cpp
index 613a98b4c..8c5dd3761 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) {
@@ -141,19 +141,20 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
switch (Settings::values.cpu_core) {
case Settings::CpuCore::Unicorn:
- cpu_core = std::make_unique<ARM_Unicorn>();
+ cpu_core = std::make_shared<ARM_Unicorn>();
break;
case Settings::CpuCore::Dynarmic:
default:
#ifdef ARCHITECTURE_x86_64
- cpu_core = std::make_unique<ARM_Dynarmic>();
+ cpu_core = std::make_shared<ARM_Dynarmic>();
#else
- cpu_core = std::make_unique<ARM_Unicorn>();
+ cpu_core = std::make_shared<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
break;
}
+ scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
gpu_core = std::make_unique<Tegra::GPU>();
telemetry_session = std::make_unique<Core::TelemetrySession>();
diff --git a/src/core/core.h b/src/core/core.h
index f63cc47cc..ada23b347 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
#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;
@@ -140,9 +145,8 @@ private:
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
- ///< ARM11 CPU core
- std::unique_ptr<ARM_Interface> cpu_core;
-
+ std::shared_ptr<ARM_Interface> cpu_core;
+ std::unique_ptr<Kernel::Scheduler> scheduler;
std::unique_ptr<Tegra::GPU> gpu_core;
/// When true, signals that a reschedule should happen
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> AddressArbiter::Create(std::string name) {
- SharedPtr<AddressArbiter> 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<AddressArbiter> 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/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
new file mode 100644
index 000000000..235068b22
--- /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(ARM_Interface* 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> 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..27d0247d6
--- /dev/null
+++ b/src/core/hle/kernel/scheduler.h
@@ -0,0 +1,73 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#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:
+ explicit Scheduler(ARM_Interface* 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> 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<SharedPtr<Thread>>& 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<SharedPtr<Thread>> thread_list;
+
+ /// Lists only ready thread ids.
+ Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
+
+ SharedPtr<Thread> current_thread = nullptr;
+
+ ARM_Interface* cpu_core;
+};
+
+} // namespace Kernel
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 130b669a0..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<SharedPtr<Thread>> thread_list;
-
-// Lists only ready thread ids.
-static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
-
-static SharedPtr<Thread> 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,112 +97,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
- */
-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;
@@ -229,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);
}
/**
@@ -308,32 +189,12 @@ 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.
* Returns a tuple of (page, slot, alloc_needed) where:
@@ -400,8 +261,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
SharedPtr<Thread> 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;
@@ -472,12 +332,7 @@ ResultVal<SharedPtr<Thread>> 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;
}
@@ -491,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;
}
@@ -521,25 +372,6 @@ SharedPtr<Thread> 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;
}
@@ -562,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<SharedPtr<Thread>>& 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 bbffaf4cf..4fd2fc2f8 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -250,28 +250,6 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
SharedPtr<Process> 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();
-
-/**
- * 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
*/
Thread* GetCurrentThread();
@@ -302,9 +280,4 @@ void ThreadingInit();
*/
void ThreadingShutdown();
-/**
- * Get a const reference to the thread list for debug use
- */
-const std::vector<SharedPtr<Thread>>& 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<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
- const auto& threads = Kernel::GetThreadList();
+ const auto& threads = Core::System::GetInstance().Scheduler().GetThreadList();
std::vector<std::unique_ptr<WaitTreeThread>> item_list;
item_list.reserve(threads.size());
for (std::size_t i = 0; i < threads.size(); ++i) {