diff options
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 192 |
1 files changed, 45 insertions, 147 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 853a5dd7..9f7166ca 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,176 +15,72 @@ namespace Kernel { -class Mutex : public Object { -public: - std::string GetTypeName() const override { return "Mutex"; } - std::string GetName() const override { return name; } - - 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 - 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) - - ResultVal<bool> WaitSynchronization() override; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -typedef std::multimap<Handle, Handle> 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 - */ -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; -} - /** * Resumes a thread waiting for the specified mutex * @param mutex The mutex that some thread is waiting on */ -void ResumeWaitingThread(Mutex* mutex) { +static void ResumeWaitingThread(Mutex* mutex) { + // Reset mutex lock thread handle, nothing is waiting + mutex->locked = false; + mutex->holding_thread = nullptr; + // 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); + auto next_thread = mutex->WakeupNextThread(); + if (next_thread != nullptr) { + mutex->Acquire(next_thread); } } -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; - } +void ReleaseThreadMutexes(Thread* thread) { + for (auto& mtx : thread->held_mutexes) { + ResumeWaitingThread(mtx.get()); } - mutex->lock_thread = -1; + thread->held_mutexes.clear(); } -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).get(); - ResumeWaitingThread(mutex); - } +Mutex::Mutex() {} +Mutex::~Mutex() {} - // Erase all the locks that this thread holds - g_mutex_held_locks.erase(thread); -} +SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { + SharedPtr<Mutex> mutex(new Mutex); -bool LockMutex(Mutex* mutex) { - // Mutex alread locked? - if (mutex->locked) { - return false; - } - MutexAcquireLock(mutex); - return true; -} + mutex->initial_locked = initial_locked; + mutex->locked = false; + mutex->name = std::move(name); + mutex->holding_thread = nullptr; -bool ReleaseMutex(Mutex* mutex) { - MutexEraseLock(mutex); - ResumeWaitingThread(mutex); - return true; -} + // Acquire mutex with current thread if initialized as locked... + if (initial_locked) + mutex->Acquire(); -/** - * Releases a mutex - * @param handle Handle to mutex to release - */ -ResultCode ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get(); - if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); - - if (!ReleaseMutex(mutex)) { - // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure - // what error condition this is supposed to be signaling. - return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, - ErrorSummary::NothingHappened, ErrorLevel::Temporary); - } - return RESULT_SUCCESS; + return mutex; } -/** - * Creates a mutex - * @param handle Reference to handle for the newly created mutex - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Pointer to new Mutex object - */ -Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { - Mutex* mutex = new Mutex; - // TODO(yuriks): Fix error reporting - handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); +bool Mutex::ShouldWait() { + return locked && holding_thread != GetCurrentThread(); +} - mutex->locked = mutex->initial_locked = initial_locked; - mutex->name = name; +void Mutex::Acquire() { + Acquire(GetCurrentThread()); +} - // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) { - MutexAcquireLock(mutex); +void Mutex::Acquire(SharedPtr<Thread> thread) { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + if (locked) + return; - // Otherwise, reset lock thread handle - } else { - mutex->lock_thread = -1; - } - return mutex; -} + locked = true; -/** - * Creates a mutex - * @param initial_locked Specifies if the mutex should be locked initially - * @param name Optional name of mutex - * @return Handle to newly created object - */ -Handle CreateMutex(bool initial_locked, const std::string& name) { - Handle handle; - Mutex* mutex = CreateMutex(handle, initial_locked, name); - return handle; + thread->held_mutexes.insert(this); + holding_thread = std::move(thread); } -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); - } +void Mutex::Release() { + if (!locked) + return; - return MakeResult<bool>(wait); + holding_thread->held_mutexes.erase(this); + ResumeWaitingThread(this); } + } // namespace |