X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=include%2Fvlc_atomic.h;h=5905a73a1fcc5dcc4067c6fd629feb02c44fdea9;hb=4ca46b853b5de015f57621bd6c823abba1b4fa08;hp=051e1ae1e6ecc3e9b9a3b8dbfdb096a73d1c600d;hpb=5035a0281c0b1d82adda3b67cc4633de04616328;p=vlc diff --git a/include/vlc_atomic.h b/include/vlc_atomic.h index 051e1ae1e6..5905a73a1f 100644 --- a/include/vlc_atomic.h +++ b/include/vlc_atomic.h @@ -28,9 +28,11 @@ # if !defined (__cplusplus) && (__STDC_VERSION__ >= 201112L) \ && !defined (__STDC_NO_ATOMICS__) + +/*** Native C11 atomics ***/ # include -# else /* if (???) */ +# else # define ATOMIC_FLAG_INIT false @@ -54,45 +56,49 @@ /* 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 intptr_t atomic_long; -typedef uintptr_t atomic_ulong; -//atomic_llong -//atomic_ullong -typedef uintptr_t atomic_char16_t; -typedef uintptr_t atomic_char32_t; -typedef uintptr_t atomic_wchar_t; -typedef intptr_t atomic_int_least8_t; -typedef uintptr_t atomic_uint_least8_t; -typedef intptr_t atomic_int_least16_t; -typedef uintptr_t atomic_uint_least16_t; -typedef intptr_t atomic_int_least32_t; -typedef uintptr_t atomic_uint_least32_t; -//atomic_int_least64_t -//atomic_uint_least64_t -typedef intptr_t atomic_int_fast8_t; -typedef uintptr_t atomic_uint_fast8_t; -typedef intptr_t atomic_int_fast16_t; -typedef uintptr_t atomic_uint_fast16_t; -typedef intptr_t atomic_int_fast32_t; -typedef uintptr_t atomic_uint_fast32_t; -//atomic_int_fast64_t -//atomic_uint_fast64_t -typedef intptr_t atomic_intptr_t; -typedef uintptr_t atomic_uintptr_t; -typedef uintptr_t atomic_size_t; -typedef intptr_t atomic_ptrdiff_t; -//atomic_intmax_t -//atomic_uintmax_t + * 8-byte atomic types (or not efficiently). */ +typedef bool atomic_flag; +typedef bool atomic_bool; +typedef char atomic_char; +typedef signed char atomic_schar; +typedef unsigned char atomic_uchar; +typedef short atomic_short; +typedef unsigned short atomic_ushort; +typedef int atomic_int; +typedef unsigned int atomic_uint; +typedef long atomic_long; +typedef unsigned long atomic_ulong; +typedef long long atomic_llong; +typedef unsigned long long atomic_ullong; +//typedef char16_t atomic_char16_t; +//typedef char32_t atomic_char32_t; +typedef wchar_t atomic_wchar_t; +typedef int_least8_t atomic_int_least8_t; +typedef uint_least8_t atomic_uint_least8_t; +typedef int_least16_t atomic_int_least16_t; +typedef uint_least16_t atomic_uint_least16_t; +typedef int_least32_t atomic_int_least32_t; +typedef uint_least32_t atomic_uint_least32_t; +typedef int_least64_t atomic_int_least64_t; +typedef uint_least64_t atomic_uint_least64_t; +typedef int_fast8_t atomic_int_fast8_t; +typedef uint_fast8_t atomic_uint_fast8_t; +typedef int_fast16_t atomic_int_fast16_t; +typedef uint_fast16_t atomic_uint_fast16_t; +typedef int_fast32_t atomic_int_fast32_t; +typedef uint_fast32_t atomic_uint_fast32_t; +typedef int_fast64_t atomic_int_fast64_t; +typedef uint_fast64_t atomic_uint_fast64_t; +typedef intptr_t atomic_intptr_t; +typedef uintptr_t atomic_uintptr_t; +typedef size_t atomic_size_t; +typedef ptrdiff_t atomic_ptrdiff_t; +typedef intmax_t atomic_intmax_t; +typedef uintmax_t atomic_uintmax_t; + +# if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || (defined (__clang__) && (defined (__x86_64__) || defined (__i386__))) + +/*** Intel/GCC atomics ***/ # define atomic_store(object,desired) \ do { \ @@ -109,52 +115,35 @@ typedef intptr_t atomic_ptrdiff_t; # 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) +({ \ + typeof (object) _obj = (object); \ + typeof (*object) _old; \ + do \ + _old = atomic_load(_obj); \ + while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \ + _old; \ +}) # 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(object,expected,desired) \ +({ \ + typeof (object) _exp = (expected); \ + typeof (*object) _old = *_exp; \ + *_exp = __sync_val_compare_and_swap((object), _old, (desired)); \ + *_exp == _old; \ +}) # define atomic_compare_exchange_strong(object,expected,desired) \ - vlc_atomic_compare_exchange(object, expected, desired) + 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) + atomic_compare_exchange(object, expected, desired) # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \ atomic_compare_exchange_weak(object, expected, desired) @@ -201,6 +190,121 @@ bool vlc_atomic_compare_exchange(volatile void *object, void *expected, # define atomic_flag_clear_explicit(object,order) \ atomic_flag_clear(object) +# elif defined (__GNUC__) + +/*** No atomics ***/ + +# define atomic_store(object,desired) \ + do { \ + typeof (object) _obj = (object); \ + typeof (*object) _des = (desired); \ + vlc_global_lock(VLC_ATOMIC_MUTEX); \ + *_obj = _des; \ + vlc_global_unlock(VLC_ATOMIC_MUTEX); \ + } while (0) +# define atomic_store_explicit(object,desired,order) \ + atomic_store(object,desired) + +# define atomic_load(object) \ +({ \ + typeof (object) _obj = (object); \ + typeof (*object) _old; \ + vlc_global_lock(VLC_ATOMIC_MUTEX); \ + _old = *_obj; \ + vlc_global_unlock(VLC_ATOMIC_MUTEX); \ + _old; \ +}) +# define atomic_load_explicit(object,order) \ + atomic_load(object) + +# define atomic_exchange(object,desired) \ +({ \ + typeof (object) _obj = (object); \ + typeof (*object) _des = (desired); \ + typeof (*object) _old; \ + vlc_global_lock(VLC_ATOMIC_MUTEX); \ + _old = *_obj; \ + *_obj = _des; \ + vlc_global_unlock(VLC_ATOMIC_MUTEX); \ + _old; \ +}) +# define atomic_exchange_explicit(object,desired,order) \ + atomic_exchange(object,desired) + +# define atomic_compare_exchange_strong(object,expected,desired) \ +({ \ + typeof (object) _obj = (object); \ + typeof (object) _exp = (expected); \ + typeof (*object) _des = (desired); \ + bool ret; \ + vlc_global_lock(VLC_ATOMIC_MUTEX); \ + ret = *_obj == *_exp; \ + if (ret) \ + *_obj = _des; \ + else \ + *_exp = *_obj; \ + vlc_global_unlock(VLC_ATOMIC_MUTEX); \ + ret; \ +}) +# 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) \ + atomic_compare_exchange_strong(object, expected, desired) +# define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \ + atomic_compare_exchange_weak(object, expected, desired) + +# define atomic_fetch_OP(object,desired,op) \ +({ \ + typeof (object) _obj = (object); \ + typeof (*object) _des = (desired); \ + typeof (*object) _old; \ + vlc_global_lock(VLC_ATOMIC_MUTEX); \ + _old = *_obj; \ + *_obj = (*_obj) op (_des); \ + vlc_global_unlock(VLC_ATOMIC_MUTEX); \ + _old; \ +}) + +# define atomic_fetch_add(object,operand) \ + atomic_fetch_OP(object,operand,+) +# define atomic_fetch_add_explicit(object,operand,order) \ + atomic_fetch_add(object,operand) + +# define atomic_fetch_sub(object,operand) \ + atomic_fetch_OP(object,operand,-) +# define atomic_fetch_sub_explicit(object,operand,order) \ + atomic_fetch_sub(object,operand) + +# define atomic_fetch_or(object,operand) \ + atomic_fetch_OP(object,operand,|) +# define atomic_fetch_or_explicit(object,operand,order) \ + atomic_fetch_or(object,operand) + +# define atomic_fetch_xor(object,operand) \ + atomic_fetch_OP(object,operand,^) +# define atomic_fetch_xor_explicit(object,operand,order) \ + atomic_fetch_sub(object,operand) + +# define atomic_fetch_and(object,operand) \ + atomic_fetch_OP(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) + +# else +# error FIXME: implement atomic operations for this compiler. +# endif # endif /** @@ -215,7 +319,7 @@ typedef union # define VLC_ATOMIC_INIT(val) { (val) } /* All functions return the atom value _after_ the operation. */ -static inline uintptr_t vlc_atomic_get(const vlc_atomic_t *atom) +static inline uintptr_t vlc_atomic_get(vlc_atomic_t *atom) { return atomic_load(&atom->u); } @@ -254,24 +358,26 @@ static inline uintptr_t vlc_atomic_swap(vlc_atomic_t *atom, uintptr_t v) static inline uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *atom, uintptr_t u, uintptr_t v) { - return atomic_compare_exchange_strong(&atom->u, &u, v); + atomic_compare_exchange_strong(&atom->u, &u, v); + return u; } +typedef atomic_uint_least32_t vlc_atomic_float; + /** Helper to retrieve a single precision from an atom. */ -static inline float vlc_atomic_getf(const vlc_atomic_t *atom) +static inline float vlc_atomic_loadf(vlc_atomic_float *atom) { - union { float f; uintptr_t i; } u; - u.i = vlc_atomic_get(atom); + union { float f; uint32_t i; } u; + u.i = atomic_load(atom); return u.f; } /** Helper to store a single precision into an atom. */ -static inline float vlc_atomic_setf(vlc_atomic_t *atom, float f) +static inline void vlc_atomic_storef(vlc_atomic_float *atom, float f) { - union { float f; uintptr_t i; } u; + union { float f; uint32_t i; } u; u.f = f; - vlc_atomic_set(atom, u.i); - return f; + atomic_store(atom, u.i); } #endif