Merge pull request #10005 from liamwhite/kernel-atomics
kernel: fix unbounded stack usage in atomics
This commit is contained in:
commit
0730dc6c44
|
@ -35,24 +35,30 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
|
||||||
|
|
||||||
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
||||||
|
|
||||||
// Load the value from the address.
|
s32 current_value{};
|
||||||
const s32 current_value =
|
|
||||||
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
|
|
||||||
|
|
||||||
// Compare it to the desired one.
|
while (true) {
|
||||||
if (current_value < value) {
|
// Load the value from the address.
|
||||||
// If less than, we want to try to decrement.
|
current_value =
|
||||||
const s32 decrement_value = current_value - 1;
|
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;
|
||||||
|
|
||||||
|
// 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.
|
// 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.
|
// We're done.
|
||||||
|
@ -70,23 +76,29 @@ bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32
|
||||||
|
|
||||||
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
// TODO(bunnei): We should call CanAccessAtomic(..) here.
|
||||||
|
|
||||||
|
s32 current_value{};
|
||||||
|
|
||||||
// Load the value from the address.
|
// Load the value from the address.
|
||||||
const s32 current_value =
|
while (true) {
|
||||||
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
|
current_value =
|
||||||
|
static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
|
||||||
|
|
||||||
// Compare it to the desired one.
|
// Compare it to the desired one.
|
||||||
if (current_value == value) {
|
if (current_value == value) {
|
||||||
// If equal, we want to try to write the new 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.
|
// 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.
|
// We're done.
|
||||||
|
|
|
@ -33,21 +33,26 @@ bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u
|
||||||
auto& monitor = system.Monitor();
|
auto& monitor = system.Monitor();
|
||||||
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
|
||||||
|
|
||||||
// Load the value from the address.
|
u32 expected{};
|
||||||
const auto expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
|
|
||||||
|
|
||||||
// Orr in the new mask.
|
while (true) {
|
||||||
u32 value = expected | new_orr_mask;
|
// Load the value from the address.
|
||||||
|
expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
|
||||||
|
|
||||||
// If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
|
// Orr in the new mask.
|
||||||
if (!expected) {
|
u32 value = expected | new_orr_mask;
|
||||||
value = if_zero;
|
|
||||||
}
|
// If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
|
||||||
|
if (!expected) {
|
||||||
|
value = if_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to store.
|
||||||
|
if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to store.
|
|
||||||
if (!monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
|
|
||||||
// If we failed to store, try again.
|
// If we failed to store, try again.
|
||||||
return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're done.
|
// We're done.
|
||||||
|
|
Reference in New Issue