Skip to content

Commit b076565

Browse files
authored
Merge pull request #5596 from kjbracey-arm/strong_cas
Make LDREX/STREX CAS functions strong
2 parents 244d8a9 + 59508d4 commit b076565

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
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)

platform/mbed_critical.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void core_util_critical_section_exit(void);
121121
* }
122122
*
123123
* @note: In the failure case (where the destination isn't set), the value
124-
* pointed to by expectedCurrentValue is still updated with the current value.
124+
* pointed to by expectedCurrentValue is instead updated with the current value.
125125
* This property helps writing concise code for the following incr:
126126
*
127127
* function incr(p : pointer to int, a : int) returns int {
@@ -132,6 +132,10 @@ void core_util_critical_section_exit(void);
132132
* }
133133
* return value + a
134134
* }
135+
*
136+
* @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
137+
* always succeeds if the current value is expected, as per the pseudocode
138+
* above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
135139
*/
136140
bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue);
137141

@@ -174,7 +178,7 @@ bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_
174178
* }
175179
*
176180
* @note: In the failure case (where the destination isn't set), the value
177-
* pointed to by expectedCurrentValue is still updated with the current value.
181+
* pointed to by expectedCurrentValue is instead updated with the current value.
178182
* This property helps writing concise code for the following incr:
179183
*
180184
* function incr(p : pointer to int, a : int) returns int {
@@ -185,6 +189,10 @@ bool core_util_atomic_cas_u8(uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_
185189
* }
186190
* return value + a
187191
* }
192+
*
193+
* @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
194+
* always succeeds if the current value is expected, as per the pseudocode
195+
* above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
188196
*/
189197
bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uint16_t desiredValue);
190198

@@ -227,7 +235,7 @@ bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uin
227235
* }
228236
*
229237
* @note: In the failure case (where the destination isn't set), the value
230-
* pointed to by expectedCurrentValue is still updated with the current value.
238+
* pointed to by expectedCurrentValue is instead updated with the current value.
231239
* This property helps writing concise code for the following incr:
232240
*
233241
* function incr(p : pointer to int, a : int) returns int {
@@ -237,6 +245,10 @@ bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uin
237245
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
238246
* }
239247
* return value + a
248+
*
249+
* @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
250+
* always succeeds if the current value is expected, as per the pseudocode
251+
* above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
240252
* }
241253
*/
242254
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue);
@@ -280,7 +292,7 @@ bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uin
280292
* }
281293
*
282294
* @note: In the failure case (where the destination isn't set), the value
283-
* pointed to by expectedCurrentValue is still updated with the current value.
295+
* pointed to by expectedCurrentValue is instead updated with the current value.
284296
* This property helps writing concise code for the following incr:
285297
*
286298
* function incr(p : pointer to int, a : int) returns int {
@@ -291,6 +303,10 @@ bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uin
291303
* }
292304
* return value + a
293305
* }
306+
*
307+
* @note: This corresponds to the C11 "atomic_compare_exchange_strong" - it
308+
* always succeeds if the current value is expected, as per the pseudocode
309+
* above; it will not spuriously fail as "atomic_compare_exchange_weak" may.
294310
*/
295311
bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue);
296312

0 commit comments

Comments
 (0)