summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
authorGravatar Subv2017-01-02 19:38:08 -0500
committerGravatar Subv2017-01-04 15:58:48 -0500
commitd3ff5b91e14356912589f9bac47fccbe79e07279 (patch)
treee35c698d40539e360981a61b38f8fbb60aee7418 /src/core/hle/kernel/mutex.cpp
parentKernel/Mutex: Update a mutex priority when a thread stops waiting on it. (diff)
downloadyuzu-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.cpp60
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
14namespace Kernel { 14namespace 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 */
20static 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 */
35static 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
48void ReleaseThreadMutexes(Thread* thread) { 16void 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
111void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { 77void 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
116void Mutex::RemoveWaitingThread(Thread* thread) { 83void 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
89void 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