#pragma once #include #include #include #include #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus /* Some C++ compilers don't support _Atomic as a qualifier and instead define * _Atomic as a macro in stdatomic.h, in terms of std::atomic. */ #define rt_atomic(t) _Atomic(t) #else #define rt_atomic(t) t _Atomic #endif #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) #include /* The compare_exchange built-ins in GCC don't clear the reservation if the * comparison fails after the ldrex, which can result in false-positive strex * results if the failed compare_exchange occurred in an exception that * pre-empted a different ldrex+strex pair. To avoid this, unconditionally * clear the reservation after a compare_exchange. On M-Profile, any exception * entry or exit automatically clears the reservation (section A3.4.4 "Context * switch support" in the Armv7-M Architecture Reference Manual), so this is * only needed on A/R-Profile. */ #if RT_ARM_PROFILE_AR #define rt_atomic_compare_exchange_weak(p, e, v, mos, mof) \ ({ \ bool result = \ atomic_compare_exchange_weak_explicit(p, e, v, mos, mof); \ __asm__("clrex" ::: "memory"); \ result; \ }) #define rt_atomic_compare_exchange(p, e, v, mos, mof) \ ({ \ bool result = \ atomic_compare_exchange_strong_explicit(p, e, v, mos, mof); \ __asm__("clrex" ::: "memory"); \ result; \ }) #endif /* Work around a bug in GCC versions < 14 where atomic_flag operations silently * don't generate atomic code on Armv6-M rather than failing to link. The * equivalent atomic_exchange operations on an atomic_bool work. * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107567 */ #if (__GNUC__ < 14) && RT_ARM_V6M #define RT_ATOMIC_USE_BOOL_AS_FLAG 1 #endif // (__GNUC__ < 14) && RT_ARM_V6M #endif // defined(__arm__) && defined(__GNUC__) && !defined(__clang__) #ifndef RT_ATOMIC_USE_BOOL_AS_FLAG #define RT_ATOMIC_USE_BOOL_AS_FLAG 0 #endif typedef rt_atomic(bool) rt_atomic_bool; typedef rt_atomic(unsigned char) rt_atomic_uchar; typedef rt_atomic(int) rt_atomic_int; typedef rt_atomic(unsigned int) rt_atomic_uint; typedef rt_atomic(long) rt_atomic_long; typedef rt_atomic(unsigned long) rt_atomic_ulong; typedef rt_atomic(size_t) rt_atomic_size_t; typedef rt_atomic(uintptr_t) rt_atomic_uintptr_t; typedef rt_atomic(uint32_t) rt_atomic_uint32_t; #define rt_atomic_load atomic_load_explicit #define rt_atomic_store atomic_store_explicit #define rt_atomic_fetch_add atomic_fetch_add_explicit #define rt_atomic_fetch_sub atomic_fetch_sub_explicit #define rt_atomic_fetch_and atomic_fetch_and_explicit #define rt_atomic_fetch_or atomic_fetch_or_explicit #define rt_atomic_exchange atomic_exchange_explicit #ifndef rt_atomic_compare_exchange_weak #define rt_atomic_compare_exchange_weak atomic_compare_exchange_weak_explicit #endif #ifndef rt_atomic_compare_exchange #define rt_atomic_compare_exchange atomic_compare_exchange_strong_explicit #endif #define RT_ATOMIC_RELAXED memory_order_relaxed #define RT_ATOMIC_CONSUME memory_order_consume #define RT_ATOMIC_ACQUIRE memory_order_acquire #define RT_ATOMIC_RELEASE memory_order_release #define RT_ATOMIC_ACQ_REL memory_order_acq_rel #define RT_ATOMIC_SEQ_CST memory_order_seq_cst #if RT_ATOMIC_USE_BOOL_AS_FLAG typedef rt_atomic_bool rt_atomic_flag; #define RT_ATOMIC_FLAG_INIT false #define rt_atomic_flag_test_and_set(f, mo) atomic_exchange_explicit(f, true, mo) #define rt_atomic_flag_clear(f, mo) atomic_store_explicit(f, false, mo) #else // !RT_ATOMIC_USE_BOOL_AS_FLAG typedef atomic_flag rt_atomic_flag; #if defined(__clang__) && defined(__cplusplus) /* clang's stdatomic.h defines atomic_flag as a struct containing an * atomic_bool, but then doesn't provide an ATOMIC_FLAG_INIT that works in C * and C++. */ #define RT_ATOMIC_FLAG_INIT {false} #else // !defined(__clang__) || !defined(__cplusplus) #define RT_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT #endif // defined(__clang__) && defined(__cplusplus) #define rt_atomic_flag_test_and_set atomic_flag_test_and_set_explicit #define rt_atomic_flag_clear atomic_flag_clear_explicit #endif // RT_ATOMIC_USE_BOOL_AS_FLAG #ifdef __cplusplus } #endif