diff options
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 64 |
1 files changed, 28 insertions, 36 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index acf484659..a811db392 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -5,6 +5,8 @@ #include <map> #include <vector> +#include <boost/range/algorithm_ext/erase.hpp> + #include "common/common.h" #include "core/hle/kernel/kernel.h" @@ -13,16 +15,13 @@ namespace Kernel { -typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; -static MutexMap g_mutex_held_locks; - /** * Resumes a thread waiting for the specified mutex * @param mutex The mutex that some thread is waiting on */ static void ResumeWaitingThread(Mutex* mutex) { // Reset mutex lock thread handle, nothing is waiting - mutex->locked = false; + mutex->lock_count = 0; mutex->holding_thread = nullptr; // Find the next waiting thread for the mutex... @@ -33,24 +32,19 @@ static void ResumeWaitingThread(Mutex* mutex) { } void ReleaseThreadMutexes(Thread* thread) { - auto locked_range = g_mutex_held_locks.equal_range(thread); - - // Release every mutex that the thread holds, and resume execution on the waiting threads - for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { - ResumeWaitingThread(iter->second.get()); + for (auto& mtx : thread->held_mutexes) { + ResumeWaitingThread(mtx.get()); } - - // Erase all the locks that this thread holds - g_mutex_held_locks.erase(thread); + thread->held_mutexes.clear(); } -ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { +Mutex::Mutex() {} +Mutex::~Mutex() {} + +SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { SharedPtr<Mutex> mutex(new Mutex); - // TOOD(yuriks): Don't create Handle (see Thread::Create()) - CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); - mutex->initial_locked = initial_locked; - mutex->locked = false; + mutex->lock_count = 0; mutex->name = std::move(name); mutex->holding_thread = nullptr; @@ -58,42 +52,40 @@ ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) if (initial_locked) mutex->Acquire(); - return MakeResult<SharedPtr<Mutex>>(mutex); + return mutex; } bool Mutex::ShouldWait() { - return locked && holding_thread != GetCurrentThread(); + return lock_count > 0 && holding_thread != GetCurrentThread();; } void Mutex::Acquire() { Acquire(GetCurrentThread()); } -void Mutex::Acquire(Thread* thread) { +void Mutex::Acquire(SharedPtr<Thread> thread) { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); - if (locked) - return; - locked = true; + // Actually "acquire" the mutex only if we don't already have it... + if (lock_count == 0) { + thread->held_mutexes.insert(this); + holding_thread = std::move(thread); + } - g_mutex_held_locks.insert(std::make_pair(thread, this)); - holding_thread = thread; + lock_count++; } void Mutex::Release() { - if (!locked) - return; - - auto locked_range = g_mutex_held_locks.equal_range(holding_thread); - - for (MutexMap::iterator iter = locked_range.first; iter != locked_range.second; ++iter) { - if (iter->second == this) { - g_mutex_held_locks.erase(iter); - break; + // Only release if the mutex is held... + if (lock_count > 0) { + lock_count--; + + // Yield to the next thread only if we've fully released the mutex... + if (lock_count == 0) { + holding_thread->held_mutexes.erase(this); + ResumeWaitingThread(this); } } - - ResumeWaitingThread(this); } } // namespace |