Files

187 lines
8.5 KiB
C

#ifndef VLIBC_STDATOMIC_H
#define VLIBC_STDATOMIC_H
/*
* vlibc — <stdatomic.h>.
*
* 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 <vlibc/features.h>
#include <stddef.h>
#include <stdint.h>
#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 */