summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.cpp
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-25 17:37:12 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:14 -0400
commit203e706302c24f278eec7d0bd2362ce73b0e2612 (patch)
tree2a725cf13ed569fd846f7ab603475ca1cd06302f /src/core/hle/kernel/mutex.cpp
parentSVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, Cance... (diff)
downloadyuzu-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.cpp65
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
126ResultCode Mutex::Release(VAddr address) { 127std::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
154ResultCode 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