From 882b6fed75b7bf34809493482496e98c498a14e0 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Thu, 22 Jan 2015 23:12:19 -0200 Subject: Kernel: Convert Mutex to not use Handles --- src/core/hle/kernel/mutex.cpp | 131 ++++++++++++++--------------------------- src/core/hle/kernel/mutex.h | 52 ++++++++++++---- src/core/hle/service/apt_s.cpp | 1 + src/core/hle/service/apt_u.cpp | 16 ++--- src/core/hle/svc.cpp | 24 ++++++-- 5 files changed, 110 insertions(+), 114 deletions(-) diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index c94c2acc9..acf484659 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,59 +13,30 @@ namespace Kernel { -class Mutex : public WaitObject { -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 - std::string name; ///< Name of mutex (optional) - SharedPtr holding_thread; ///< Thread that has acquired the mutex - - bool ShouldWait() override; - void Acquire() override; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - typedef std::multimap, SharedPtr> 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 acquire the mutex - */ -static void MutexAcquireLock(Mutex* mutex, Thread* thread) { - g_mutex_held_locks.insert(std::make_pair(thread, mutex)); - mutex->holding_thread = thread; -} - /** * 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->holding_thread = nullptr; + // Find the next waiting thread for the mutex... 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->holding_thread = nullptr; + mutex->Acquire(next_thread); } } void ReleaseThreadMutexes(Thread* thread) { - auto locked = g_mutex_held_locks.equal_range(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.first; iter != locked.second; ++iter) { + for (auto iter = locked_range.first; iter != locked_range.second; ++iter) { ResumeWaitingThread(iter->second.get()); } @@ -73,62 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { g_mutex_held_locks.erase(thread); } -static bool ReleaseMutex(Mutex* mutex) { - if (mutex->locked) { - auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); - - 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; -} - -ResultCode ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_handle_table.Get(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; -} - -/** - * 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 - */ -static 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); +ResultVal> Mutex::Create(bool initial_locked, std::string name) { + SharedPtr mutex(new Mutex); + // TOOD(yuriks): Don't create Handle (see Thread::Create()) + CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); - mutex->locked = mutex->initial_locked = initial_locked; - mutex->name = name; + mutex->initial_locked = initial_locked; + mutex->locked = false; + mutex->name = std::move(name); mutex->holding_thread = nullptr; // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) - MutexAcquireLock(mutex, GetCurrentThread()); + if (initial_locked) + mutex->Acquire(); - return mutex; -} - -Handle CreateMutex(bool initial_locked, const std::string& name) { - Handle handle; - Mutex* mutex = CreateMutex(handle, initial_locked, name); - return handle; + return MakeResult>(mutex); } bool Mutex::ShouldWait() { @@ -136,9 +66,34 @@ bool Mutex::ShouldWait() { } void Mutex::Acquire() { + Acquire(GetCurrentThread()); +} + +void Mutex::Acquire(Thread* thread) { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + if (locked) + return; + locked = true; - MutexAcquireLock(this, GetCurrentThread()); + + g_mutex_held_locks.insert(std::make_pair(thread, this)); + holding_thread = thread; +} + +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; + } + } + + ResumeWaitingThread(this); } } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bb8778c98..a6d822e60 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -4,25 +4,51 @@ #pragma once +#include + #include "common/common_types.h" #include "core/hle/kernel/kernel.h" namespace Kernel { -/** - * Releases a mutex - * @param handle Handle to mutex to release - */ -ResultCode ReleaseMutex(Handle handle); - -/** - * 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="Unknown"); +class Thread; + +class Mutex : public WaitObject { +public: + /** + * Creates a mutex. + * @param initial_locked Specifies if the mutex should be locked initially + * @param name Optional name of mutex + * @return Pointer to new Mutex object + */ + static ResultVal> Create(bool initial_locked, std::string name = "Unknown"); + + 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 + std::string name; ///< Name of mutex (optional) + SharedPtr holding_thread; ///< Thread that has acquired the mutex + + bool ShouldWait() override; + void Acquire() override; + + /** + * Acquires the specified mutex for the specified thread + * @param mutex Mutex that is to be acquired + * @param thread Thread that will acquire the mutex + */ + void Acquire(Thread* thread); + void Release(); + +private: + Mutex() = default; +}; /** * Releases all the mutexes held by the specified thread diff --git a/src/core/hle/service/apt_s.cpp b/src/core/hle/service/apt_s.cpp index 31e6653ef..7ad428ee7 100644 --- a/src/core/hle/service/apt_s.cpp +++ b/src/core/hle/service/apt_s.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/apt_s.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp index 1f6b148e8..5d7a6e060 100644 --- a/src/core/hle/service/apt_u.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -10,6 +10,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/thread.h" #include "core/hle/service/apt_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -28,7 +29,7 @@ static const VAddr SHARED_FONT_VADDR = 0x18000000; /// Handle to shared memory region designated to for shared system font static Kernel::SharedPtr shared_font_mem; -static Handle lock_handle = 0; +static Kernel::SharedPtr lock; static Handle notification_event_handle = 0; ///< APT notification event handle static Handle pause_event_handle = 0; ///< APT pause event handle static std::vector shared_font; @@ -76,8 +77,8 @@ void Initialize(Service::Interface* self) { Kernel::ClearEvent(notification_event_handle); Kernel::SignalEvent(pause_event_handle); // Fire start event - _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); - Kernel::ReleaseMutex(lock_handle); + _assert_msg_(KERNEL, (nullptr != lock), "Cannot initialize without lock"); + lock->Release(); cmd_buff[1] = RESULT_SUCCESS.raw; // No error } @@ -103,10 +104,9 @@ void GetLockHandle(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field - if (0 == lock_handle) { + if (nullptr == lock) { // TODO(bunnei): Verify if this is created here or at application boot? - lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); - Kernel::ReleaseMutex(lock_handle); + lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); } cmd_buff[1] = RESULT_SUCCESS.raw; // No error @@ -116,7 +116,7 @@ void GetLockHandle(Service::Interface* self) { cmd_buff[3] = 0; cmd_buff[4] = 0; - cmd_buff[5] = lock_handle; + cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom(); LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); } @@ -520,7 +520,7 @@ Interface::Interface() { shared_font_mem = nullptr; } - lock_handle = 0; + lock = nullptr; Register(FunctionTable, ARRAY_SIZE(FunctionTable)); } diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index b093d0368..76ce59b29 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -364,18 +364,32 @@ static Result SetThreadPriority(Handle handle, s32 priority) { } /// Create a mutex -static Result CreateMutex(Handle* mutex, u32 initial_locked) { - *mutex = Kernel::CreateMutex((initial_locked != 0)); +static Result CreateMutex(Handle* handle, u32 initial_locked) { + using Kernel::Mutex; + + auto mutex_res = Mutex::Create(initial_locked != 0); + if (mutex_res.Failed()) + return mutex_res.Code().raw; + SharedPtr mutex = mutex_res.MoveFrom(); + + *handle = Kernel::g_handle_table.Create(mutex).MoveFrom(); LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", - initial_locked ? "true" : "false", *mutex); + initial_locked ? "true" : "false", *handle); return 0; } /// Release a mutex static Result ReleaseMutex(Handle handle) { + using Kernel::Mutex; + LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); - ResultCode res = Kernel::ReleaseMutex(handle); - return res.raw; + + SharedPtr mutex = Kernel::g_handle_table.Get(handle); + if (mutex == nullptr) + return InvalidHandle(ErrorModule::Kernel).raw; + + mutex->Release(); + return RESULT_SUCCESS.raw; } /// Get the ID for the specified thread. -- cgit v1.2.3