summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
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
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')
-rw-r--r--src/core/hle/kernel/mutex.cpp60
-rw-r--r--src/core/hle/kernel/mutex.h6
-rw-r--r--src/core/hle/kernel/thread.cpp21
-rw-r--r--src/core/hle/kernel/thread.h9
4 files changed, 54 insertions, 42 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
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 31f920516..c57adf400 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -39,6 +39,12 @@ public:
39 std::string name; ///< Name of mutex (optional) 39 std::string name; ///< Name of mutex (optional)
40 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex 40 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
41 41
42 /**
43 * Elevate the mutex priority to the best priority
44 * among the priorities of all its waiting threads.
45 */
46 void UpdatePriority();
47
42 bool ShouldWait(Thread* thread) const override; 48 bool ShouldWait(Thread* thread) const override;
43 void Acquire(Thread* thread) override; 49 void Acquire(Thread* thread) override;
44 50
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d44010824..3a5a67450 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -105,15 +105,15 @@ void Thread::Stop() {
105 105
106 WakeupAllWaitingThreads(); 106 WakeupAllWaitingThreads();
107 107
108 // Release all the mutexes that this thread holds
109 ReleaseThreadMutexes(this);
110
111 // Clean up any dangling references in objects that this thread was waiting for 108 // Clean up any dangling references in objects that this thread was waiting for
112 for (auto& wait_object : wait_objects) { 109 for (auto& wait_object : wait_objects) {
113 wait_object->RemoveWaitingThread(this); 110 wait_object->RemoveWaitingThread(this);
114 } 111 }
115 wait_objects.clear(); 112 wait_objects.clear();
116 113
114 // Release all the mutexes that this thread holds
115 ReleaseThreadMutexes(this);
116
117 // Mark the TLS slot in the thread's page as free. 117 // Mark the TLS slot in the thread's page as free.
118 u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; 118 u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
119 u32 tls_slot = 119 u32 tls_slot =
@@ -515,8 +515,21 @@ void Thread::SetPriority(s32 priority) {
515 nominal_priority = current_priority = priority; 515 nominal_priority = current_priority = priority;
516} 516}
517 517
518void Thread::UpdatePriority() {
519 s32 best_priority = nominal_priority;
520 for (auto& mutex : held_mutexes) {
521 if (mutex->priority < best_priority)
522 best_priority = mutex->priority;
523 }
524 BoostPriority(best_priority);
525}
526
518void Thread::BoostPriority(s32 priority) { 527void Thread::BoostPriority(s32 priority) {
519 ready_queue.move(this, current_priority, priority); 528 // If thread was ready, adjust queues
529 if (status == THREADSTATUS_READY)
530 ready_queue.move(this, current_priority, priority);
531 else
532 ready_queue.prepare(priority);
520 current_priority = priority; 533 current_priority = priority;
521} 534}
522 535
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index f2bc1ec9c..e2f0cc831 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -90,6 +90,12 @@ public:
90 void SetPriority(s32 priority); 90 void SetPriority(s32 priority);
91 91
92 /** 92 /**
93 * Boost's a thread's priority to the best priority among the thread's held mutexes.
94 * This prevents priority inversion via priority inheritance.
95 */
96 void UpdatePriority();
97
98 /**
93 * Temporarily boosts the thread's priority until the next time it is scheduled 99 * Temporarily boosts the thread's priority until the next time it is scheduled
94 * @param priority The new priority 100 * @param priority The new priority
95 */ 101 */
@@ -178,6 +184,9 @@ public:
178 /// Mutexes currently held by this thread, which will be released when it exits. 184 /// Mutexes currently held by this thread, which will be released when it exits.
179 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; 185 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
180 186
187 /// Mutexes that this thread is currently waiting for.
188 boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes;
189
181 SharedPtr<Process> owner_process; ///< Process that owns this thread 190 SharedPtr<Process> owner_process; ///< Process that owns this thread
182 191
183 /// Objects that the thread is waiting on. 192 /// Objects that the thread is waiting on.