#ifndef VLIBC_STDATOMIC_H #define VLIBC_STDATOMIC_H /* * vlibc — . * * Atomics (C23). All operations defer to the GCC __atomic_* builtins, the * same idiom src/internal/atomic.h uses: on x86_64 every standard atomic * type here is lock-free in hardware, so the builtins inline to plain * instructions and never call into libatomic. The header is fully * self-contained (no system stdatomic.h) and compiles as C17-style code too, * since _Atomic remains a keyword. * * The atomic_* operations are function-like macros over the polymorphic * builtins (C23 allows any atomic operation to be implemented as a macro), * which keeps them type-generic across every atomic_* type without a * _Generic dispatch table. * * This header is ISO C core and is present in every profile. */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* Memory ordering. The enum values are the GCC __ATOMIC_* constants. */ typedef enum { memory_order_relaxed = __ATOMIC_RELAXED, memory_order_consume = __ATOMIC_CONSUME, memory_order_acquire = __ATOMIC_ACQUIRE, memory_order_release = __ATOMIC_RELEASE, memory_order_acq_rel = __ATOMIC_ACQ_REL, memory_order_seq_cst = __ATOMIC_SEQ_CST } memory_order; /* Lock-free guarantees for each type (0: never, 1: sometimes, 2: always). */ #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE #define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE #define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE #define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE #define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE #define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE /* Atomic scalar types. */ typedef _Atomic _Bool atomic_bool; typedef _Atomic char atomic_char; typedef _Atomic signed char atomic_schar; typedef _Atomic unsigned char atomic_uchar; typedef _Atomic short atomic_short; typedef _Atomic unsigned short atomic_ushort; typedef _Atomic int atomic_int; typedef _Atomic unsigned int atomic_uint; typedef _Atomic long atomic_long; typedef _Atomic unsigned long atomic_ulong; typedef _Atomic long long atomic_llong; typedef _Atomic unsigned long long atomic_ullong; typedef _Atomic __CHAR16_TYPE__ atomic_char16_t; typedef _Atomic __CHAR32_TYPE__ atomic_char32_t; typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t; typedef _Atomic int_least8_t atomic_int_least8_t; typedef _Atomic uint_least8_t atomic_uint_least8_t; typedef _Atomic int_least16_t atomic_int_least16_t; typedef _Atomic uint_least16_t atomic_uint_least16_t; typedef _Atomic int_least32_t atomic_int_least32_t; typedef _Atomic uint_least32_t atomic_uint_least32_t; typedef _Atomic int_least64_t atomic_int_least64_t; typedef _Atomic uint_least64_t atomic_uint_least64_t; typedef _Atomic int_fast8_t atomic_int_fast8_t; typedef _Atomic uint_fast8_t atomic_uint_fast8_t; typedef _Atomic int_fast16_t atomic_int_fast16_t; typedef _Atomic uint_fast16_t atomic_uint_fast16_t; typedef _Atomic int_fast32_t atomic_int_fast32_t; typedef _Atomic uint_fast32_t atomic_uint_fast32_t; typedef _Atomic int_fast64_t atomic_int_fast64_t; typedef _Atomic uint_fast64_t atomic_uint_fast64_t; typedef _Atomic intptr_t atomic_intptr_t; typedef _Atomic uintptr_t atomic_uintptr_t; typedef _Atomic size_t atomic_size_t; typedef _Atomic ptrdiff_t atomic_ptrdiff_t; typedef _Atomic intmax_t atomic_intmax_t; typedef _Atomic uintmax_t atomic_uintmax_t; /* The only type the standard guarantees to be lock-free. */ typedef _Atomic unsigned int atomic_flag; /* Initializer for an atomic_flag object. */ #define ATOMIC_FLAG_INIT 0 /* * The operations below are macros because the __atomic_* builtins are * polymorphic: they accept any 1/2/4/8-byte scalar or pointer type, so a * single macro serves every atomic_* type. The (object) argument is the * address of the atomic object, matching the standard's function signatures. */ /* Initialize the atomic object to value (a relaxed store). */ #define atomic_init(object, value) __atomic_store_n((object), (value), __ATOMIC_RELAXED) /* Load the current value. */ #define atomic_load(object) __atomic_load_n((object), __ATOMIC_SEQ_CST) #define atomic_load_explicit(object, order) __atomic_load_n((object), (order)) /* Store value. */ #define atomic_store(object, value) __atomic_store_n((object), (value), __ATOMIC_SEQ_CST) #define atomic_store_explicit(object, value, order) __atomic_store_n((object), (value), (order)) /* Exchange object's value with desired; returns the previous value. */ #define atomic_exchange(object, desired) __atomic_exchange_n((object), (desired), __ATOMIC_SEQ_CST) #define atomic_exchange_explicit(object, desired, order) \ __atomic_exchange_n((object), (desired), (order)) /* * Compare-and-swap: store desired into object iff *object equals *expected. * On failure *expected is updated with the actual value and the macro * returns false. The first memorder governs the read-modify-write on * success, the second the load on failure. */ #define atomic_compare_exchange_strong(object, expected, desired) \ __atomic_compare_exchange_n((object), (expected), (desired), 0, __ATOMIC_SEQ_CST, \ __ATOMIC_SEQ_CST) #define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ __atomic_compare_exchange_n((object), (expected), (desired), 0, (success), (failure)) #define atomic_compare_exchange_weak(object, expected, desired) \ __atomic_compare_exchange_n((object), (expected), (desired), 1, __ATOMIC_SEQ_CST, \ __ATOMIC_SEQ_CST) #define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ __atomic_compare_exchange_n((object), (expected), (desired), 1, (success), (failure)) /* Fetch and add; returns the previous value. */ #define atomic_fetch_add(object, operand) __atomic_fetch_add((object), (operand), __ATOMIC_SEQ_CST) #define atomic_fetch_add_explicit(object, operand, order) \ __atomic_fetch_add((object), (operand), (order)) /* Fetch and subtract; returns the previous value. */ #define atomic_fetch_sub(object, operand) __atomic_fetch_sub((object), (operand), __ATOMIC_SEQ_CST) #define atomic_fetch_sub_explicit(object, operand, order) \ __atomic_fetch_sub((object), (operand), (order)) /* Fetch and bitwise-or; returns the previous value. */ #define atomic_fetch_or(object, operand) __atomic_fetch_or((object), (operand), __ATOMIC_SEQ_CST) #define atomic_fetch_or_explicit(object, operand, order) \ __atomic_fetch_or((object), (operand), (order)) /* Fetch and bitwise-xor; returns the previous value. */ #define atomic_fetch_xor(object, operand) __atomic_fetch_xor((object), (operand), __ATOMIC_SEQ_CST) #define atomic_fetch_xor_explicit(object, operand, order) \ __atomic_fetch_xor((object), (operand), (order)) /* Fetch and bitwise-and; returns the previous value. */ #define atomic_fetch_and(object, operand) __atomic_fetch_and((object), (operand), __ATOMIC_SEQ_CST) #define atomic_fetch_and_explicit(object, operand, order) \ __atomic_fetch_and((object), (operand), (order)) /* atomic_flag: test-and-set (returns the previous flag value). */ #define atomic_flag_test_and_set(object) __atomic_test_and_set((object), __ATOMIC_SEQ_CST) #define atomic_flag_test_and_set_explicit(object, order) __atomic_test_and_set((object), (order)) /* atomic_flag: clear. */ #define atomic_flag_clear(object) __atomic_clear((object), __ATOMIC_SEQ_CST) #define atomic_flag_clear_explicit(object, order) __atomic_clear((object), (order)) /* Non-zero iff *object is always lock-free. */ #define atomic_is_lock_free(object) __atomic_is_lock_free(sizeof *(object), (object)) /* Fences. */ #define atomic_thread_fence(order) __atomic_thread_fence((order)) #define atomic_signal_fence(order) __atomic_signal_fence((order)) /* Carry a dependency through a load without a synchronization edge. */ #define kill_dependency(y) (y) #ifdef __cplusplus } #endif #endif /* VLIBC_STDATOMIC_H */