summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-10-07 18:57:13 -0400
committerGravatar FernandoS272019-10-15 11:55:18 -0400
commit44e09e5f21915391672558940842b92e3a64cb1b (patch)
tree3a0e4db9cff1ad0ed7c70d4a6fc91695f8e1c137 /src/core/hle/kernel/svc.cpp
parentKernel: Clang Format (diff)
downloadyuzu-44e09e5f21915391672558940842b92e3a64cb1b.tar.gz
yuzu-44e09e5f21915391672558940842b92e3a64cb1b.tar.xz
yuzu-44e09e5f21915391672558940842b92e3a64cb1b.zip
Kernel: Correct Results in Condition Variables and Mutexes
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp27
1 files changed, 9 insertions, 18 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index bd67fc96d..823d1d403 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1677,18 +1677,20 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1677 1677
1678 // Atomically read the value of the mutex. 1678 // Atomically read the value of the mutex.
1679 u32 mutex_val = 0; 1679 u32 mutex_val = 0;
1680 u32 update_val = 0;
1681 const VAddr mutex_address = thread->GetMutexWaitAddress();
1680 do { 1682 do {
1681 monitor.SetExclusive(current_core, thread->GetMutexWaitAddress()); 1683 monitor.SetExclusive(current_core, mutex_address);
1682 1684
1683 // If the mutex is not yet acquired, acquire it. 1685 // If the mutex is not yet acquired, acquire it.
1684 mutex_val = Memory::Read32(thread->GetMutexWaitAddress()); 1686 mutex_val = Memory::Read32(mutex_address);
1685 1687
1686 if (mutex_val != 0) { 1688 if (mutex_val != 0) {
1687 monitor.ClearExclusive(); 1689 update_val = mutex_val | Mutex::MutexHasWaitersFlag;
1688 break; 1690 } else {
1691 update_val = thread->GetWaitHandle();
1689 } 1692 }
1690 } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(), 1693 } while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val));
1691 thread->GetWaitHandle()));
1692 if (mutex_val == 0) { 1694 if (mutex_val == 0) {
1693 // We were able to acquire the mutex, resume this thread. 1695 // We were able to acquire the mutex, resume this thread.
1694 ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); 1696 ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar);
@@ -1702,20 +1704,9 @@ static ResultCode SignalProcessWideKey(Core::System& system, VAddr condition_var
1702 thread->SetLockOwner(nullptr); 1704 thread->SetLockOwner(nullptr);
1703 thread->SetMutexWaitAddress(0); 1705 thread->SetMutexWaitAddress(0);
1704 thread->SetWaitHandle(0); 1706 thread->SetWaitHandle(0);
1707 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
1705 system.PrepareReschedule(thread->GetProcessorID()); 1708 system.PrepareReschedule(thread->GetProcessorID());
1706 } else { 1709 } else {
1707 // Atomically signal that the mutex now has a waiting thread.
1708 do {
1709 monitor.SetExclusive(current_core, thread->GetMutexWaitAddress());
1710
1711 // Ensure that the mutex value is still what we expect.
1712 u32 value = Memory::Read32(thread->GetMutexWaitAddress());
1713 // TODO(Subv): When this happens, the kernel just clears the exclusive state and
1714 // retries the initial read for this thread.
1715 ASSERT_MSG(mutex_val == value, "Unhandled synchronization primitive case");
1716 } while (!monitor.ExclusiveWrite32(current_core, thread->GetMutexWaitAddress(),
1717 mutex_val | Mutex::MutexHasWaitersFlag));
1718
1719 // The mutex is already owned by some other thread, make this thread wait on it. 1710 // The mutex is already owned by some other thread, make this thread wait on it.
1720 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); 1711 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
1721 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1712 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();