diff options
| author | 2017-01-02 13:53:10 -0500 | |
|---|---|---|
| committer | 2017-01-04 15:58:47 -0500 | |
| commit | b6a0355568ee327bef8957b9a2498897b96e1278 (patch) | |
| tree | c2b4ac0c55ecfc2c60495e85e88e64c0f2bb6d8f /src | |
| parent | Kernel/Mutex: Implemented priority inheritance. (diff) | |
| download | yuzu-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.cpp | 23 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 35 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.h | 1 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 5 |
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 | ||
| 35 | SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | 34 | SharedPtr<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 | */ | ||
| 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 | |||
| 31 | void ReleaseThreadMutexes(Thread* thread) { | 48 | void 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 | ||
| 94 | void Mutex::AddWaitingThread(SharedPtr<Thread> thread) { | 111 | void 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 | 116 | void 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 |