diff options
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 108 |
1 files changed, 64 insertions, 44 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index b303ba1284..558068c792 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -1,5 +1,5 @@ // Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 +// Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include <map> @@ -18,8 +18,8 @@ public: std::string GetTypeName() const override { return "Mutex"; } std::string GetName() const override { return name; } - static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } - Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; } + static const HandleType HANDLE_TYPE = HandleType::Mutex; + HandleType GetHandleType() const override { return HANDLE_TYPE; } bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state @@ -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_handle_table.Get<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,28 +104,10 @@ 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); - bool woke_threads = false; - - // Find the next waiting thread for the mutex... - while (!woke_threads && !mutex->waiting_threads.empty()) { - std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); - woke_threads |= ReleaseMutexForThread(mutex, *iter); - mutex->waiting_threads.erase(iter); - } - // Reset mutex lock thread handle, nothing is waiting - if (!woke_threads) { - mutex->locked = false; - mutex->lock_thread = -1; - } - return woke_threads; + ResumeWaitingThread(mutex); + return true; } /** @@ -109,7 +115,7 @@ bool ReleaseMutex(Mutex* mutex) { * @param handle Handle to mutex to release */ ResultCode ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle); + Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle); if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!ReleaseMutex(mutex)) { @@ -130,7 +136,8 @@ ResultCode ReleaseMutex(Handle handle) { */ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { Mutex* mutex = new Mutex; - handle = Kernel::g_object_pool.Create(mutex); + // TODO(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); mutex->locked = mutex->initial_locked = initial_locked; mutex->name = name; @@ -158,4 +165,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 |