summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Subv2014-12-07 15:44:21 -0500
committerGravatar Subv2014-12-07 15:44:21 -0500
commit64128aa61a7ada0744f801df116dfbe229a50382 (patch)
treec22742e84c584242f38926307aad471a952ca723
parentMutex: Properly lock the mutex when a thread enters it (diff)
downloadyuzu-64128aa61a7ada0744f801df116dfbe229a50382.tar.gz
yuzu-64128aa61a7ada0744f801df116dfbe229a50382.tar.xz
yuzu-64128aa61a7ada0744f801df116dfbe229a50382.zip
Mutex: Release all held mutexes when a thread exits.
-rw-r--r--src/core/hle/kernel/mutex.cpp68
-rw-r--r--src/core/hle/kernel/mutex.h6
-rw-r--r--src/core/hle/kernel/thread.cpp4
3 files changed, 56 insertions, 22 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 17850c1b3..01de3c510 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -13,6 +13,9 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class Mutex;
17void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle());
18
16class Mutex : public Object { 19class Mutex : public Object {
17public: 20public:
18 std::string GetTypeName() const override { return "Mutex"; } 21 std::string GetTypeName() const override { return "Mutex"; }
@@ -34,6 +37,7 @@ public:
34 } else { 37 } else {
35 // Lock the mutex when the first thread accesses it 38 // Lock the mutex when the first thread accesses it
36 locked = true; 39 locked = true;
40 MutexAcquireLock(this);
37 } 41 }
38 42
39 return MakeResult<bool>(wait); 43 return MakeResult<bool>(wait);
@@ -45,21 +49,46 @@ public:
45typedef std::multimap<Handle, Handle> MutexMap; 49typedef std::multimap<Handle, Handle> MutexMap;
46static MutexMap g_mutex_held_locks; 50static MutexMap g_mutex_held_locks;
47 51
52/**
53 * Acquires the specified mutex for the specified thread
54 * @param mutex Mutex that is to be acquired
55 * @param thread Thread that will acquired
56 */
48void MutexAcquireLock(Mutex* mutex, Handle thread) { 57void MutexAcquireLock(Mutex* mutex, Handle thread) {
49 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); 58 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
50 mutex->lock_thread = thread; 59 mutex->lock_thread = thread;
51} 60}
52 61
53void MutexAcquireLock(Mutex* mutex) { 62bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
54 Handle thread = GetCurrentThreadHandle();
55 MutexAcquireLock(mutex, thread); 63 MutexAcquireLock(mutex, thread);
64 Kernel::ResumeThreadFromWait(thread);
65 return true;
66}
67
68/**
69 * Resumes a thread waiting for the specified mutex
70 * @param mutex The mutex that some thread is waiting on
71 */
72void ResumeWaitingThread(Mutex* mutex) {
73 // Find the next waiting thread for the mutex...
74 if (mutex->waiting_threads.empty()) {
75 // Reset mutex lock thread handle, nothing is waiting
76 mutex->locked = false;
77 mutex->lock_thread = -1;
78 }
79 else {
80 // Resume the next waiting thread and re-lock the mutex
81 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
82 ReleaseMutexForThread(mutex, *iter);
83 mutex->waiting_threads.erase(iter);
84 }
56} 85}
57 86
58void MutexEraseLock(Mutex* mutex) { 87void MutexEraseLock(Mutex* mutex) {
59 Handle handle = mutex->GetHandle(); 88 Handle handle = mutex->GetHandle();
60 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); 89 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
61 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { 90 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
62 if ((*iter).second == handle) { 91 if (iter->second == handle) {
63 g_mutex_held_locks.erase(iter); 92 g_mutex_held_locks.erase(iter);
64 break; 93 break;
65 } 94 }
@@ -67,6 +96,19 @@ void MutexEraseLock(Mutex* mutex) {
67 mutex->lock_thread = -1; 96 mutex->lock_thread = -1;
68} 97}
69 98
99void ReleaseThreadMutexes(Handle thread) {
100 auto locked = g_mutex_held_locks.equal_range(thread);
101
102 // Release every mutex that the thread holds, and resume execution on the waiting threads
103 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
104 Mutex* mutex = g_object_pool.GetFast<Mutex>(iter->second);
105 ResumeWaitingThread(mutex);
106 }
107
108 // Erase all the locks that this thread holds
109 g_mutex_held_locks.erase(thread);
110}
111
70bool LockMutex(Mutex* mutex) { 112bool LockMutex(Mutex* mutex) {
71 // Mutex alread locked? 113 // Mutex alread locked?
72 if (mutex->locked) { 114 if (mutex->locked) {
@@ -76,27 +118,9 @@ bool LockMutex(Mutex* mutex) {
76 return true; 118 return true;
77} 119}
78 120
79bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
80 MutexAcquireLock(mutex, thread);
81 Kernel::ResumeThreadFromWait(thread);
82 return true;
83}
84
85bool ReleaseMutex(Mutex* mutex) { 121bool ReleaseMutex(Mutex* mutex) {
86 MutexEraseLock(mutex); 122 MutexEraseLock(mutex);
87 123 ResumeWaitingThread(mutex);
88 // Find the next waiting thread for the mutex...
89 if (mutex->waiting_threads.empty()) {
90 // Reset mutex lock thread handle, nothing is waiting
91 mutex->locked = false;
92 mutex->lock_thread = -1;
93 } else {
94 // Resume the next waiting thread and re-lock the mutex
95 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
96 ReleaseMutexForThread(mutex, *iter);
97 mutex->waiting_threads.erase(iter);
98 }
99
100 return true; 124 return true;
101} 125}
102 126
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 155449f95..7f4909a6e 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -24,4 +24,10 @@ ResultCode ReleaseMutex(Handle handle);
24 */ 24 */
25Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); 25Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
26 26
27/**
28 * Releases all the mutexes held by the specified thread
29 * @param thread Thread that is holding the mutexes
30 */
31void ReleaseThreadMutexes(Handle thread);
32
27} // namespace 33} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 8d65dc84d..c01d76e4d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -14,6 +14,7 @@
14#include "core/hle/hle.h" 14#include "core/hle/hle.h"
15#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/kernel/mutex.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18#include "core/mem_map.h" 19#include "core/mem_map.h"
19 20
@@ -156,6 +157,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
156 Thread* thread = g_object_pool.Get<Thread>(handle); 157 Thread* thread = g_object_pool.Get<Thread>(handle);
157 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); 158 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
158 159
160 // Release all the mutexes that this thread holds
161 ReleaseThreadMutexes(handle);
162
159 ChangeReadyState(thread, false); 163 ChangeReadyState(thread, false);
160 thread->status = THREADSTATUS_DORMANT; 164 thread->status = THREADSTATUS_DORMANT;
161 for (Handle waiting_handle : thread->waiting_threads) { 165 for (Handle waiting_handle : thread->waiting_threads) {