Merge pull request #439 from Subv/idle_thread_m
Threads: Use a dummy idle thread when no other are ready.
This commit is contained in:
commit
91d96840ea
|
@ -5,6 +5,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/arm/disassembler/arm_disasm.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
|
/// Run the core CPU loop
|
||||||
void RunLoop(int tight_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();
|
HW::Update();
|
||||||
if (HLE::g_reschedule) {
|
if (HLE::g_reschedule) {
|
||||||
Kernel::Reschedule();
|
Kernel::Reschedule();
|
||||||
|
|
|
@ -124,6 +124,8 @@ bool LoadExec(u32 entry_point) {
|
||||||
|
|
||||||
// 0x30 is the typical main thread priority I've seen used so far
|
// 0x30 is the typical main thread priority I've seen used so far
|
||||||
g_main_thread = Kernel::SetupMainThread(0x30);
|
g_main_thread = Kernel::SetupMainThread(0x30);
|
||||||
|
// Setup the idle thread
|
||||||
|
Kernel::SetupIdleThread();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common/thread_queue_list.h"
|
#include "common/thread_queue_list.h"
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/hle.h"
|
#include "core/hle/hle.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
@ -34,6 +35,7 @@ public:
|
||||||
inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
|
inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
|
||||||
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
|
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
|
||||||
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
|
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
|
||||||
|
inline bool IsIdle() const { return idle; }
|
||||||
|
|
||||||
ResultVal<bool> WaitSynchronization() override {
|
ResultVal<bool> WaitSynchronization() override {
|
||||||
const bool wait = status != THREADSTATUS_DORMANT;
|
const bool wait = status != THREADSTATUS_DORMANT;
|
||||||
|
@ -69,6 +71,9 @@ public:
|
||||||
std::vector<Handle> waiting_threads;
|
std::vector<Handle> waiting_threads;
|
||||||
|
|
||||||
std::string name;
|
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.
|
// Lists all thread ids that aren't deleted/etc.
|
||||||
|
@ -444,7 +449,14 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) {
|
||||||
return RESULT_SUCCESS;
|
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 SetupMainThread(s32 priority, int stack_size) {
|
||||||
Handle handle;
|
Handle handle;
|
||||||
|
|
||||||
|
@ -497,6 +509,15 @@ void Reschedule() {
|
||||||
ResumeThreadFromWait(prev->GetHandle());
|
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) {
|
ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
||||||
Thread* thread = g_handle_table.Get<Thread>(handle);
|
Thread* thread = g_handle_table.Get<Thread>(handle);
|
||||||
if (thread == nullptr)
|
if (thread == nullptr)
|
||||||
|
|
|
@ -104,6 +104,17 @@ ResultVal<u32> GetThreadPriority(const Handle handle);
|
||||||
/// Set the priority of the thread specified by handle
|
/// Set the priority of the thread specified by handle
|
||||||
ResultCode SetThreadPriority(Handle handle, s32 priority);
|
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
|
/// Initialize threading
|
||||||
void ThreadingInit();
|
void ThreadingInit();
|
||||||
|
|
||||||
|
|
Reference in New Issue