summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
authorGravatar Sebastian Valle2017-01-05 12:55:01 -0500
committerGravatar GitHub2017-01-05 12:55:01 -0500
commitf20d872643654c574f73a263f032613046900f07 (patch)
tree021284c18034d053c81928fa19d2efb6658451fb /src/core/hle/kernel/mutex.cpp
parentMerge pull request #2407 from jroweboy/nightly-deploy (diff)
parentKernel: Add some asserts to enforce the invariants in the scheduler. (diff)
downloadyuzu-f20d872643654c574f73a263f032613046900f07.tar.gz
yuzu-f20d872643654c574f73a263f032613046900f07.tar.xz
yuzu-f20d872643654c574f73a263f032613046900f07.zip
Merge pull request #2393 from Subv/synch
Kernel: Mutex priority inheritance and synchronization improvements.
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp84
1 files changed, 49 insertions, 35 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 736944bae..cef961289 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -6,26 +6,18 @@
6#include <vector> 6#include <vector>
7#include <boost/range/algorithm_ext/erase.hpp> 7#include <boost/range/algorithm_ext/erase.hpp>
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
12 13
13namespace Kernel { 14namespace Kernel {
14 15
15/**
16 * Resumes a thread waiting for the specified mutex
17 * @param mutex The mutex that some thread is waiting on
18 */
19static void ResumeWaitingThread(Mutex* mutex) {
20 // Reset mutex lock thread handle, nothing is waiting
21 mutex->lock_count = 0;
22 mutex->holding_thread = nullptr;
23 mutex->WakeupAllWaitingThreads();
24}
25
26void ReleaseThreadMutexes(Thread* thread) { 16void ReleaseThreadMutexes(Thread* thread) {
27 for (auto& mtx : thread->held_mutexes) { 17 for (auto& mtx : thread->held_mutexes) {
28 ResumeWaitingThread(mtx.get()); 18 mtx->lock_count = 0;
19 mtx->holding_thread = nullptr;
20 mtx->WakeupAllWaitingThreads();
29 } 21 }
30 thread->held_mutexes.clear(); 22 thread->held_mutexes.clear();
31} 23}
@@ -40,52 +32,74 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
40 mutex->name = std::move(name); 32 mutex->name = std::move(name);
41 mutex->holding_thread = nullptr; 33 mutex->holding_thread = nullptr;
42 34
43 // Acquire mutex with current thread if initialized as locked... 35 // Acquire mutex with current thread if initialized as locked
44 if (initial_locked) 36 if (initial_locked)
45 mutex->Acquire(); 37 mutex->Acquire(GetCurrentThread());
46 38
47 return mutex; 39 return mutex;
48} 40}
49 41
50bool Mutex::ShouldWait() { 42bool Mutex::ShouldWait(Thread* thread) const {
51 auto thread = GetCurrentThread(); 43 return lock_count > 0 && thread != holding_thread;
52 bool wait = lock_count > 0 && holding_thread != thread;
53
54 // If the holding thread of the mutex is lower priority than this thread, that thread should
55 // temporarily inherit this thread's priority
56 if (wait && thread->current_priority < holding_thread->current_priority)
57 holding_thread->BoostPriority(thread->current_priority);
58
59 return wait;
60}
61
62void Mutex::Acquire() {
63 Acquire(GetCurrentThread());
64} 44}
65 45
66void Mutex::Acquire(SharedPtr<Thread> thread) { 46void Mutex::Acquire(Thread* thread) {
67 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 47 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
68 48
69 // Actually "acquire" the mutex only if we don't already have it... 49 // Actually "acquire" the mutex only if we don't already have it
70 if (lock_count == 0) { 50 if (lock_count == 0) {
51 priority = thread->current_priority;
71 thread->held_mutexes.insert(this); 52 thread->held_mutexes.insert(this);
72 holding_thread = std::move(thread); 53 holding_thread = thread;
54 thread->UpdatePriority();
55 Core::System::GetInstance().PrepareReschedule();
73 } 56 }
74 57
75 lock_count++; 58 lock_count++;
76} 59}
77 60
78void Mutex::Release() { 61void Mutex::Release() {
79 // Only release if the mutex is held... 62 // Only release if the mutex is held
80 if (lock_count > 0) { 63 if (lock_count > 0) {
81 lock_count--; 64 lock_count--;
82 65
83 // 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
84 if (lock_count == 0) { 67 if (lock_count == 0) {
85 holding_thread->held_mutexes.erase(this); 68 holding_thread->held_mutexes.erase(this);
86 ResumeWaitingThread(this); 69 holding_thread->UpdatePriority();
70 holding_thread = nullptr;
71 WakeupAllWaitingThreads();
72 Core::System::GetInstance().PrepareReschedule();
87 } 73 }
88 } 74 }
89} 75}
90 76
77void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
78 WaitObject::AddWaitingThread(thread);
79 thread->pending_mutexes.insert(this);
80 UpdatePriority();
81}
82
83void Mutex::RemoveWaitingThread(Thread* thread) {
84 WaitObject::RemoveWaitingThread(thread);
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 }
103}
104
91} // namespace 105} // namespace