summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2014-12-10 22:52:55 -0500
committerGravatar bunnei2014-12-10 22:52:55 -0500
commit3a75c8069e9c044f6a8f2fd80c7d35ea245a9f6e (patch)
tree59d94738da7ef6f31ddbc8d4cbfbd58f578e25d8
parentMerge pull request #239 from linkmauve/country-codes (diff)
parentMutex: Remove some forward declarations (diff)
downloadyuzu-3a75c8069e9c044f6a8f2fd80c7d35ea245a9f6e.tar.gz
yuzu-3a75c8069e9c044f6a8f2fd80c7d35ea245a9f6e.tar.xz
yuzu-3a75c8069e9c044f6a8f2fd80c7d35ea245a9f6e.zip
Merge pull request #256 from Subv/mutex
Kernel/Mutex: Properly lock the mutex when a thread enters it
-rw-r--r--src/core/hle/kernel/mutex.cpp94
-rw-r--r--src/core/hle/kernel/mutex.h6
-rw-r--r--src/core/hle/kernel/thread.cpp4
3 files changed, 67 insertions, 37 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index d07e9761b..5a173e129 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -27,21 +27,7 @@ public:
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex 27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 28 std::string name; ///< Name of mutex (optional)
29 29
30 ResultVal<bool> SyncRequest() override { 30 ResultVal<bool> WaitSynchronization() override;
31 // TODO(bunnei): ImplementMe
32 locked = true;
33 return MakeResult<bool>(false);
34 }
35
36 ResultVal<bool> WaitSynchronization() override {
37 // TODO(bunnei): ImplementMe
38 bool wait = locked;
39 if (locked) {
40 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
41 }
42
43 return MakeResult<bool>(wait);
44 }
45}; 31};
46 32
47//////////////////////////////////////////////////////////////////////////////////////////////////// 33////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,21 +35,46 @@ public:
49typedef std::multimap<Handle, Handle> MutexMap; 35typedef std::multimap<Handle, Handle> MutexMap;
50static MutexMap g_mutex_held_locks; 36static MutexMap g_mutex_held_locks;
51 37
52void MutexAcquireLock(Mutex* mutex, Handle thread) { 38/**
39 * Acquires the specified mutex for the specified thread
40 * @param mutex Mutex that is to be acquired
41 * @param thread Thread that will acquired
42 */
43void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) {
53 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); 44 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
54 mutex->lock_thread = thread; 45 mutex->lock_thread = thread;
55} 46}
56 47
57void MutexAcquireLock(Mutex* mutex) { 48bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
58 Handle thread = GetCurrentThreadHandle();
59 MutexAcquireLock(mutex, thread); 49 MutexAcquireLock(mutex, thread);
50 Kernel::ResumeThreadFromWait(thread);
51 return true;
52}
53
54/**
55 * Resumes a thread waiting for the specified mutex
56 * @param mutex The mutex that some thread is waiting on
57 */
58void ResumeWaitingThread(Mutex* mutex) {
59 // Find the next waiting thread for the mutex...
60 if (mutex->waiting_threads.empty()) {
61 // Reset mutex lock thread handle, nothing is waiting
62 mutex->locked = false;
63 mutex->lock_thread = -1;
64 }
65 else {
66 // Resume the next waiting thread and re-lock the mutex
67 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
68 ReleaseMutexForThread(mutex, *iter);
69 mutex->waiting_threads.erase(iter);
70 }
60} 71}
61 72
62void MutexEraseLock(Mutex* mutex) { 73void MutexEraseLock(Mutex* mutex) {
63 Handle handle = mutex->GetHandle(); 74 Handle handle = mutex->GetHandle();
64 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); 75 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
65 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { 76 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
66 if ((*iter).second == handle) { 77 if (iter->second == handle) {
67 g_mutex_held_locks.erase(iter); 78 g_mutex_held_locks.erase(iter);
68 break; 79 break;
69 } 80 }
@@ -71,6 +82,19 @@ void MutexEraseLock(Mutex* mutex) {
71 mutex->lock_thread = -1; 82 mutex->lock_thread = -1;
72} 83}
73 84
85void ReleaseThreadMutexes(Handle thread) {
86 auto locked = g_mutex_held_locks.equal_range(thread);
87
88 // Release every mutex that the thread holds, and resume execution on the waiting threads
89 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
90 Mutex* mutex = g_object_pool.GetFast<Mutex>(iter->second);
91 ResumeWaitingThread(mutex);
92 }
93
94 // Erase all the locks that this thread holds
95 g_mutex_held_locks.erase(thread);
96}
97
74bool LockMutex(Mutex* mutex) { 98bool LockMutex(Mutex* mutex) {
75 // Mutex alread locked? 99 // Mutex alread locked?
76 if (mutex->locked) { 100 if (mutex->locked) {
@@ -80,26 +104,9 @@ bool LockMutex(Mutex* mutex) {
80 return true; 104 return true;
81} 105}
82 106
83bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
84 MutexAcquireLock(mutex, thread);
85 Kernel::ResumeThreadFromWait(thread);
86 return true;
87}
88
89bool ReleaseMutex(Mutex* mutex) { 107bool ReleaseMutex(Mutex* mutex) {
90 MutexEraseLock(mutex); 108 MutexEraseLock(mutex);
91 109 ResumeWaitingThread(mutex);
92 // Find the next waiting thread for the mutex...
93 while (!mutex->waiting_threads.empty()) {
94 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
95 ReleaseMutexForThread(mutex, *iter);
96 mutex->waiting_threads.erase(iter);
97 }
98
99 // Reset mutex lock thread handle, nothing is waiting
100 mutex->locked = false;
101 mutex->lock_thread = -1;
102
103 return true; 110 return true;
104} 111}
105 112
@@ -157,4 +164,17 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
157 return handle; 164 return handle;
158} 165}
159 166
167ResultVal<bool> Mutex::WaitSynchronization() {
168 bool wait = locked;
169 if (locked) {
170 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
171 }
172 else {
173 // Lock the mutex when the first thread accesses it
174 locked = true;
175 MutexAcquireLock(this);
176 }
177
178 return MakeResult<bool>(wait);
179}
160} // namespace 180} // namespace
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 1e879b45a..492b917e1 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
@@ -164,6 +165,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
164 Thread* thread = g_object_pool.Get<Thread>(handle); 165 Thread* thread = g_object_pool.Get<Thread>(handle);
165 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); 166 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
166 167
168 // Release all the mutexes that this thread holds
169 ReleaseThreadMutexes(handle);
170
167 ChangeReadyState(thread, false); 171 ChangeReadyState(thread, false);
168 thread->status = THREADSTATUS_DORMANT; 172 thread->status = THREADSTATUS_DORMANT;
169 for (Handle waiting_handle : thread->waiting_threads) { 173 for (Handle waiting_handle : thread->waiting_threads) {