aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp192
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