mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Kernel/Mutex: Update a mutex priority when a thread stops waiting on it.
This commit is contained in:
		
							parent
							
								
									7abf185390
								
							
						
					
					
						commit
						b6a0355568
					
				
					 5 changed files with 42 additions and 24 deletions
				
			
		|  | @ -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
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue