diff options
| author | 2017-01-02 19:38:08 -0500 | |
|---|---|---|
| committer | 2017-01-04 15:58:48 -0500 | |
| commit | d3ff5b91e14356912589f9bac47fccbe79e07279 (patch) | |
| tree | e35c698d40539e360981a61b38f8fbb60aee7418 /src/core/hle/kernel/mutex.cpp | |
| parent | Kernel/Mutex: Update a mutex priority when a thread stops waiting on it. (diff) | |
| download | yuzu-d3ff5b91e14356912589f9bac47fccbe79e07279.tar.gz yuzu-d3ff5b91e14356912589f9bac47fccbe79e07279.tar.xz yuzu-d3ff5b91e14356912589f9bac47fccbe79e07279.zip | |
Kernel/Mutex: Propagate thread priority changes to other threads inheriting the priority via mutexes
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 60 |
1 files changed, 22 insertions, 38 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 84ff65150..cef961289 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -13,38 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | /** | ||
| 17 | * Boost's a thread's priority to the best priority among the thread's held mutexes. | ||
| 18 | * This prevents priority inversion via priority inheritance. | ||
| 19 | */ | ||
| 20 | static void UpdateThreadPriority(Thread* thread) { | ||
| 21 | s32 best_priority = THREADPRIO_LOWEST; | ||
| 22 | for (auto& mutex : thread->held_mutexes) { | ||
| 23 | if (mutex->priority < best_priority) | ||
| 24 | best_priority = mutex->priority; | ||
| 25 | } | ||
| 26 | |||
| 27 | best_priority = std::min(best_priority, thread->nominal_priority); | ||
| 28 | thread->SetPriority(best_priority); | ||
| 29 | } | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Elevate the mutex priority to the best priority | ||
| 33 | * among the priorities of all its waiting threads. | ||
| 34 | */ | ||
| 35 | static void UpdateMutexPriority(Mutex* mutex) { | ||
| 36 | s32 best_priority = THREADPRIO_LOWEST; | ||
| 37 | for (auto& waiter : mutex->GetWaitingThreads()) { | ||
| 38 | if (waiter->current_priority < best_priority) | ||
| 39 | best_priority = waiter->current_priority; | ||
| 40 | } | ||
| 41 | |||
| 42 | if (best_priority != mutex->priority) { | ||
| 43 | mutex->priority = best_priority; | ||
| 44 | UpdateThreadPriority(mutex->holding_thread.get()); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void ReleaseThreadMutexes(Thread* thread) { | 16 | void ReleaseThreadMutexes(Thread* thread) { |
| 49 | for (auto& mtx : thread->held_mutexes) { | 17 | for (auto& mtx : thread->held_mutexes) { |
| 50 | mtx->lock_count = 0; | 18 | mtx->lock_count = 0; |
| @@ -83,9 +51,7 @@ void Mutex::Acquire(Thread* thread) { | |||
| 83 | priority = thread->current_priority; | 51 | priority = thread->current_priority; |
| 84 | thread->held_mutexes.insert(this); | 52 | thread->held_mutexes.insert(this); |
| 85 | holding_thread = thread; | 53 | holding_thread = thread; |
| 86 | 54 | thread->UpdatePriority(); | |
| 87 | UpdateThreadPriority(thread); | ||
| 88 | |||
| 89 | Core::System::GetInstance().PrepareReschedule(); | 55 | Core::System::GetInstance().PrepareReschedule(); |
| 90 | } | 56 | } |
| 91 | 57 | ||
| @@ -100,7 +66,7 @@ void Mutex::Release() { | |||
| 100 | // Yield to the next thread only if we've fully released the mutex | 66 | // Yield to the next thread only if we've fully released the mutex |
| 101 | if (lock_count == 0) { | 67 | if (lock_count == 0) { |
| 102 | holding_thread->held_mutexes.erase(this); | 68 | holding_thread->held_mutexes.erase(this); |
| 103 | UpdateThreadPriority(holding_thread.get()); | 69 | holding_thread->UpdatePriority(); |
| 104 | holding_thread = nullptr; | 70 | holding_thread = nullptr; |
| 105 | WakeupAllWaitingThreads(); | 71 | WakeupAllWaitingThreads(); |
| 106 | Core::System::GetInstance().PrepareReschedule(); | 72 | Core::System::GetInstance().PrepareReschedule(); |
| @@ -110,12 +76,30 @@ void Mutex::Release() { | |||
| 110 | 76 | ||
| 111 | void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { | 77 | void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { |
| 112 | WaitObject::AddWaitingThread(thread); | 78 | WaitObject::AddWaitingThread(thread); |
| 113 | UpdateMutexPriority(this); | 79 | thread->pending_mutexes.insert(this); |
| 80 | UpdatePriority(); | ||
| 114 | } | 81 | } |
| 115 | 82 | ||
| 116 | void Mutex::RemoveWaitingThread(Thread* thread) { | 83 | void Mutex::RemoveWaitingThread(Thread* thread) { |
| 117 | WaitObject::RemoveWaitingThread(thread); | 84 | WaitObject::RemoveWaitingThread(thread); |
| 118 | UpdateMutexPriority(this); | 85 | thread->pending_mutexes.erase(this); |
| 86 | UpdatePriority(); | ||
| 87 | } | ||
| 88 | |||
| 89 | void Mutex::UpdatePriority() { | ||
| 90 | if (!holding_thread) | ||
| 91 | return; | ||
| 92 | |||
| 93 | s32 best_priority = THREADPRIO_LOWEST; | ||
| 94 | for (auto& waiter : GetWaitingThreads()) { | ||
| 95 | if (waiter->current_priority < best_priority) | ||
| 96 | best_priority = waiter->current_priority; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (best_priority != priority) { | ||
| 100 | priority = best_priority; | ||
| 101 | holding_thread->UpdatePriority(); | ||
| 102 | } | ||
| 119 | } | 103 | } |
| 120 | 104 | ||
| 121 | } // namespace | 105 | } // namespace |