Make LDREX/STREX CAS functions strong

The LDREX/STREX implementations of the compare-and-swap functions were
weak (they could spuriously fail when the value was expected), whereas
the critial section implementation was strong, and the documentation has
no suggestion that there might be spurious failures.

Rationalise by adding a retry loop for STREX failure, so that it only
returns false when the value is not expected.

Fixes https://github.com/ARMmbed/mbed-os/issues/5556
pull/5596/head
Kevin Bracey 2017-11-28 11:50:48 +02:00
parent 4e222952d7
commit cfa6d07a3b
1 changed files with 27 additions and 24 deletions

View File

@ -110,39 +110,42 @@ MBED_WEAK void core_util_critical_section_exit(void)
bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
{
uint8_t currentValue = __LDREXB((volatile uint8_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
return !__STREXB(desiredValue, (volatile uint8_t*)ptr);
do {
uint8_t currentValue = __LDREXB((volatile uint8_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
} while (__STREXB(desiredValue, (volatile uint8_t*)ptr));
return true;
}
bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue)
{
uint16_t currentValue = __LDREXH((volatile uint16_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
return !__STREXH(desiredValue, (volatile uint16_t*)ptr);
do {
uint16_t currentValue = __LDREXH((volatile uint16_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
} while (__STREXH(desiredValue, (volatile uint16_t*)ptr));
return true;
}
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue)
{
uint32_t currentValue = __LDREXW((volatile uint32_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
return !__STREXW(desiredValue, (volatile uint32_t*)ptr);
do {
uint32_t currentValue = __LDREXW((volatile uint32_t*)ptr);
if (currentValue != *expectedCurrentValue) {
*expectedCurrentValue = currentValue;
__CLREX();
return false;
}
} while (__STREXW(desiredValue, (volatile uint32_t*)ptr));
return true;
}
uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)