Skip to content

Commit cfa6d07

Browse files
committed
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 #5556
1 parent 4e22295 commit cfa6d07

File tree

1 file changed

+27
-24
lines changed

1 file changed

+27
-24
lines changed

platform/mbed_critical.c

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -110,39 +110,42 @@ MBED_WEAK void core_util_critical_section_exit(void)
110110

111111
bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
112112
{
113-
uint8_t currentValue = __LDREXB((volatile uint8_t*)ptr);
114-
if (currentValue != *expectedCurrentValue) {
115-
*expectedCurrentValue = currentValue;
116-
__CLREX();
117-
return false;
118-
}
119-
120-
return !__STREXB(desiredValue, (volatile uint8_t*)ptr);
113+
do {
114+
uint8_t currentValue = __LDREXB((volatile uint8_t*)ptr);
115+
if (currentValue != *expectedCurrentValue) {
116+
*expectedCurrentValue = currentValue;
117+
__CLREX();
118+
return false;
119+
}
120+
} while (__STREXB(desiredValue, (volatile uint8_t*)ptr));
121+
return true;
121122
}
122123

123124
bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue)
124125
{
125-
uint16_t currentValue = __LDREXH((volatile uint16_t*)ptr);
126-
if (currentValue != *expectedCurrentValue) {
127-
*expectedCurrentValue = currentValue;
128-
__CLREX();
129-
return false;
130-
}
131-
132-
return !__STREXH(desiredValue, (volatile uint16_t*)ptr);
126+
do {
127+
uint16_t currentValue = __LDREXH((volatile uint16_t*)ptr);
128+
if (currentValue != *expectedCurrentValue) {
129+
*expectedCurrentValue = currentValue;
130+
__CLREX();
131+
return false;
132+
}
133+
} while (__STREXH(desiredValue, (volatile uint16_t*)ptr));
134+
return true;
133135
}
134136

135137

136138
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue)
137139
{
138-
uint32_t currentValue = __LDREXW((volatile uint32_t*)ptr);
139-
if (currentValue != *expectedCurrentValue) {
140-
*expectedCurrentValue = currentValue;
141-
__CLREX();
142-
return false;
143-
}
144-
145-
return !__STREXW(desiredValue, (volatile uint32_t*)ptr);
140+
do {
141+
uint32_t currentValue = __LDREXW((volatile uint32_t*)ptr);
142+
if (currentValue != *expectedCurrentValue) {
143+
*expectedCurrentValue = currentValue;
144+
__CLREX();
145+
return false;
146+
}
147+
} while (__STREXW(desiredValue, (volatile uint32_t*)ptr));
148+
return true;
146149
}
147150

148151
uint8_t core_util_atomic_incr_u8(uint8_t *valuePtr, uint8_t delta)

0 commit comments

Comments
 (0)