mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Kernel: Convert Mutex to not use Handles
This commit is contained in:
		
							parent
							
								
									38e7122f23
								
							
						
					
					
						commit
						882b6fed75
					
				
					 5 changed files with 109 additions and 113 deletions
				
			
		|  | @ -13,59 +13,30 @@ | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | 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<Thread> holding_thread;           ///< Thread that has acquired the mutex
 |  | ||||||
| 
 |  | ||||||
|     bool ShouldWait() override; |  | ||||||
|     void Acquire() override; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | typedef std::multimap<SharedPtr<Thread>, SharedPtr<Mutex>> MutexMap; | ||||||
| static MutexMap g_mutex_held_locks; | 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 |  * Resumes a thread waiting for the specified mutex | ||||||
|  * @param mutex The mutex that some thread is waiting on |  * @param mutex The mutex that some thread is waiting on | ||||||
|  */ |  */ | ||||||
| static 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...
 |     // Find the next waiting thread for the mutex...
 | ||||||
|     auto next_thread = mutex->WakeupNextThread(); |     auto next_thread = mutex->WakeupNextThread(); | ||||||
|     if (next_thread != nullptr) { |     if (next_thread != nullptr) { | ||||||
|         MutexAcquireLock(mutex, next_thread); |         mutex->Acquire(next_thread); | ||||||
|     } else { |  | ||||||
|         // Reset mutex lock thread handle, nothing is waiting
 |  | ||||||
|         mutex->locked = false; |  | ||||||
|         mutex->holding_thread = nullptr; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ReleaseThreadMutexes(Thread* 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
 |     // 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()); |         ResumeWaitingThread(iter->second.get()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -73,62 +44,21 @@ void ReleaseThreadMutexes(Thread* thread) { | ||||||
|     g_mutex_held_locks.erase(thread); |     g_mutex_held_locks.erase(thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool ReleaseMutex(Mutex* mutex) { | ResultVal<SharedPtr<Mutex>> Mutex::Create(bool initial_locked, std::string name) { | ||||||
|     if (mutex->locked) { |     SharedPtr<Mutex> mutex(new Mutex); | ||||||
|         auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); |     // TOOD(yuriks): Don't create Handle (see Thread::Create())
 | ||||||
|  |     CASCADE_RESULT(auto unused, Kernel::g_handle_table.Create(mutex)); | ||||||
| 
 | 
 | ||||||
|         for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { |     mutex->initial_locked = initial_locked; | ||||||
|             if (iter->second == mutex) { |     mutex->locked = false; | ||||||
|                 g_mutex_held_locks.erase(iter); |     mutex->name = std::move(name); | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         ResumeWaitingThread(mutex); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * 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); |  | ||||||
| 
 |  | ||||||
|     mutex->locked = mutex->initial_locked = initial_locked; |  | ||||||
|     mutex->name = name; |  | ||||||
|     mutex->holding_thread = nullptr; |     mutex->holding_thread = nullptr; | ||||||
| 
 | 
 | ||||||
|     // Acquire mutex with current thread if initialized as locked...
 |     // Acquire mutex with current thread if initialized as locked...
 | ||||||
|     if (mutex->locked) |     if (initial_locked) | ||||||
|         MutexAcquireLock(mutex, GetCurrentThread()); |         mutex->Acquire(); | ||||||
| 
 | 
 | ||||||
|     return mutex; |     return MakeResult<SharedPtr<Mutex>>(mutex); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Handle CreateMutex(bool initial_locked, const std::string& name) { |  | ||||||
|     Handle handle; |  | ||||||
|     Mutex* mutex = CreateMutex(handle, initial_locked, name); |  | ||||||
|     return handle; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Mutex::ShouldWait() { | bool Mutex::ShouldWait() { | ||||||
|  | @ -136,9 +66,34 @@ bool Mutex::ShouldWait() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Mutex::Acquire() { | void Mutex::Acquire() { | ||||||
|  |     Acquire(GetCurrentThread()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Mutex::Acquire(Thread* thread) { | ||||||
|     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); |     _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); | ||||||
|  |     if (locked) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|     locked = true; |     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
 | } // namespace
 | ||||||
|  |  | ||||||
|  | @ -4,25 +4,51 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| 
 | 
 | ||||||
| /**
 | class Thread; | ||||||
|  * Releases a mutex |  | ||||||
|  * @param handle Handle to mutex to release |  | ||||||
|  */ |  | ||||||
| ResultCode ReleaseMutex(Handle handle); |  | ||||||
| 
 | 
 | ||||||
| /**
 | class Mutex : public WaitObject { | ||||||
|  * Creates a mutex | public: | ||||||
|  * @param initial_locked Specifies if the mutex should be locked initially |     /**
 | ||||||
|  * @param name Optional name of mutex |      * Creates a mutex. | ||||||
|  * @return Handle to newly created object |      * @param initial_locked Specifies if the mutex should be locked initially | ||||||
|  */ |      * @param name Optional name of mutex | ||||||
| Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); |      * @return Pointer to new Mutex object | ||||||
|  |      */ | ||||||
|  |     static ResultVal<SharedPtr<Mutex>> 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<Thread> 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 |  * Releases all the mutexes held by the specified thread | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include "core/hle/kernel/event.h" | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/service/apt_s.h" | #include "core/hle/service/apt_s.h" | ||||||
| 
 | 
 | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include "core/hle/kernel/event.h" | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
|  | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/service/apt_u.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
 | /// Handle to shared memory region designated to for shared system font
 | ||||||
| static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; | ||||||
| 
 | 
 | ||||||
| static Handle lock_handle = 0; | static Kernel::SharedPtr<Kernel::Mutex> lock; | ||||||
| static Handle notification_event_handle = 0; ///< APT notification event handle
 | static Handle notification_event_handle = 0; ///< APT notification event handle
 | ||||||
| static Handle pause_event_handle = 0; ///< APT pause event handle
 | static Handle pause_event_handle = 0; ///< APT pause event handle
 | ||||||
| static std::vector<u8> shared_font; | static std::vector<u8> shared_font; | ||||||
|  | @ -76,8 +77,8 @@ void Initialize(Service::Interface* self) { | ||||||
|     Kernel::ClearEvent(notification_event_handle); |     Kernel::ClearEvent(notification_event_handle); | ||||||
|     Kernel::SignalEvent(pause_event_handle); // Fire start event
 |     Kernel::SignalEvent(pause_event_handle); // Fire start event
 | ||||||
| 
 | 
 | ||||||
|     _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); |     _assert_msg_(KERNEL, (nullptr != lock), "Cannot initialize without lock"); | ||||||
|     Kernel::ReleaseMutex(lock_handle); |     lock->Release(); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| } | } | ||||||
|  | @ -103,10 +104,9 @@ void GetLockHandle(Service::Interface* self) { | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||||
|     u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
 |     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?
 |         // TODO(bunnei): Verify if this is created here or at application boot?
 | ||||||
|         lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); |         lock = Kernel::Mutex::Create(false, "APT_U:Lock").MoveFrom(); | ||||||
|         Kernel::ReleaseMutex(lock_handle); |  | ||||||
|     } |     } | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 |     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||||
| 
 | 
 | ||||||
|  | @ -116,7 +116,7 @@ void GetLockHandle(Service::Interface* self) { | ||||||
|     cmd_buff[3] = 0; |     cmd_buff[3] = 0; | ||||||
|     cmd_buff[4] = 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]); |     LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -520,7 +520,7 @@ Interface::Interface() { | ||||||
|         shared_font_mem = nullptr; |         shared_font_mem = nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lock_handle = 0; |     lock = nullptr; | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |     Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -364,18 +364,32 @@ static Result SetThreadPriority(Handle handle, s32 priority) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Create a mutex
 | /// Create a mutex
 | ||||||
| static Result CreateMutex(Handle* mutex, u32 initial_locked) { | static Result CreateMutex(Handle* handle, u32 initial_locked) { | ||||||
|     *mutex = Kernel::CreateMutex((initial_locked != 0)); |     using Kernel::Mutex; | ||||||
|  | 
 | ||||||
|  |     auto mutex_res = Mutex::Create(initial_locked != 0); | ||||||
|  |     if (mutex_res.Failed()) | ||||||
|  |         return mutex_res.Code().raw; | ||||||
|  |     SharedPtr<Mutex> mutex = mutex_res.MoveFrom(); | ||||||
|  | 
 | ||||||
|  |     *handle = Kernel::g_handle_table.Create(mutex).MoveFrom(); | ||||||
|     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", |     LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X", | ||||||
|         initial_locked ? "true" : "false", *mutex); |         initial_locked ? "true" : "false", *handle); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Release a mutex
 | /// Release a mutex
 | ||||||
| static Result ReleaseMutex(Handle handle) { | static Result ReleaseMutex(Handle handle) { | ||||||
|  |     using Kernel::Mutex; | ||||||
|  | 
 | ||||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); |     LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle); | ||||||
|     ResultCode res = Kernel::ReleaseMutex(handle); | 
 | ||||||
|     return res.raw; |     SharedPtr<Mutex> mutex = Kernel::g_handle_table.Get<Mutex>(handle); | ||||||
|  |     if (mutex == nullptr) | ||||||
|  |         return InvalidHandle(ErrorModule::Kernel).raw; | ||||||
|  | 
 | ||||||
|  |     mutex->Release(); | ||||||
|  |     return RESULT_SUCCESS.raw; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Get the ID for the specified thread.
 | /// Get the ID for the specified thread.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue