summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2017-01-02 13:53:10 -0500
committerGravatar Subv2017-01-04 15:58:47 -0500
commitb6a0355568ee327bef8957b9a2498897b96e1278 (patch)
treec2b4ac0c55ecfc2c60495e85e88e64c0f2bb6d8f /src
parentKernel/Mutex: Implemented priority inheritance. (diff)
downloadyuzu-b6a0355568ee327bef8957b9a2498897b96e1278.tar.gz
yuzu-b6a0355568ee327bef8957b9a2498897b96e1278.tar.xz
yuzu-b6a0355568ee327bef8957b9a2498897b96e1278.zip
Kernel/Mutex: Update a mutex priority when a thread stops waiting on it.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/kernel.cpp23
-rw-r--r--src/core/hle/kernel/kernel.h2
-rw-r--r--src/core/hle/kernel/mutex.cpp35
-rw-r--r--src/core/hle/kernel/mutex.h1
-rw-r--r--src/core/hle/svc.cpp5
5 files changed, 42 insertions, 24 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index ef9dbafa5..6f61d526a 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <boost/range/algorithm_ext/erase.hpp>
7#include "common/assert.h" 6#include "common/assert.h"
8#include "common/logging/log.h" 7#include "common/logging/log.h"
9#include "core/hle/config_mem.h" 8#include "core/hle/config_mem.h"
@@ -34,10 +33,17 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
34 33
35SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { 34SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
36 // Remove the threads that are ready or already running from our waitlist 35 // Remove the threads that are ready or already running from our waitlist
37 boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) { 36 auto to_remove = waiting_threads.end();
38 return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY || 37 do {
39 thread->status == THREADSTATUS_DEAD; 38 to_remove = std::find_if(waiting_threads.begin(), waiting_threads.end(),
40 }); 39 [](const SharedPtr<Thread>& thread) {
40 return thread->status == THREADSTATUS_RUNNING ||
41 thread->status == THREADSTATUS_READY ||
42 thread->status == THREADSTATUS_DEAD;
43 });
44 // Call RemoveWaitingThread so that child classes can override the behavior.
45 RemoveWaitingThread(to_remove->get());
46 } while (to_remove != waiting_threads.end());
41 47
42 Thread* candidate = nullptr; 48 Thread* candidate = nullptr;
43 s32 candidate_priority = THREADPRIO_LOWEST + 1; 49 s32 candidate_priority = THREADPRIO_LOWEST + 1;
@@ -49,9 +55,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
49 if (ShouldWait(thread.get())) 55 if (ShouldWait(thread.get()))
50 continue; 56 continue;
51 57
52 bool ready_to_run = 58 bool ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
53 std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), 59 [&thread](const SharedPtr<WaitObject>& object) {
54 [&thread](const SharedPtr<WaitObject>& object) { return object->ShouldWait(thread.get()); }); 60 return object->ShouldWait(thread.get());
61 });
55 if (ready_to_run) { 62 if (ready_to_run) {
56 candidate = thread.get(); 63 candidate = thread.get();
57 candidate_priority = thread->current_priority; 64 candidate_priority = thread->current_priority;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2680f89c9..05097824b 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -151,7 +151,7 @@ public:
151 * Removes a thread from waiting on this object (e.g. if it was resumed already) 151 * Removes a thread from waiting on this object (e.g. if it was resumed already)
152 * @param thread Pointer to thread to remove 152 * @param thread Pointer to thread to remove
153 */ 153 */
154 void RemoveWaitingThread(Thread* thread); 154 virtual void RemoveWaitingThread(Thread* thread);
155 155
156 /** 156 /**
157 * Wake up all threads waiting on this object that can be awoken, in priority order, 157 * Wake up all threads waiting on this object that can be awoken, in priority order,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index e83717e80..84ff65150 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -28,6 +28,23 @@ static void UpdateThreadPriority(Thread* thread) {
28 thread->SetPriority(best_priority); 28 thread->SetPriority(best_priority);
29} 29}
30 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
31void ReleaseThreadMutexes(Thread* thread) { 48void ReleaseThreadMutexes(Thread* thread) {
32 for (auto& mtx : thread->held_mutexes) { 49 for (auto& mtx : thread->held_mutexes) {
33 mtx->lock_count = 0; 50 mtx->lock_count = 0;
@@ -93,20 +110,12 @@ void Mutex::Release() {
93 110
94void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { 111void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
95 WaitObject::AddWaitingThread(thread); 112 WaitObject::AddWaitingThread(thread);
113 UpdateMutexPriority(this);
114}
96 115
97 // Elevate the mutex priority to the best priority 116void Mutex::RemoveWaitingThread(Thread* thread) {
98 // among the priorities of all its waiting threads. 117 WaitObject::RemoveWaitingThread(thread);
99 118 UpdateMutexPriority(this);
100 s32 best_priority = THREADPRIO_LOWEST;
101 for (auto& waiter : GetWaitingThreads()) {
102 if (waiter->current_priority < best_priority)
103 best_priority = waiter->current_priority;
104 }
105
106 if (best_priority != priority) {
107 priority = best_priority;
108 UpdateThreadPriority(holding_thread.get());
109 }
110} 119}
111 120
112} // namespace 121} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 3e6adeb17..31f920516 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -43,6 +43,7 @@ public:
43 void Acquire(Thread* thread) override; 43 void Acquire(Thread* thread) override;
44 44
45 void AddWaitingThread(SharedPtr<Thread> thread) override; 45 void AddWaitingThread(SharedPtr<Thread> thread) override;
46 void RemoveWaitingThread(Thread* thread) override;
46 47
47 void Release(); 48 void Release();
48 49
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 5d6359344..b6e34a9e9 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -373,8 +373,9 @@ static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 ha
373 return ERR_SYNC_TIMEOUT; 373 return ERR_SYNC_TIMEOUT;
374 } else { 374 } else {
375 // Find the first object that is acquirable in the provided list of objects 375 // Find the first object that is acquirable in the provided list of objects
376 auto itr = std::find_if(objects.begin(), objects.end(), 376 auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) {
377 [thread](const ObjectPtr& object) { return !object->ShouldWait(thread); }); 377 return !object->ShouldWait(thread);
378 });
378 379
379 if (itr != objects.end()) { 380 if (itr != objects.end()) {
380 // We found a ready object, acquire it and set the result value 381 // We found a ready object, acquire it and set the result value