Skip to content

Commit c32984c

Browse files
committed
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.
1 parent 0b27736 commit c32984c

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

platform/mbed_critical.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,27 @@ void core_util_critical_section_exit(void)
100100
}
101101
}
102102

103+
void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr)
104+
{
105+
flagPtr->_flag = false;
106+
}
107+
103108
#if MBED_EXCLUSIVE_ACCESS
104109

105110
/* Supress __ldrex and __strex deprecated warnings - "#3731-D: intrinsic is deprecated" */
106111
#if defined (__CC_ARM)
107112
#pragma diag_suppress 3731
108113
#endif
109114

115+
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr)
116+
{
117+
uint8_t currentValue;
118+
do {
119+
currentValue = __LDREXB(&flagPtr->_flag);
120+
} while (__STREXB(true, &flagPtr->_flag));
121+
return currentValue;
122+
}
123+
110124
bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
111125
{
112126
do {
@@ -204,6 +218,15 @@ uint32_t core_util_atomic_decr_u32(volatile uint32_t *valuePtr, uint32_t delta)
204218

205219
#else
206220

221+
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr)
222+
{
223+
core_util_critical_section_enter();
224+
uint8_t currentValue = flagPtr->_flag;
225+
flagPtr->_flag = true;
226+
core_util_critical_section_exit();
227+
return currentValue;
228+
}
229+
207230
bool core_util_atomic_cas_u8(volatile uint8_t *ptr, uint8_t *expectedCurrentValue, uint8_t desiredValue)
208231
{
209232
bool success;

platform/mbed_critical.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,43 @@ void core_util_critical_section_exit(void);
8989
*/
9090
bool core_util_in_critical_section(void);
9191

92+
/**
93+
* A lock-free, primitive atomic flag.
94+
*
95+
* Emulate C11's atomic_flag. The flag is initially in an indeterminate state
96+
* unless explicitly initialised with CORE_UTIL_ATOMIC_FLAG_INIT.
97+
*/
98+
typedef struct core_util_atomic_flag {
99+
uint8_t _flag;
100+
} core_util_atomic_flag;
101+
102+
/**
103+
* Initialiser for a core_util_atomic_flag.
104+
*
105+
* Example:
106+
* ~~~
107+
* core_util_atomic_flag in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
108+
* ~~~
109+
*/
110+
#define CORE_UTIL_ATOMIC_FLAG_INIT { 0 }
111+
112+
/**
113+
* Atomic test and set.
114+
*
115+
* Atomically tests then sets the flag to true, returning the previous value.
116+
*
117+
* @param flagPtr Target flag being tested and set.
118+
* @return The previous value.
119+
*/
120+
bool core_util_atomic_flag_test_and_set(volatile core_util_atomic_flag *flagPtr);
121+
122+
/**
123+
* Atomic clear.
124+
*
125+
* @param flagPtr Target flag being cleared.
126+
*/
127+
void core_util_atomic_flag_clear(volatile core_util_atomic_flag *flagPtr);
128+
92129
/**
93130
* Atomic compare and set. It compares the contents of a memory location to a
94131
* given value and, only if they are the same, modifies the contents of that

0 commit comments

Comments
 (0)