diff options
| author | 2020-02-25 16:38:33 -0400 | |
|---|---|---|
| committer | 2020-06-27 11:35:13 -0400 | |
| commit | 3b5b950c895a2db217a3e5c8105cec4498a2534e (patch) | |
| tree | 2a8e054af30c9aa8039f8faa4b993e2290642184 /src/core/hle/kernel/mutex.cpp | |
| parent | SVC: Remove global HLE Lock. (diff) | |
| download | yuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.tar.gz yuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.tar.xz yuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.zip | |
SVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, CancelSynchronization, ArbitrateLock
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 7869eb32b..3520c5e49 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -72,42 +72,55 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 72 | return ERR_INVALID_ADDRESS; | 72 | return ERR_INVALID_ADDRESS; |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 75 | auto& kernel = system.Kernel(); |
| 76 | std::shared_ptr<Thread> current_thread = | 76 | std::shared_ptr<Thread> current_thread = |
| 77 | SharedFrom(system.CurrentScheduler().GetCurrentThread()); | 77 | SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); |
| 78 | std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); | 78 | { |
| 79 | std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); | 79 | SchedulerLock lock(kernel); |
| 80 | // The mutex address must be 4-byte aligned | ||
| 81 | if ((address % sizeof(u32)) != 0) { | ||
| 82 | return ERR_INVALID_ADDRESS; | ||
| 83 | } | ||
| 80 | 84 | ||
| 81 | // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another | 85 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 82 | // thread. | 86 | std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); |
| 83 | ASSERT(requesting_thread == current_thread); | 87 | std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); |
| 84 | 88 | ||
| 85 | const u32 addr_value = system.Memory().Read32(address); | 89 | // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another |
| 90 | // thread. | ||
| 91 | ASSERT(requesting_thread == current_thread); | ||
| 86 | 92 | ||
| 87 | // If the mutex isn't being held, just return success. | 93 | current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); |
| 88 | if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { | ||
| 89 | return RESULT_SUCCESS; | ||
| 90 | } | ||
| 91 | 94 | ||
| 92 | if (holding_thread == nullptr) { | 95 | const u32 addr_value = system.Memory().Read32(address); |
| 93 | LOG_ERROR(Kernel, "Holding thread does not exist! thread_handle={:08X}", | ||
| 94 | holding_thread_handle); | ||
| 95 | return ERR_INVALID_HANDLE; | ||
| 96 | } | ||
| 97 | 96 | ||
| 98 | // Wait until the mutex is released | 97 | // If the mutex isn't being held, just return success. |
| 99 | current_thread->SetMutexWaitAddress(address); | 98 | if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { |
| 100 | current_thread->SetWaitHandle(requesting_thread_handle); | 99 | return RESULT_SUCCESS; |
| 100 | } | ||
| 101 | 101 | ||
| 102 | current_thread->SetStatus(ThreadStatus::WaitMutex); | 102 | if (holding_thread == nullptr) { |
| 103 | current_thread->InvalidateWakeupCallback(); | 103 | return ERR_INVALID_HANDLE; |
| 104 | } | ||
| 104 | 105 | ||
| 105 | // Update the lock holder thread's priority to prevent priority inversion. | 106 | // Wait until the mutex is released |
| 106 | holding_thread->AddMutexWaiter(current_thread); | 107 | current_thread->SetMutexWaitAddress(address); |
| 108 | current_thread->SetWaitHandle(requesting_thread_handle); | ||
| 107 | 109 | ||
| 108 | system.PrepareReschedule(); | 110 | current_thread->SetStatus(ThreadStatus::WaitMutex); |
| 109 | 111 | ||
| 110 | return RESULT_SUCCESS; | 112 | // Update the lock holder thread's priority to prevent priority inversion. |
| 113 | holding_thread->AddMutexWaiter(current_thread); | ||
| 114 | } | ||
| 115 | |||
| 116 | { | ||
| 117 | SchedulerLock lock(kernel); | ||
| 118 | auto* owner = current_thread->GetLockOwner(); | ||
| 119 | if (owner != nullptr) { | ||
| 120 | owner->RemoveMutexWaiter(current_thread); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | return current_thread->GetSignalingResult(); | ||
| 111 | } | 124 | } |
| 112 | 125 | ||
| 113 | ResultCode Mutex::Release(VAddr address) { | 126 | ResultCode Mutex::Release(VAddr address) { |