diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ef9dbafa5..6f61d526a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include -#include #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/config_mem.h" @@ -34,10 +33,17 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { SharedPtr WaitObject::GetHighestPriorityReadyThread() { // Remove the threads that are ready or already running from our waitlist - boost::range::remove_erase_if(waiting_threads, [](const SharedPtr& thread) { - return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY || - thread->status == THREADSTATUS_DEAD; - }); + auto to_remove = waiting_threads.end(); + do { + to_remove = std::find_if(waiting_threads.begin(), waiting_threads.end(), + [](const SharedPtr& thread) { + return thread->status == THREADSTATUS_RUNNING || + thread->status == THREADSTATUS_READY || + thread->status == THREADSTATUS_DEAD; + }); + // Call RemoveWaitingThread so that child classes can override the behavior. + RemoveWaitingThread(to_remove->get()); + } while (to_remove != waiting_threads.end()); Thread* candidate = nullptr; s32 candidate_priority = THREADPRIO_LOWEST + 1; @@ -49,9 +55,10 @@ SharedPtr WaitObject::GetHighestPriorityReadyThread() { if (ShouldWait(thread.get())) continue; - bool ready_to_run = - std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), - [&thread](const SharedPtr& object) { return object->ShouldWait(thread.get()); }); + bool ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), + [&thread](const SharedPtr& object) { + return object->ShouldWait(thread.get()); + }); if (ready_to_run) { candidate = thread.get(); candidate_priority = thread->current_priority; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2680f89c9..05097824b 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -151,7 +151,7 @@ public: * Removes a thread from waiting on this object (e.g. if it was resumed already) * @param thread Pointer to thread to remove */ - void RemoveWaitingThread(Thread* thread); + virtual void RemoveWaitingThread(Thread* thread); /** * Wake up all threads waiting on this object that can be awoken, in priority order, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index e83717e80..84ff65150 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -28,6 +28,23 @@ static void UpdateThreadPriority(Thread* thread) { thread->SetPriority(best_priority); } +/** + * Elevate the mutex priority to the best priority + * among the priorities of all its waiting threads. + */ +static void UpdateMutexPriority(Mutex* mutex) { + s32 best_priority = THREADPRIO_LOWEST; + for (auto& waiter : mutex->GetWaitingThreads()) { + if (waiter->current_priority < best_priority) + best_priority = waiter->current_priority; + } + + if (best_priority != mutex->priority) { + mutex->priority = best_priority; + UpdateThreadPriority(mutex->holding_thread.get()); + } +} + void ReleaseThreadMutexes(Thread* thread) { for (auto& mtx : thread->held_mutexes) { mtx->lock_count = 0; @@ -93,20 +110,12 @@ void Mutex::Release() { void Mutex::AddWaitingThread(SharedPtr thread) { WaitObject::AddWaitingThread(thread); + UpdateMutexPriority(this); +} - // Elevate the mutex priority to the best priority - // among the priorities of all its waiting threads. - - s32 best_priority = THREADPRIO_LOWEST; - for (auto& waiter : GetWaitingThreads()) { - if (waiter->current_priority < best_priority) - best_priority = waiter->current_priority; - } - - if (best_priority != priority) { - priority = best_priority; - UpdateThreadPriority(holding_thread.get()); - } +void Mutex::RemoveWaitingThread(Thread* thread) { + WaitObject::RemoveWaitingThread(thread); + UpdateMutexPriority(this); } } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 3e6adeb17..31f920516 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -43,6 +43,7 @@ public: void Acquire(Thread* thread) override; void AddWaitingThread(SharedPtr thread) override; + void RemoveWaitingThread(Thread* thread) override; void Release(); diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 5d6359344..b6e34a9e9 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -373,8 +373,9 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha return ERR_SYNC_TIMEOUT; } else { // Find the first object that is acquirable in the provided list of objects - auto itr = std::find_if(objects.begin(), objects.end(), - [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); }); + auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { + return !object->ShouldWait(thread); + }); if (itr != objects.end()) { // We found a ready object, acquire it and set the result value