Skip to content

Commit cf6f8e3

Browse files
committed
Added cas instrinsics for pointer values
- core_util_atomic_cas - core_util_atomic_incr - core_util_atomic_decr
1 parent 1794463 commit cf6f8e3

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

hal/api/critical.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,59 @@ bool core_util_atomic_cas_u16(uint16_t *ptr, uint16_t *expectedCurrentValue, uin
221221
*/
222222
bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uint32_t desiredValue);
223223

224+
/**
225+
* Atomic compare and set. It compares the contents of a memory location to a
226+
* given value and, only if they are the same, modifies the contents of that
227+
* memory location to a given new value. This is done as a single atomic
228+
* operation. The atomicity guarantees that the new value is calculated based on
229+
* up-to-date information; if the value had been updated by another thread in
230+
* the meantime, the write would fail due to a mismatched expectedCurrentValue.
231+
*
232+
* Refer to https://en.wikipedia.org/wiki/Compare-and-set [which may redirect
233+
* you to the article on compare-and swap].
234+
*
235+
* @param ptr The target memory location.
236+
* @param[in,out] expectedCurrentValue A pointer to some location holding the
237+
* expected current value of the data being set atomically.
238+
* The computed 'desiredValue' should be a function of this current value.
239+
* @Note: This is an in-out parameter. In the
240+
* failure case of atomic_cas (where the
241+
* destination isn't set), the pointee of expectedCurrentValue is
242+
* updated with the current value.
243+
* @param[in] desiredValue The new value computed based on '*expectedCurrentValue'.
244+
*
245+
* @return true if the memory location was atomically
246+
* updated with the desired value (after verifying
247+
* that it contained the expectedCurrentValue),
248+
* false otherwise. In the failure case,
249+
* exepctedCurrentValue is updated with the new
250+
* value of the target memory location.
251+
*
252+
* pseudocode:
253+
* function cas(p : pointer to int, old : pointer to int, new : int) returns bool {
254+
* if *p != *old {
255+
* *old = *p
256+
* return false
257+
* }
258+
* *p = new
259+
* return true
260+
* }
261+
*
262+
* @Note: In the failure case (where the destination isn't set), the value
263+
* pointed to by expectedCurrentValue is still updated with the current value.
264+
* This property helps writing concise code for the following incr:
265+
*
266+
* function incr(p : pointer to int, a : int) returns int {
267+
* done = false
268+
* *value = *p // This fetch operation need not be atomic.
269+
* while not done {
270+
* done = atomic_cas(p, &value, value + a) // *value gets updated automatically until success
271+
* }
272+
* return value + a
273+
* }
274+
*/
275+
bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue);
276+
224277
/**
225278
* Atomic increment.
226279
* @param valuePtr Target memory location being incremented.
@@ -245,6 +298,14 @@ uint16_t core_util_atomic_incr_u16(uint16_t * valuePtr, uint16_t delta);
245298
*/
246299
uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta);
247300

301+
/**
302+
* Atomic increment.
303+
* @param valuePtr Target memory location being incremented.
304+
* @param delta The amount being incremented.
305+
* @return The new incremented value.
306+
*/
307+
void *core_util_atomic_incr_ptr(void **valuePtr, unsigned delta);
308+
248309
/**
249310
* Atomic decrement.
250311
* @param valuePtr Target memory location being decremented.
@@ -269,6 +330,14 @@ uint16_t core_util_atomic_decr_u16(uint16_t * valuePtr, uint16_t delta);
269330
*/
270331
uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta);
271332

333+
/**
334+
* Atomic decrement.
335+
* @param valuePtr Target memory location being decremented.
336+
* @param delta The amount being decremented.
337+
* @return The new decremented value.
338+
*/
339+
void *core_util_atomic_decr_ptr(void **valuePtr, unsigned delta);
340+
272341
#ifdef __cplusplus
273342
} // extern "C"
274343
#endif

hal/common/critical.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,13 @@ bool core_util_atomic_cas_u32(uint32_t *ptr, uint32_t *expectedCurrentValue, uin
236236
return success;
237237
}
238238

239+
bool core_util_atomic_cas_ptr(void **ptr, void **expectedCurrentValue, void *desiredValue) {
240+
return core_util_atomic_cas_u32(
241+
(unsigned *)ptr,
242+
(unsigned *)expectedCurrentValue,
243+
(unsigned)desiredValue);
244+
}
245+
239246
uint8_t core_util_atomic_incr_u8(uint8_t * valuePtr, uint8_t delta)
240247
{
241248
uint8_t newValue;
@@ -266,6 +273,10 @@ uint32_t core_util_atomic_incr_u32(uint32_t * valuePtr, uint32_t delta)
266273
return newValue;
267274
}
268275

276+
void *core_util_atomic_incr_ptr(void **valuePtr, unsigned delta) {
277+
return core_util_atomic_incr((unsigned)valuePtr, delta);
278+
}
279+
269280

270281
uint8_t core_util_atomic_decr_u8(uint8_t * valuePtr, uint8_t delta)
271282
{
@@ -297,5 +308,9 @@ uint32_t core_util_atomic_decr_u32(uint32_t * valuePtr, uint32_t delta)
297308
return newValue;
298309
}
299310

311+
void *core_util_atomic_decr_ptr(void **valuePtr, unsigned delta) {
312+
return core_util_atomic_decr((unsigned)valuePtr, delta);
313+
}
314+
300315
#endif
301316

0 commit comments

Comments
 (0)