diff --git a/include/vlc_atomic.h b/include/vlc_atomic.h index 67aff9a05f..11b2711e76 100644 --- a/include/vlc_atomic.h +++ b/include/vlc_atomic.h @@ -26,6 +26,165 @@ * Atomic operations do not require locking, but they are not very powerful. */ +# if !defined (__cplusplus) && (__STDC_VERSION__ >= 201112L) \ + && !defined (__STDC_NO_ATOMICS__) +# include + +# else /* if (???) */ + +# define ATOMIC_FLAG_INIT false + +# define ATOMIC_VAR_INIT(value) (value) + +# define atomic_init(obj, value) \ + do { *(obj) = (value); } while(0) + +# define kill_dependency(y) \ + ((void)0) + +# define atomic_thread_fence(order) \ + __sync_synchronize() + +# define atomic_signal_fence(order) \ + ((void)0) + +# define atomic_is_lock_free(obj) \ + false + +/* In principles, __sync_*() only supports int, long and long long and their + * unsigned equivalents, i.e. 4-bytes and 8-bytes types, although GCC also + * supports 1 and 2-bytes types. Some non-x86 architectures do not support + * 8-byte atomic types (or not efficiently). So lets stick to (u)intptr_t. */ +typedef intptr_t atomic_flag; +typedef intptr_t atomic_bool; +typedef intptr_t atomic_char; +typedef intptr_t atomic_schar; +typedef uintptr_t atomic_uchar; +typedef intptr_t atomic_short; +typedef uintptr_t atomic_ushort; +typedef intptr_t atomic_int; +typedef uintptr_t atomic_uint; +//typedef signed long atomic_long; +//typedef unsigned long atomic_ulong; +//typedef signed long long atomic_llong; +//typedef unsigned long long atomic_ullong; +/* ... */ +typedef intptr_t atomic_intptr_t; +typedef uintptr_t atomic_uintptr_t; +typedef uintptr_t atomic_size_t; +typedef intptr_t atomic_ptrdiff_t; +//typedef intmax_t atomic_intmax_t; +//typedef uintmax_t atomic_uintmax_t; + +# define atomic_store(object,desired) \ + do { \ + *(object) = (desired); \ + __sync_synchronize(); \ + } while (0) + +# define atomic_store_explicit(object,desired,order) \ + atomic_store(object,desired) + +# define atomic_load(object) \ + (__sync_synchronize(), *(object)) + +# define atomic_load_explicit(object,order) \ + atomic_load(object) + +static inline +intptr_t vlc_atomic_exchange(volatile void *object, intptr_t desired) +{ + volatile intptr_t *ptr = (volatile intptr_t *)object; + intptr_t old; + /* NOTE: while __sync_lock_test_and_set() is an atomic exchange, its memory + * order is too weak (acquire instead of sequentially consistent). + * Because of that, for lack of both C11 _Generic() and GNU C compound + * statements, atomic exchange needs a helper function. + * Thus all atomic types must have the same size. */ + do + old = atomic_load(ptr); + while (!__sync_bool_compare_and_swap(ptr, old, desired)); + + return old; +} + +# define atomic_exchange(object,desired) \ + vlc_atomic_exchange(object,desired) + +# define atomic_exchange_explicit(object,desired,order) \ + atomic_exchange(object,desired) + +static inline +bool vlc_atomic_compare_exchange(volatile void *object, void *expected, + intptr_t desired) +{ + volatile intptr_t *ptr = (volatile intptr_t *)object; + intptr_t old = *(intptr_t *)expected; + intptr_t val = __sync_val_compare_and_swap(ptr, old, desired); + if (old != val) + { + *(intptr_t *)expected = val; + return false; + } + return true; +} + +# define atomic_compare_exchange_strong(object,expected,desired) \ + vlc_atomic_compare_exchange(object, expected, desired) + +# define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \ + atomic_compare_exchange_strong(object, expected, desired) + +# define atomic_compare_exchange_weak(object,expected,desired) \ + vlc_atomic_compare_exchange(object, expected, desired) + +# define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \ + atomic_compare_exchange_weak(object, expected, desired) + +# define atomic_fetch_add(object,operand) \ + __sync_fetch_and_add(object, operand) + +# define atomic_fetch_add_explicit(object,operand,order) \ + atomic_fetch_add(object,operand) + +# define atomic_fetch_sub(object,operand) \ + __sync_fetch_and_sub(object, operand) + +# define atomic_fetch_sub_explicit(object,operand,order) \ + atomic_fetch_sub(object,operand) + +# define atomic_fetch_or(object,operand) \ + __sync_fetch_and_or(object, operand) + +# define atomic_fetch_or_explicit(object,operand,order) \ + atomic_fetch_or(object,operand) + +# define atomic_fetch_xor(object,operand) \ + __sync_fetch_and_sub(object, operand) + +# define atomic_fetch_xor_explicit(object,operand,order) \ + atomic_fetch_sub(object,operand) + +# define atomic_fetch_and(object,operand) \ + __sync_fetch_and_and(object, operand) + +# define atomic_fetch_and_explicit(object,operand,order) \ + atomic_fetch_and(object,operand) + +# define atomic_flag_test_and_set(object) \ + atomic_exchange(object, true) + +# define atomic_flag_test_and_set_explicit(object,order) \ + atomic_flag_test_and_set(object) + +# define atomic_flag_clear(object) \ + atomic_store(object, false) + +# define atomic_flag_clear_explicit(object,order) \ + atomic_flag_clear(object) + +# endif + /** Static initializer for \ref vlc_atomic_t */ # define VLC_ATOMIC_INIT(val) { (val) }