Add atomic load and store functions, and add barriers to the existing atomic
functions.
File currently has no explicit barriers - we don't support SMP, so don't
need CPU barriers.
But we do need to worry about compiler barriers - particularly if link time
optimisation is activated so that the compiler can see inside these
functions. The assembler or intrinsics that access PRIMASK for
enter/exit critical act as barriers, but LDREX, STREX and simple
volatile pointer loads and stores do not.
Critical section count/state variables are synchronised by IRQ disabling and
critical section calls themselves, so do not need to be volatile.
This eliminates a couple of unnecessary reads of the counter variable.
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.
The atomic functions preserve volatile semantics - they only perform the
accesses specified. Add the volatile qualifier to the value pointer to
reflect this. This does not change existing caller code - it's
equivalent to adding a const qualifier to indicate we don't write to
a pointer - it means people can pass us qualified pointers without
casts, letting the compile check const- or volatile-correctness.
This is consistent with C11 <stdatomic.h>, which volatile-qualifies its
equivalent functions.
Note that this useage of volatile has nothing to do with the atomicity -
objects accessed via the atomic functions do not need to be volatile.
But it does permit these calls to be used on objects which have been
declared volatile.
The volatile qualifier on the __LDREX/__STREX prototypes only means that
it's safe to use them on volatile objects. Doesn't mean you actually
have to pass them volatile pointers.
Adding the volatile is a bit like doing strlen((const char *) ptr)
because you've got a non-const pointer.
Fixes#5555 bug.
In case there is not yet defined __EXCLUSIVE_ACCESS, neither MBED_EXCLUSIVE_ACCESS that
we are introducing, use architecture macros to find out if MBED_EXCLUSIVE_ACCESS can be
enabled.
Call underlying HAL implementation to enter critical section/disable interrupts
before incrementing the global critical section counter.
Modify HAL implementations to track first entrances to the critical section and
only update the saved state on first enter.
- Define header functions for Critical Section HAL API
- hal_critical_section_enter()
- hal_critical_section_exit()
- Add weak default implementation for HAL API. The default implementation
matches the previous behaviour stored in mbed_critical:
- The first call to enter a critical section stores the state of interrupts
before disabling and each successive call re-disables interrupts.
- The last call (non-nested) will restore the IRQ state that was set on the
enter to the critical section. Nested calls are ignored.
- Add function 'core_util_in_critical_section' to User facing API to determine
if the program is currently in a critical section, instead of depending on
'core_util_interrupts_enabled'.
The LDREX/STREX implementations of the compare-and-swap functions were
weak (they could spuriously fail when the value was expected), whereas
the critial section implementation was strong, and the documentation has
no suggestion that there might be spurious failures.
Rationalise by adding a retry loop for STREX failure, so that it only
returns false when the value is not expected.
Fixes https://github.com/ARMmbed/mbed-os/issues/5556
A define which expands to more defines is not portable across all
compilers and GCC warns about this. Restructure this so the behavior
is defined. This fixes the GCC warning:
"this use of "defined" may not be portable"