Merge pull request #2234 from lioncash/mutex
core/hle/kernel: Make Mutex a per-process class.
This commit is contained in:
		| @@ -2,7 +2,6 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
| #include <map> |  | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <vector> | #include <vector> | ||||||
|  |  | ||||||
| @@ -10,8 +9,11 @@ | |||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/kernel/errors.h" | #include "core/hle/kernel/errors.h" | ||||||
| #include "core/hle/kernel/handle_table.h" | #include "core/hle/kernel/handle_table.h" | ||||||
|  | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/mutex.h" | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/object.h" | #include "core/hle/kernel/object.h" | ||||||
|  | #include "core/hle/kernel/process.h" | ||||||
|  | #include "core/hle/kernel/scheduler.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/memory.h" | #include "core/memory.h" | ||||||
| @@ -57,41 +59,47 @@ static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_t | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle holding_thread_handle, | Mutex::Mutex(Core::System& system) : system{system} {} | ||||||
|  | Mutex::~Mutex() = default; | ||||||
|  |  | ||||||
|  | ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | ||||||
|                              Handle requesting_thread_handle) { |                              Handle requesting_thread_handle) { | ||||||
|     // The mutex address must be 4-byte aligned |     // The mutex address must be 4-byte aligned | ||||||
|     if ((address % sizeof(u32)) != 0) { |     if ((address % sizeof(u32)) != 0) { | ||||||
|         return ERR_INVALID_ADDRESS; |         return ERR_INVALID_ADDRESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | ||||||
|  |     Thread* const current_thread = system.CurrentScheduler().GetCurrentThread(); | ||||||
|     SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); |     SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); | ||||||
|     SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); |     SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); | ||||||
|  |  | ||||||
|     // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another |     // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another | ||||||
|     // thread. |     // thread. | ||||||
|     ASSERT(requesting_thread == GetCurrentThread()); |     ASSERT(requesting_thread == current_thread); | ||||||
|  |  | ||||||
|     u32 addr_value = Memory::Read32(address); |     const u32 addr_value = Memory::Read32(address); | ||||||
|  |  | ||||||
|     // If the mutex isn't being held, just return success. |     // If the mutex isn't being held, just return success. | ||||||
|     if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { |     if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { | ||||||
|         return RESULT_SUCCESS; |         return RESULT_SUCCESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (holding_thread == nullptr) |     if (holding_thread == nullptr) { | ||||||
|         return ERR_INVALID_HANDLE; |         return ERR_INVALID_HANDLE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Wait until the mutex is released |     // Wait until the mutex is released | ||||||
|     GetCurrentThread()->SetMutexWaitAddress(address); |     current_thread->SetMutexWaitAddress(address); | ||||||
|     GetCurrentThread()->SetWaitHandle(requesting_thread_handle); |     current_thread->SetWaitHandle(requesting_thread_handle); | ||||||
|  |  | ||||||
|     GetCurrentThread()->SetStatus(ThreadStatus::WaitMutex); |     current_thread->SetStatus(ThreadStatus::WaitMutex); | ||||||
|     GetCurrentThread()->InvalidateWakeupCallback(); |     current_thread->InvalidateWakeupCallback(); | ||||||
|  |  | ||||||
|     // Update the lock holder thread's priority to prevent priority inversion. |     // Update the lock holder thread's priority to prevent priority inversion. | ||||||
|     holding_thread->AddMutexWaiter(GetCurrentThread()); |     holding_thread->AddMutexWaiter(current_thread); | ||||||
|  |  | ||||||
|     Core::System::GetInstance().PrepareReschedule(); |     system.PrepareReschedule(); | ||||||
|  |  | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| @@ -102,7 +110,8 @@ ResultCode Mutex::Release(VAddr address) { | |||||||
|         return ERR_INVALID_ADDRESS; |         return ERR_INVALID_ADDRESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); |     auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); | ||||||
|  |     auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); | ||||||
|  |  | ||||||
|     // There are no more threads waiting for the mutex, release it completely. |     // There are no more threads waiting for the mutex, release it completely. | ||||||
|     if (thread == nullptr) { |     if (thread == nullptr) { | ||||||
| @@ -111,7 +120,7 @@ ResultCode Mutex::Release(VAddr address) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Transfer the ownership of the mutex from the previous owner to the new one. |     // Transfer the ownership of the mutex from the previous owner to the new one. | ||||||
|     TransferMutexOwnership(address, GetCurrentThread(), thread); |     TransferMutexOwnership(address, current_thread, thread); | ||||||
|  |  | ||||||
|     u32 mutex_value = thread->GetWaitHandle(); |     u32 mutex_value = thread->GetWaitHandle(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,32 +5,34 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/object.h" |  | ||||||
|  |  | ||||||
| union ResultCode; | union ResultCode; | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Core { | ||||||
|  | class System; | ||||||
|  | } | ||||||
|  |  | ||||||
| class HandleTable; | namespace Kernel { | ||||||
| class Thread; |  | ||||||
|  |  | ||||||
| class Mutex final { | class Mutex final { | ||||||
| public: | public: | ||||||
|  |     explicit Mutex(Core::System& system); | ||||||
|  |     ~Mutex(); | ||||||
|  |  | ||||||
|     /// Flag that indicates that a mutex still has threads waiting for it. |     /// Flag that indicates that a mutex still has threads waiting for it. | ||||||
|     static constexpr u32 MutexHasWaitersFlag = 0x40000000; |     static constexpr u32 MutexHasWaitersFlag = 0x40000000; | ||||||
|     /// Mask of the bits in a mutex address value that contain the mutex owner. |     /// Mask of the bits in a mutex address value that contain the mutex owner. | ||||||
|     static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; |     static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; | ||||||
|  |  | ||||||
|     /// Attempts to acquire a mutex at the specified address. |     /// Attempts to acquire a mutex at the specified address. | ||||||
|     static ResultCode TryAcquire(HandleTable& handle_table, VAddr address, |     ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, | ||||||
|                                  Handle holding_thread_handle, Handle requesting_thread_handle); |                           Handle requesting_thread_handle); | ||||||
|  |  | ||||||
|     /// Releases the mutex at the specified address. |     /// Releases the mutex at the specified address. | ||||||
|     static ResultCode Release(VAddr address); |     ResultCode Release(VAddr address); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     Mutex() = default; |     Core::System& system; | ||||||
|     ~Mutex() = default; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Kernel | } // namespace Kernel | ||||||
|   | |||||||
| @@ -229,7 +229,8 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) { | |||||||
| } | } | ||||||
|  |  | ||||||
| Process::Process(Core::System& system) | Process::Process(Core::System& system) | ||||||
|     : WaitObject{system.Kernel()}, address_arbiter{system}, system{system} {} |     : WaitObject{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} | ||||||
|  |  | ||||||
| Process::~Process() = default; | Process::~Process() = default; | ||||||
|  |  | ||||||
| void Process::Acquire(Thread* thread) { | void Process::Acquire(Thread* thread) { | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ | |||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/kernel/address_arbiter.h" | #include "core/hle/kernel/address_arbiter.h" | ||||||
| #include "core/hle/kernel/handle_table.h" | #include "core/hle/kernel/handle_table.h" | ||||||
|  | #include "core/hle/kernel/mutex.h" | ||||||
| #include "core/hle/kernel/process_capability.h" | #include "core/hle/kernel/process_capability.h" | ||||||
| #include "core/hle/kernel/vm_manager.h" | #include "core/hle/kernel/vm_manager.h" | ||||||
| #include "core/hle/kernel/wait_object.h" | #include "core/hle/kernel/wait_object.h" | ||||||
| @@ -126,6 +127,16 @@ public: | |||||||
|         return address_arbiter; |         return address_arbiter; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Gets a reference to the process' mutex lock. | ||||||
|  |     Mutex& GetMutex() { | ||||||
|  |         return mutex; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Gets a const reference to the process' mutex lock | ||||||
|  |     const Mutex& GetMutex() const { | ||||||
|  |         return mutex; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Gets the current status of the process |     /// Gets the current status of the process | ||||||
|     ProcessStatus GetStatus() const { |     ProcessStatus GetStatus() const { | ||||||
|         return status; |         return status; | ||||||
| @@ -288,6 +299,11 @@ private: | |||||||
|     /// Per-process address arbiter. |     /// Per-process address arbiter. | ||||||
|     AddressArbiter address_arbiter; |     AddressArbiter address_arbiter; | ||||||
|  |  | ||||||
|  |     /// The per-process mutex lock instance used for handling various | ||||||
|  |     /// forms of services, such as lock arbitration, and condition | ||||||
|  |     /// variable related facilities. | ||||||
|  |     Mutex mutex; | ||||||
|  |  | ||||||
|     /// Random values for svcGetInfo RandomEntropy |     /// Random values for svcGetInfo RandomEntropy | ||||||
|     std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; |     std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -551,8 +551,8 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||||||
|         return ERR_INVALID_ADDRESS; |         return ERR_INVALID_ADDRESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |     auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess(); | ||||||
|     return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, |     return current_process->GetMutex().TryAcquire(mutex_addr, holding_thread_handle, | ||||||
|                                                   requesting_thread_handle); |                                                   requesting_thread_handle); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -571,7 +571,8 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | |||||||
|         return ERR_INVALID_ADDRESS; |         return ERR_INVALID_ADDRESS; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return Mutex::Release(mutex_addr); |     auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess(); | ||||||
|  |     return current_process->GetMutex().Release(mutex_addr); | ||||||
| } | } | ||||||
|  |  | ||||||
| enum class BreakType : u32 { | enum class BreakType : u32 { | ||||||
| @@ -1340,11 +1341,15 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var | |||||||
|         "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", |         "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", | ||||||
|         mutex_addr, condition_variable_addr, thread_handle, nano_seconds); |         mutex_addr, condition_variable_addr, thread_handle, nano_seconds); | ||||||
|  |  | ||||||
|     const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |     auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess(); | ||||||
|  |     const auto& handle_table = current_process->GetHandleTable(); | ||||||
|     SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |     SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | ||||||
|     ASSERT(thread); |     ASSERT(thread); | ||||||
|  |  | ||||||
|     CASCADE_CODE(Mutex::Release(mutex_addr)); |     const auto release_result = current_process->GetMutex().Release(mutex_addr); | ||||||
|  |     if (release_result.IsError()) { | ||||||
|  |         return release_result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     SharedPtr<Thread> current_thread = GetCurrentThread(); |     SharedPtr<Thread> current_thread = GetCurrentThread(); | ||||||
|     current_thread->SetCondVarWaitAddress(condition_variable_addr); |     current_thread->SetCondVarWaitAddress(condition_variable_addr); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user