diff options
author | Subv <subv2112@gmail.com> | 2015-01-07 10:10:58 -0500 |
---|---|---|
committer | Subv <subv2112@gmail.com> | 2015-01-07 20:31:31 -0500 |
commit | 60a373a7862a85b8b030ea1b18d01d364ddf8a8b (patch) | |
tree | e9e6288406b16f2a8dd10236c96567a895af3410 /src/core | |
parent | b659cac2dc67ee97297049fcfb02c1ce186ffcb0 (diff) |
Threads: Use a dummy idle thread when no other are ready.
This thread will not actually execute instructions, it will only advance the timing/events and try to yield immediately to the next ready thread, if there aren't any ready threads then it will be rescheduled and start its job again.
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/core.cpp | 13 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 23 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 11 |
4 files changed, 47 insertions, 2 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 8ac4481ccb..98f8a7dffd 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -5,6 +5,7 @@ #include "common/common_types.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/settings.h" #include "core/arm/disassembler/arm_disasm.h" @@ -23,7 +24,17 @@ ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core /// Run the core CPU loop void RunLoop(int tight_loop) { - g_app_core->Run(tight_loop); + // If the current thread is an idle thread, then don't execute instructions, + // instead advance to the next event and try to yield to the next thread + if (Kernel::IsIdleThread(Kernel::GetCurrentThreadHandle())) { + LOG_TRACE(Core_ARM11, "Idling"); + CoreTiming::Idle(); + CoreTiming::Advance(); + HLE::Reschedule(__func__); + } else { + g_app_core->Run(tight_loop); + } + HW::Update(); if (HLE::g_reschedule) { Kernel::Reschedule(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e59ed1b57c..ae2c11a1ca 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -124,6 +124,8 @@ bool LoadExec(u32 entry_point) { // 0x30 is the typical main thread priority I've seen used so far g_main_thread = Kernel::SetupMainThread(0x30); + // Setup the idle thread + Kernel::SetupIdleThread(); return true; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d764511462..58fb62e898 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -11,6 +11,7 @@ #include "common/thread_queue_list.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" @@ -34,6 +35,7 @@ public: inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } + inline bool IsIdle() const { return idle; } ResultVal<bool> WaitSynchronization() override { const bool wait = status != THREADSTATUS_DORMANT; @@ -69,6 +71,9 @@ public: std::vector<Handle> waiting_threads; std::string name; + + /// Whether this thread is intended to never actually be executed, i.e. always idle + bool idle = false; }; // Lists all thread ids that aren't deleted/etc. @@ -444,7 +449,14 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { return RESULT_SUCCESS; } -/// Sets up the primary application thread +Handle SetupIdleThread() { + Handle handle; + Thread* thread = CreateThread(handle, "idle", 0, THREADPRIO_LOWEST, THREADPROCESSORID_0, 0, 0); + thread->idle = true; + CallThread(thread); + return handle; +} + Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; @@ -497,6 +509,15 @@ void Reschedule() { ResumeThreadFromWait(prev->GetHandle()); } +bool IsIdleThread(Handle handle) { + Thread* thread = g_handle_table.Get<Thread>(handle); + if (!thread) { + LOG_ERROR(Kernel, "Thread not found %u", handle); + return false; + } + return thread->IsIdle(); +} + ResultCode GetThreadId(u32* thread_id, Handle handle) { Thread* thread = g_handle_table.Get<Thread>(handle); if (thread == nullptr) diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0e1397cd96..dfe92d162a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -104,6 +104,17 @@ ResultVal<u32> GetThreadPriority(const Handle handle); /// Set the priority of the thread specified by handle ResultCode SetThreadPriority(Handle handle, s32 priority); +/** + * Sets up the idle thread, this is a thread that is intended to never execute instructions, + * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue + * and will try to yield on every call. + * @returns The handle of the idle thread + */ +Handle SetupIdleThread(); + +/// Whether the current thread is an idle thread +bool IsIdleThread(Handle thread); + /// Initialize threading void ThreadingInit(); |