diff options
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 27 |
3 files changed, 17 insertions, 24 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 77edbcd1f..002c5af2b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| 16 | #include "core/hle/kernel/address_arbiter.h" | 16 | #include "core/hle/kernel/address_arbiter.h" |
| 17 | #include "core/hle/kernel/client_port.h" | 17 | #include "core/hle/kernel/client_port.h" |
| 18 | #include "core/hle/kernel/errors.h" | ||
| 18 | #include "core/hle/kernel/handle_table.h" | 19 | #include "core/hle/kernel/handle_table.h" |
| 19 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/process.h" | 21 | #include "core/hle/kernel/process.h" |
| @@ -60,12 +61,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 60 | if (thread->HasWakeupCallback()) { | 61 | if (thread->HasWakeupCallback()) { |
| 61 | resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); | 62 | resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); |
| 62 | } | 63 | } |
| 63 | } | 64 | } else if (thread->GetStatus() == ThreadStatus::WaitMutex || |
| 64 | 65 | thread->GetStatus() == ThreadStatus::WaitCondVar) { | |
| 65 | if (thread->GetMutexWaitAddress() != 0 || thread->GetCondVarWaitAddress() != 0 || | ||
| 66 | thread->GetWaitHandle() != 0) { | ||
| 67 | ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex || | ||
| 68 | thread->GetStatus() == ThreadStatus::WaitCondVar); | ||
| 69 | thread->SetMutexWaitAddress(0); | 66 | thread->SetMutexWaitAddress(0); |
| 70 | thread->SetCondVarWaitAddress(0); | 67 | thread->SetCondVarWaitAddress(0); |
| 71 | thread->SetWaitHandle(0); | 68 | thread->SetWaitHandle(0); |
| @@ -85,6 +82,10 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_ | |||
| 85 | } | 82 | } |
| 86 | 83 | ||
| 87 | if (resume) { | 84 | if (resume) { |
| 85 | if (thread->GetStatus() == ThreadStatus::WaitCondVar || | ||
| 86 | thread->GetStatus() == ThreadStatus::WaitArb) { | ||
| 87 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | ||
| 88 | } | ||
| 88 | thread->ResumeFromWait(); | 89 | thread->ResumeFromWait(); |
| 89 | } | 90 | } |
| 90 | } | 91 | } |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index eb919246c..663d0f4b6 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -139,6 +139,7 @@ ResultCode Mutex::Release(VAddr address) { | |||
| 139 | thread->SetCondVarWaitAddress(0); | 139 | thread->SetCondVarWaitAddress(0); |
| 140 | thread->SetMutexWaitAddress(0); | 140 | thread->SetMutexWaitAddress(0); |
| 141 | thread->SetWaitHandle(0); | 141 | thread->SetWaitHandle(0); |
| 142 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 142 | 143 | ||
| 143 | system.PrepareReschedule(); | 144 | system.PrepareReschedule(); |
| 144 | 145 | ||
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(); |