Merge pull request #751 from yuriks/idle-thread
Thread: Remove the idle thread
This commit is contained in:
commit
ee8da4c356
|
@ -24,9 +24,9 @@ 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) {
|
||||||
// If the current thread is an idle thread, then don't execute instructions,
|
// If we don't have a currently active thread then don't execute instructions,
|
||||||
// instead advance to the next event and try to yield to the next thread
|
// instead advance to the next event and try to yield to the next thread
|
||||||
if (Kernel::GetCurrentThread()->IsIdle()) {
|
if (Kernel::GetCurrentThread() == nullptr) {
|
||||||
LOG_TRACE(Core_ARM11, "Idling");
|
LOG_TRACE(Core_ARM11, "Idling");
|
||||||
CoreTiming::Idle();
|
CoreTiming::Idle();
|
||||||
CoreTiming::Advance();
|
CoreTiming::Advance();
|
||||||
|
|
|
@ -158,7 +158,7 @@ static void PriorityBoostStarvedThreads() {
|
||||||
|
|
||||||
u64 delta = current_ticks - thread->last_running_ticks;
|
u64 delta = current_ticks - thread->last_running_ticks;
|
||||||
|
|
||||||
if (thread->status == THREADSTATUS_READY && delta > boost_timeout && !thread->idle) {
|
if (thread->status == THREADSTATUS_READY && delta > boost_timeout) {
|
||||||
const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
|
const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
|
||||||
thread->BoostPriority(priority);
|
thread->BoostPriority(priority);
|
||||||
}
|
}
|
||||||
|
@ -170,8 +170,6 @@ static void PriorityBoostStarvedThreads() {
|
||||||
* @param new_thread The thread to switch to
|
* @param new_thread The thread to switch to
|
||||||
*/
|
*/
|
||||||
static void SwitchContext(Thread* new_thread) {
|
static void SwitchContext(Thread* new_thread) {
|
||||||
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
|
|
||||||
|
|
||||||
Thread* previous_thread = GetCurrentThread();
|
Thread* previous_thread = GetCurrentThread();
|
||||||
|
|
||||||
// Save context for previous thread
|
// Save context for previous thread
|
||||||
|
@ -189,6 +187,8 @@ static void SwitchContext(Thread* new_thread) {
|
||||||
|
|
||||||
// Load context of new thread
|
// Load context of new thread
|
||||||
if (new_thread) {
|
if (new_thread) {
|
||||||
|
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
|
||||||
|
|
||||||
current_thread = new_thread;
|
current_thread = new_thread;
|
||||||
|
|
||||||
ready_queue.remove(new_thread->current_priority, new_thread);
|
ready_queue.remove(new_thread->current_priority, new_thread);
|
||||||
|
@ -216,6 +216,10 @@ static Thread* PopNextReadyThread() {
|
||||||
// We have to do better than the current thread.
|
// We have to do better than the current thread.
|
||||||
// This call returns null when that's not possible.
|
// This call returns null when that's not possible.
|
||||||
next = ready_queue.pop_first_better(thread->current_priority);
|
next = ready_queue.pop_first_better(thread->current_priority);
|
||||||
|
if (!next) {
|
||||||
|
// Otherwise just keep going with the current thread
|
||||||
|
next = thread;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
next = ready_queue.pop_first();
|
next = ready_queue.pop_first();
|
||||||
}
|
}
|
||||||
|
@ -452,16 +456,6 @@ void Thread::BoostPriority(s32 priority) {
|
||||||
current_priority = priority;
|
current_priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Thread> SetupIdleThread() {
|
|
||||||
// We need to pass a few valid values to get around parameter checking in Thread::Create.
|
|
||||||
// TODO(yuriks): Figure out a way to avoid passing the bogus VAddr parameter
|
|
||||||
auto thread = Thread::Create("idle", Memory::TLS_AREA_VADDR, THREADPRIO_LOWEST, 0,
|
|
||||||
THREADPROCESSORID_0, 0).MoveFrom();
|
|
||||||
|
|
||||||
thread->idle = true;
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
|
SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
|
||||||
DEBUG_ASSERT(!GetCurrentThread());
|
DEBUG_ASSERT(!GetCurrentThread());
|
||||||
|
|
||||||
|
@ -478,24 +472,25 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reschedule() {
|
void Reschedule() {
|
||||||
Thread* prev = GetCurrentThread();
|
|
||||||
|
|
||||||
PriorityBoostStarvedThreads();
|
PriorityBoostStarvedThreads();
|
||||||
|
|
||||||
|
Thread* cur = GetCurrentThread();
|
||||||
Thread* next = PopNextReadyThread();
|
Thread* next = PopNextReadyThread();
|
||||||
HLE::g_reschedule = false;
|
HLE::g_reschedule = false;
|
||||||
|
|
||||||
if (next != nullptr) {
|
// Don't bother switching to the same thread
|
||||||
LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId());
|
if (next == cur)
|
||||||
SwitchContext(next);
|
return;
|
||||||
} else {
|
|
||||||
LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId());
|
|
||||||
|
|
||||||
for (auto& thread : thread_list) {
|
if (cur && next) {
|
||||||
LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),
|
LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
|
||||||
thread->current_priority, thread->status);
|
} else if (cur) {
|
||||||
}
|
LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId());
|
||||||
|
} else {
|
||||||
|
LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwitchContext(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::SetWaitSynchronizationResult(ResultCode result) {
|
void Thread::SetWaitSynchronizationResult(ResultCode result) {
|
||||||
|
@ -520,9 +515,6 @@ void ThreadingInit() {
|
||||||
|
|
||||||
thread_list.clear();
|
thread_list.clear();
|
||||||
ready_queue.clear();
|
ready_queue.clear();
|
||||||
|
|
||||||
// Setup the idle thread
|
|
||||||
SetupIdleThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadingShutdown() {
|
void ThreadingShutdown() {
|
||||||
|
|
|
@ -72,12 +72,6 @@ public:
|
||||||
bool ShouldWait() override;
|
bool ShouldWait() override;
|
||||||
void Acquire() override;
|
void Acquire() override;
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the thread is an idle (stub) thread
|
|
||||||
* @return True if the thread is an idle (stub) thread, false otherwise
|
|
||||||
*/
|
|
||||||
inline bool IsIdle() const { return idle; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the thread's current priority
|
* Gets the thread's current priority
|
||||||
* @return The current thread's priority
|
* @return The current thread's priority
|
||||||
|
@ -170,9 +164,6 @@ public:
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
/// Whether this thread is intended to never actually be executed, i.e. always idle
|
|
||||||
bool idle = false;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread();
|
Thread();
|
||||||
~Thread() override;
|
~Thread() override;
|
||||||
|
@ -230,14 +221,6 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
|
||||||
*/
|
*/
|
||||||
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
|
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* @return The handle of the idle thread
|
|
||||||
*/
|
|
||||||
SharedPtr<Thread> SetupIdleThread();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize threading
|
* Initialize threading
|
||||||
*/
|
*/
|
||||||
|
|
Reference in New Issue