mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 08:59:03 -06:00 
			
		
		
		
	Kernel/Mutex: Update a mutex priority when a thread stops waiting on it.
This commit is contained in:
		@@ -3,7 +3,6 @@
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <boost/range/algorithm_ext/erase.hpp>
 | 
			
		||||
#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<Thread> WaitObject::GetHighestPriorityReadyThread() {
 | 
			
		||||
    // Remove the threads that are ready or already running from our waitlist
 | 
			
		||||
    boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& 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>& 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<Thread> 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<WaitObject>& object) { return object->ShouldWait(thread.get()); });
 | 
			
		||||
        bool ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
 | 
			
		||||
                                        [&thread](const SharedPtr<WaitObject>& object) {
 | 
			
		||||
                                            return object->ShouldWait(thread.get());
 | 
			
		||||
                                        });
 | 
			
		||||
        if (ready_to_run) {
 | 
			
		||||
            candidate = thread.get();
 | 
			
		||||
            candidate_priority = thread->current_priority;
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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> 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
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ public:
 | 
			
		||||
    void Acquire(Thread* thread) override;
 | 
			
		||||
 | 
			
		||||
    void AddWaitingThread(SharedPtr<Thread> thread) override;
 | 
			
		||||
    void RemoveWaitingThread(Thread* thread) override;
 | 
			
		||||
 | 
			
		||||
    void Release();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user