mirror of https://github.com/ARMmbed/mbed-os.git
Add atomic_flag utility
An atomic flag primitive is sometimes wanted, and it is cumbersome to create it from the compare-and-swap operation - cumbersome enough that people often don't bother. Put in a core_util_atomic_flag that follows the C11/C++11 atomic_flag API, such that it could be mapped to it with #define later.pull/8328/head
parent
0b27736536
commit
c32984c3a8
|
@ -100,6 +100,11 @@ void core_util_critical_section_exit(void)
|
|||
}
|
||||
}
|
||||
|
||||
void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr)
|
||||
{
|
||||
flagPtr->_flag = false;
|
||||
}
|
||||
|
||||
#if MBED_EXCLUSIVE_ACCESS
|
||||
|
||||
/* Supress __ldrex and __strex deprecated warnings - "#3731-D: intrinsic is deprecated" */
|
||||
|
@ -107,6 +112,15 @@ void core_util_critical_section_exit(void)
|
|||
#pragma diag_suppress 3731
|
||||
#endif
|
||||
|
||||
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr)
|
||||
{
|
||||
uint8_t currentValue;
|
||||
do {
|
||||
currentValue = __LDREXB(&flagPtr->_flag);
|
||||
} while (__STREXB(true, &flagPtr->_flag));
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
|
||||
{
|
||||
do {
|
||||
|
@ -204,6 +218,15 @@ uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t delta)
|
|||
|
||||
#else
|
||||
|
||||
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
uint8_t currentValue = flagPtr->_flag;
|
||||
flagPtr->_flag = true;
|
||||
core_util_critical_section_exit();
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
|
||||
{
|
||||
bool success;
|
||||
|
|
|
@ -89,6 +89,43 @@ void core_util_critical_section_exit(void);
|
|||
*/
|
||||
bool core_util_in_critical_section(void);
|
||||
|
||||
/**
|
||||
* A lock-free, primitive atomic flag.
|
||||
*
|
||||
* Emulate C11's atomic_flag. The flag is initially in an indeterminate state
|
||||
* unless explicitly initialised with CORE_UTIL_ATOMIC_FLAG_INIT.
|
||||
*/
|
||||
typedef struct core_util_atomic_flag {
|
||||
uint8_t _flag;
|
||||
} core_util_atomic_flag;
|
||||
|
||||
/**
|
||||
* Initialiser for a core_util_atomic_flag.
|
||||
*
|
||||
* Example:
|
||||
* ~~~
|
||||
* core_util_atomic_flag in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
||||
* ~~~
|
||||
*/
|
||||
#define CORE_UTIL_ATOMIC_FLAG_INIT { 0 }
|
||||
|
||||
/**
|
||||
* Atomic test and set.
|
||||
*
|
||||
* Atomically tests then sets the flag to true, returning the previous value.
|
||||
*
|
||||
* @param flagPtr Target flag being tested and set.
|
||||
* @return The previous value.
|
||||
*/
|
||||
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr);
|
||||
|
||||
/**
|
||||
* Atomic clear.
|
||||
*
|
||||
* @param flagPtr Target flag being cleared.
|
||||
*/
|
||||
void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr);
|
||||
|
||||
/**
|
||||
* Atomic compare and set. It compares the contents of a memory location to a
|
||||
* given value and, only if they are the same, modifies the contents of that
|
||||
|
|
Loading…
Reference in New Issue