diff options
Diffstat (limited to 'src/core/hle/kernel/k_address_arbiter.cpp')
-rw-r--r-- | src/core/hle/kernel/k_address_arbiter.cpp | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 274928dcf..78d43d729 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -21,8 +21,8 @@ KAddressArbiter::~KAddressArbiter() = default; namespace { -bool ReadFromUser(Core::System& system, s32* out, KProcessAddress address) { - *out = system.Memory().Read32(GetInteger(address)); +bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) { + *out = GetCurrentMemory(kernel).Read32(GetInteger(address)); return true; } @@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address // TODO(bunnei): We should call CanAccessAtomic(..) here. - // Load the value from the address. - const s32 current_value = - static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + s32 current_value{}; + + while (true) { + // Load the value from the address. + current_value = + static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); - // Compare it to the desired one. - if (current_value < value) { - // If less than, we want to try to decrement. - const s32 decrement_value = current_value - 1; + // Compare it to the desired one. + if (current_value < value) { + // If less than, we want to try to decrement. + const s32 decrement_value = current_value - 1; + + // Decrement and try to store. + if (monitor.ExclusiveWrite32(current_core, GetInteger(address), + static_cast<u32>(decrement_value))) { + break; + } - // Decrement and try to store. - if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), - static_cast<u32>(decrement_value))) { // If we failed to store, try again. - DecrementIfLessThan(system, out, address, value); + } else { + // Otherwise, clear our exclusive hold and finish + monitor.ClearExclusive(current_core); + break; } - } else { - // Otherwise, clear our exclusive hold and finish - monitor.ClearExclusive(current_core); } // We're done. @@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 // TODO(bunnei): We should call CanAccessAtomic(..) here. - // Load the value from the address. - const s32 current_value = - static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + s32 current_value{}; - // Compare it to the desired one. - if (current_value == value) { - // If equal, we want to try to write the new value. + // Load the value from the address. + while (true) { + current_value = + static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address))); + + // Compare it to the desired one. + if (current_value == value) { + // If equal, we want to try to write the new value. + + // Try to store. + if (monitor.ExclusiveWrite32(current_core, GetInteger(address), + static_cast<u32>(new_value))) { + break; + } - // Try to store. - if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), - static_cast<u32>(new_value))) { // If we failed to store, try again. - UpdateIfEqual(system, out, address, value, new_value); + } else { + // Otherwise, clear our exclusive hold and finish. + monitor.ClearExclusive(current_core); + break; } - } else { - // Otherwise, clear our exclusive hold and finish. - monitor.ClearExclusive(current_core); } // We're done. @@ -209,7 +221,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 if (value != new_value) { succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value); } else { - succeeded = ReadFromUser(m_system, std::addressof(user_value), addr); + succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); } R_UNLESS(succeeded, ResultInvalidCurrentMemory); @@ -252,7 +264,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, if (decrement) { succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value); } else { - succeeded = ReadFromUser(m_system, std::addressof(user_value), addr); + succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); } if (!succeeded) { @@ -303,7 +315,7 @@ Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) { // Read the value from userspace. s32 user_value{}; - if (!ReadFromUser(m_system, std::addressof(user_value), addr)) { + if (!ReadFromUser(m_kernel, std::addressof(user_value), addr)) { slp.CancelSleep(); R_THROW(ResultInvalidCurrentMemory); } |