Explorar o código

Merge pull request #256 from Subv/mutex

Kernel/Mutex: Properly lock the mutex when a thread enters it
bunnei %!s(int64=11) %!d(string=hai) anos
pai
achega
3a75c8069e
Modificáronse 3 ficheiros con 67 adicións e 37 borrados
  1. 57 37
      src/core/hle/kernel/mutex.cpp
  2. 6 0
      src/core/hle/kernel/mutex.h
  3. 4 0
      src/core/hle/kernel/thread.cpp

+ 57 - 37
src/core/hle/kernel/mutex.cpp

@@ -27,21 +27,7 @@ public:
     std::vector<Handle> waiting_threads;        ///< Threads that are waiting for the mutex
     std::string name;                           ///< Name of mutex (optional)
 
-    ResultVal<bool> SyncRequest() override {
-        // TODO(bunnei): ImplementMe
-        locked = true;
-        return MakeResult<bool>(false);
-    }
-
-    ResultVal<bool> WaitSynchronization() override {
-        // TODO(bunnei): ImplementMe
-        bool wait = locked;
-        if (locked) {
-            Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
-        }
-
-        return MakeResult<bool>(wait);
-    }
+    ResultVal<bool> WaitSynchronization() override;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,21 +35,46 @@ public:
 typedef std::multimap<Handle, Handle> MutexMap;
 static MutexMap g_mutex_held_locks;
 
-void MutexAcquireLock(Mutex* mutex, Handle thread) {
+/**
+ * Acquires the specified mutex for the specified thread
+ * @param mutex Mutex that is to be acquired
+ * @param thread Thread that will acquired
+ */
+void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) {
     g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
     mutex->lock_thread = thread;
 }
 
-void MutexAcquireLock(Mutex* mutex) {
-    Handle thread = GetCurrentThreadHandle();
+bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
     MutexAcquireLock(mutex, thread);
+    Kernel::ResumeThreadFromWait(thread);
+    return true;
+}
+
+/**
+ * Resumes a thread waiting for the specified mutex
+ * @param mutex The mutex that some thread is waiting on
+ */
+void ResumeWaitingThread(Mutex* mutex) {
+    // Find the next waiting thread for the mutex...
+    if (mutex->waiting_threads.empty()) {
+        // Reset mutex lock thread handle, nothing is waiting
+        mutex->locked = false;
+        mutex->lock_thread = -1;
+    }
+    else {
+        // Resume the next waiting thread and re-lock the mutex
+        std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
+        ReleaseMutexForThread(mutex, *iter);
+        mutex->waiting_threads.erase(iter);
+    }
 }
 
 void MutexEraseLock(Mutex* mutex) {
     Handle handle = mutex->GetHandle();
     auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
     for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
-        if ((*iter).second == handle) {
+        if (iter->second == handle) {
             g_mutex_held_locks.erase(iter);
             break;
         }
@@ -71,6 +82,19 @@ void MutexEraseLock(Mutex* mutex) {
     mutex->lock_thread = -1;
 }
 
+void ReleaseThreadMutexes(Handle thread) {
+    auto locked = g_mutex_held_locks.equal_range(thread);
+    
+    // Release every mutex that the thread holds, and resume execution on the waiting threads
+    for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
+        Mutex* mutex = g_object_pool.GetFast<Mutex>(iter->second);
+        ResumeWaitingThread(mutex);
+    }
+
+    // Erase all the locks that this thread holds
+    g_mutex_held_locks.erase(thread);
+}
+
 bool LockMutex(Mutex* mutex) {
     // Mutex alread locked?
     if (mutex->locked) {
@@ -80,26 +104,9 @@ bool LockMutex(Mutex* mutex) {
     return true;
 }
 
-bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
-    MutexAcquireLock(mutex, thread);
-    Kernel::ResumeThreadFromWait(thread);
-    return true;
-}
-
 bool ReleaseMutex(Mutex* mutex) {
     MutexEraseLock(mutex);
-
-    // Find the next waiting thread for the mutex...
-    while (!mutex->waiting_threads.empty()) {
-        std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
-        ReleaseMutexForThread(mutex, *iter);
-        mutex->waiting_threads.erase(iter);
-    }
-
-    // Reset mutex lock thread handle, nothing is waiting
-    mutex->locked = false;
-    mutex->lock_thread = -1;
-
+    ResumeWaitingThread(mutex);
     return true;
 }
 
@@ -157,4 +164,17 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
     return handle;
 }
 
+ResultVal<bool> Mutex::WaitSynchronization() {
+    bool wait = locked;
+    if (locked) {
+        Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
+    }
+    else {
+        // Lock the mutex when the first thread accesses it
+        locked = true;
+        MutexAcquireLock(this);
+    }
+
+    return MakeResult<bool>(wait);
+}
 } // namespace

+ 6 - 0
src/core/hle/kernel/mutex.h

@@ -24,4 +24,10 @@ ResultCode ReleaseMutex(Handle handle);
  */
 Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
 
+/**
+ * Releases all the mutexes held by the specified thread
+ * @param thread Thread that is holding the mutexes
+ */
+void ReleaseThreadMutexes(Handle thread);
+
 } // namespace

+ 4 - 0
src/core/hle/kernel/thread.cpp

@@ -14,6 +14,7 @@
 #include "core/hle/hle.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/mutex.h"
 #include "core/hle/result.h"
 #include "core/mem_map.h"
 
@@ -164,6 +165,9 @@ ResultCode StopThread(Handle handle, const char* reason) {
     Thread* thread = g_object_pool.Get<Thread>(handle);
     if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
 
+    // Release all the mutexes that this thread holds
+    ReleaseThreadMutexes(handle);
+
     ChangeReadyState(thread, false);
     thread->status = THREADSTATUS_DORMANT;
     for (Handle waiting_handle : thread->waiting_threads) {