diff options
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 112 |
1 files changed, 39 insertions, 73 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 853a5dd74..cd05a1397 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,7 +13,7 @@ namespace Kernel { -class Mutex : public Object { +class Mutex : public WaitObject { public: std::string GetTypeName() const override { return "Mutex"; } std::string GetName() const override { return name; } @@ -23,39 +23,26 @@ public: bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state - Handle lock_thread; ///< Handle to thread that currently has mutex - std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex std::string name; ///< Name of mutex (optional) + SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex - ResultVal<bool> WaitSynchronization() override; + bool ShouldWait() override; + void Acquire() override; }; //////////////////////////////////////////////////////////////////////////////////////////////////// -typedef std::multimap<Handle, Handle> MutexMap; +typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; static MutexMap g_mutex_held_locks; /** * Acquires the specified mutex for the specified thread * @param mutex Mutex that is to be acquired - * @param thread Thread that will acquired + * @param thread Thread that will acquire the mutex */ -void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { - g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); - mutex->lock_thread = thread; -} - -bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { - MutexAcquireLock(mutex, thread_handle); - - Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get(); - if (thread == nullptr) { - LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); - return false; - } - - thread->ResumeFromWait(); - return true; +void MutexAcquireLock(Mutex* mutex, Thread* thread) { + g_mutex_held_locks.insert(std::make_pair(thread, mutex)); + mutex->holding_thread = thread; } /** @@ -64,56 +51,41 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { */ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... - if (mutex->waiting_threads.empty()) { + auto next_thread = mutex->WakeupNextThread(); + if (next_thread != nullptr) { + MutexAcquireLock(mutex, next_thread); + } else { // 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); + mutex->holding_thread = nullptr; } } -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) { - g_mutex_held_locks.erase(iter); - break; - } - } - mutex->lock_thread = -1; -} - -void ReleaseThreadMutexes(Handle thread) { +void ReleaseThreadMutexes(Thread* 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_handle_table.Get<Mutex>(iter->second).get(); - ResumeWaitingThread(mutex); + for (auto iter = locked.first; iter != locked.second; ++iter) { + ResumeWaitingThread(iter->second.get()); } // Erase all the locks that this thread holds g_mutex_held_locks.erase(thread); } -bool LockMutex(Mutex* mutex) { - // Mutex alread locked? +bool ReleaseMutex(Mutex* mutex) { if (mutex->locked) { - return false; - } - MutexAcquireLock(mutex); - return true; -} + auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); -bool ReleaseMutex(Mutex* mutex) { - MutexEraseLock(mutex); - ResumeWaitingThread(mutex); + for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { + if (iter->second == mutex) { + g_mutex_held_locks.erase(iter); + break; + } + } + + ResumeWaitingThread(mutex); + } return true; } @@ -148,15 +120,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) mutex->locked = mutex->initial_locked = initial_locked; mutex->name = name; + mutex->holding_thread = nullptr; // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) { - MutexAcquireLock(mutex); + if (mutex->locked) + MutexAcquireLock(mutex, GetCurrentThread()); - // Otherwise, reset lock thread handle - } else { - mutex->lock_thread = -1; - } return mutex; } @@ -172,17 +141,14 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal<bool> Mutex::WaitSynchronization() { - bool wait = locked; - if (locked) { - waiting_threads.push_back(GetCurrentThread()->GetHandle()); - Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); - } else { - // Lock the mutex when the first thread accesses it - locked = true; - MutexAcquireLock(this); - } +bool Mutex::ShouldWait() { + return locked && holding_thread != GetCurrentThread(); +} - return MakeResult<bool>(wait); +void Mutex::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + locked = true; + MutexAcquireLock(this, GetCurrentThread()); } + } // namespace |