diff options
| author | 2020-02-25 17:37:12 -0400 | |
|---|---|---|
| committer | 2020-06-27 11:35:14 -0400 | |
| commit | 203e706302c24f278eec7d0bd2362ce73b0e2612 (patch) | |
| tree | 2a725cf13ed569fd846f7ab603475ca1cd06302f /src/core/hle/kernel/mutex.cpp | |
| parent | SVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, Cance... (diff) | |
| download | yuzu-203e706302c24f278eec7d0bd2362ce73b0e2612.tar.gz yuzu-203e706302c24f278eec7d0bd2362ce73b0e2612.tar.xz yuzu-203e706302c24f278eec7d0bd2362ce73b0e2612.zip | |
SVC: Correct ArbitrateUnlock
Diffstat (limited to 'src/core/hle/kernel/mutex.cpp')
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 65 |
1 files changed, 33 insertions, 32 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 3520c5e49..18325db57 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -84,10 +84,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 84 | 84 | ||
| 85 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 85 | const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 86 | std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); | 86 | std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); |
| 87 | std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); | 87 | std::shared_ptr<Thread> requesting_thread = |
| 88 | handle_table.Get<Thread>(requesting_thread_handle); | ||
| 88 | 89 | ||
| 89 | // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another | 90 | // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of |
| 90 | // thread. | 91 | // another thread. |
| 91 | ASSERT(requesting_thread == current_thread); | 92 | ASSERT(requesting_thread == current_thread); |
| 92 | 93 | ||
| 93 | current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | 94 | current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); |
| @@ -123,47 +124,47 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, | |||
| 123 | return current_thread->GetSignalingResult(); | 124 | return current_thread->GetSignalingResult(); |
| 124 | } | 125 | } |
| 125 | 126 | ||
| 126 | ResultCode Mutex::Release(VAddr address) { | 127 | std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thread> owner, |
| 127 | // The mutex address must be 4-byte aligned | 128 | VAddr address) { |
| 128 | if ((address % sizeof(u32)) != 0) { | 129 | // The mutex address must be 4-byte aligned |
| 129 | LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); | 130 | if ((address % sizeof(u32)) != 0) { |
| 130 | return ERR_INVALID_ADDRESS; | 131 | LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); |
| 131 | } | 132 | return {ERR_INVALID_ADDRESS, nullptr}; |
| 132 | 133 | } | |
| 133 | std::shared_ptr<Thread> current_thread = | ||
| 134 | SharedFrom(system.CurrentScheduler().GetCurrentThread()); | ||
| 135 | auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); | ||
| 136 | 134 | ||
| 137 | // There are no more threads waiting for the mutex, release it completely. | 135 | auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); |
| 138 | if (thread == nullptr) { | 136 | if (new_owner == nullptr) { |
| 139 | system.Memory().Write32(address, 0); | 137 | system.Memory().Write32(address, 0); |
| 140 | return RESULT_SUCCESS; | 138 | return {RESULT_SUCCESS, nullptr}; |
| 141 | } | 139 | } |
| 142 | |||
| 143 | // Transfer the ownership of the mutex from the previous owner to the new one. | 140 | // Transfer the ownership of the mutex from the previous owner to the new one. |
| 144 | TransferMutexOwnership(address, current_thread, thread); | 141 | TransferMutexOwnership(address, owner, new_owner); |
| 145 | 142 | u32 mutex_value = new_owner->GetWaitHandle(); | |
| 146 | u32 mutex_value = thread->GetWaitHandle(); | ||
| 147 | |||
| 148 | if (num_waiters >= 2) { | 143 | if (num_waiters >= 2) { |
| 149 | // Notify the guest that there are still some threads waiting for the mutex | 144 | // Notify the guest that there are still some threads waiting for the mutex |
| 150 | mutex_value |= Mutex::MutexHasWaitersFlag; | 145 | mutex_value |= Mutex::MutexHasWaitersFlag; |
| 151 | } | 146 | } |
| 152 | 147 | new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS); | |
| 153 | // Grant the mutex to the next waiting thread and resume it. | 148 | new_owner->ResumeFromWait(); |
| 149 | new_owner->SetLockOwner(nullptr); | ||
| 154 | system.Memory().Write32(address, mutex_value); | 150 | system.Memory().Write32(address, mutex_value); |
| 151 | return {RESULT_SUCCESS, new_owner}; | ||
| 152 | } | ||
| 153 | |||
| 154 | ResultCode Mutex::Release(VAddr address) { | ||
| 155 | auto& kernel = system.Kernel(); | ||
| 156 | SchedulerLock lock(kernel); | ||
| 155 | 157 | ||
| 156 | ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); | 158 | std::shared_ptr<Thread> current_thread = |
| 157 | thread->ResumeFromWait(); | 159 | SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); |
| 158 | 160 | ||
| 159 | thread->SetLockOwner(nullptr); | 161 | auto [result, new_owner] = Unlock(current_thread, address); |
| 160 | thread->SetCondVarWaitAddress(0); | ||
| 161 | thread->SetMutexWaitAddress(0); | ||
| 162 | thread->SetWaitHandle(0); | ||
| 163 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 164 | 162 | ||
| 165 | system.PrepareReschedule(); | 163 | if (result != RESULT_SUCCESS && new_owner != nullptr) { |
| 164 | new_owner->SetSynchronizationResults(nullptr, result); | ||
| 165 | } | ||
| 166 | 166 | ||
| 167 | return RESULT_SUCCESS; | 167 | return result; |
| 168 | } | 168 | } |
| 169 | |||
| 169 | } // namespace Kernel | 170 | } // namespace Kernel |