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