This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d939b3edcbb2c715cc3d524167826281eccd34de Author: Kacper Michajłow <[email protected]> AuthorDate: Thu Aug 20 10:27:07 2026 +0200 Commit: Kacper Michajłow <[email protected]> CommitDate: Mon Sep 14 04:35:12 2026 +0200 compat/atomics/dummy: rewrite and fix stdatomic.h This header shared the win32 emulation's design and therefore its bugs. Bring the dummy version in sync and fix all issues. Signed-off-by: Kacper Michajłow <[email protected]> --- compat/atomics/dummy/stdatomic.h | 442 +++++++++++++++++++++++++++++---------- 1 file changed, 332 insertions(+), 110 deletions(-) diff --git a/compat/atomics/dummy/stdatomic.h b/compat/atomics/dummy/stdatomic.h index 59d85f915d..41e0cb4c26 100644 --- a/compat/atomics/dummy/stdatomic.h +++ b/compat/atomics/dummy/stdatomic.h @@ -16,161 +16,383 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * based on vlc_atomic.h from VLC - * Copyright (C) 2010 Rémi Denis-Courmont - */ - #ifndef COMPAT_ATOMICS_DUMMY_STDATOMIC_H #define COMPAT_ATOMICS_DUMMY_STDATOMIC_H +#include <stdbool.h> +#include <stddef.h> #include <stdint.h> +#include <string.h> -#define ATOMIC_FLAG_INIT 0 +#include "libavutil/attributes.h" -#define ATOMIC_VAR_INIT(value) (value) +typedef enum { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst +} memory_order; -#define atomic_init(obj, value) \ -do { \ - *(obj) = (value); \ -} while(0) +#define FF_ATOMIC_LOCK_FREE 0 +#define FF_ATOMIC_ALIGN64 -#define kill_dependency(y) ((void)0) +#define ff_atomic_thread_fence(order) \ + ((void)(order)) -#define atomic_thread_fence(order) \ - ((void)0) +#define ff_atomic_signal_fence(order) \ + ((void)(order)) -#define atomic_signal_fence(order) \ - ((void)0) +/* + * The accesses go through memcpy instead of casted pointers to stay clear + * of strict-aliasing violations for types like long that have the size of + * an intN_t without being compatible with it. They are ordinary accesses, + * a volatile qualification of the object is not honoured. + */ +#define DUMMY_ATOMIC_FETCH(op, OP, name, type) \ +static av_always_inline type ff_atomic_##op##name(volatile void *object, \ + type operand, \ + memory_order order) \ +{ \ + type old = ff_atomic_load##name(object, order); \ + ff_atomic_store##name(object, old OP operand, order); \ + return old; \ +} -#define atomic_is_lock_free(obj) 0 +#define DUMMY_ATOMIC_OPS(name, type) \ +static av_always_inline type \ +ff_atomic_load_##name(const volatile void *object, memory_order order) \ +{ \ + (void)order; \ + type v; \ + memcpy(&v, (const void *)object, sizeof(v)); \ + return v; \ +} \ + \ +static av_always_inline void ff_atomic_store_##name(volatile void *object, \ + type desired, \ + memory_order order) \ +{ \ + (void)order; \ + memcpy((void *)object, &desired, sizeof(desired)); \ +} \ + \ +static av_always_inline type ff_atomic_exchange_##name(volatile void *object, \ + type desired, \ + memory_order order) \ +{ \ + type old = ff_atomic_load_##name(object, order); \ + ff_atomic_store_##name(object, desired, order); \ + return old; \ +} \ + \ +static av_always_inline bool ff_atomic_cas_##name(volatile void *object, \ + void *expected, \ + type desired, \ + memory_order order) \ +{ \ + type old = ff_atomic_load_##name(object, order); \ + if (old == ff_atomic_load_##name(expected, order)) { \ + ff_atomic_store_##name(object, desired, order); \ + return 1; \ + } \ + ff_atomic_store_##name(expected, old, order); \ + return 0; \ +} \ + \ +DUMMY_ATOMIC_FETCH(fetch_add, +, _##name, type) \ +DUMMY_ATOMIC_FETCH(fetch_sub, -, _##name, type) \ +DUMMY_ATOMIC_FETCH(fetch_or, |, _##name, type) \ +DUMMY_ATOMIC_FETCH(fetch_xor, ^, _##name, type) \ +DUMMY_ATOMIC_FETCH(fetch_and, &, _##name, type) -typedef intptr_t atomic_flag; -typedef intptr_t atomic_bool; -typedef intptr_t atomic_char; -typedef intptr_t atomic_schar; -typedef intptr_t atomic_uchar; -typedef intptr_t atomic_short; -typedef intptr_t atomic_ushort; -typedef intptr_t atomic_int; -typedef intptr_t atomic_uint; -typedef intptr_t atomic_long; -typedef intptr_t atomic_ulong; -typedef intptr_t atomic_llong; -typedef intptr_t atomic_ullong; -typedef intptr_t atomic_wchar_t; -typedef intptr_t atomic_int_least8_t; -typedef intptr_t atomic_uint_least8_t; -typedef intptr_t atomic_int_least16_t; -typedef intptr_t atomic_uint_least16_t; -typedef intptr_t atomic_int_least32_t; -typedef intptr_t atomic_uint_least32_t; -typedef intptr_t atomic_int_least64_t; -typedef intptr_t atomic_uint_least64_t; -typedef intptr_t atomic_int_fast8_t; -typedef intptr_t atomic_uint_fast8_t; -typedef intptr_t atomic_int_fast16_t; -typedef intptr_t atomic_uint_fast16_t; -typedef intptr_t atomic_int_fast32_t; -typedef intptr_t atomic_uint_fast32_t; -typedef intptr_t atomic_int_fast64_t; -typedef intptr_t atomic_uint_fast64_t; -typedef intptr_t atomic_intptr_t; -typedef intptr_t atomic_uintptr_t; -typedef intptr_t atomic_size_t; -typedef intptr_t atomic_ptrdiff_t; -typedef intptr_t atomic_intmax_t; -typedef intptr_t atomic_uintmax_t; +/* bool objects get their own set, for normalization */ +DUMMY_ATOMIC_OPS(bool, bool) +DUMMY_ATOMIC_OPS(8, uint8_t) +DUMMY_ATOMIC_OPS(16, uint16_t) +DUMMY_ATOMIC_OPS(32, uint32_t) +DUMMY_ATOMIC_OPS(64, uint64_t) -#define atomic_store(object, desired) \ -do { \ - *(object) = (desired); \ -} while (0) +#undef DUMMY_ATOMIC_OPS +#undef DUMMY_ATOMIC_FETCH -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) +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 FF_ATOMIC_ALIGN64 long long atomic_llong; +typedef FF_ATOMIC_ALIGN64 unsigned long long atomic_ullong; +typedef unsigned char atomic_char8_t; +typedef uint_least16_t atomic_char16_t; +typedef uint_least32_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 FF_ATOMIC_ALIGN64 int_least64_t atomic_int_least64_t; +typedef FF_ATOMIC_ALIGN64 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 FF_ATOMIC_ALIGN64 int_fast64_t atomic_int_fast64_t; +typedef FF_ATOMIC_ALIGN64 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 FF_ATOMIC_ALIGN64 intmax_t atomic_intmax_t; +typedef FF_ATOMIC_ALIGN64 uintmax_t atomic_uintmax_t; -#define atomic_load(object) \ - (*(object)) +/* + * Emulation of the _Atomic qualifier form for integer and pointer types of at + * most 8 bytes. This has very limited support, and will fail to compile when + * used with other types. Notably: + * - The specifier form "_Atomic(T)" is not supported, a macro cannot + * provide both forms. + * - Loads and exchanges of pointer objects return void *, not T *. Function + * pointer objects rely on the common extension converting them to and + * from void *. + * - Enumerated types are not supported, MSVC does not match them against + * their underlying type in _Generic. + * - atomic_fetch_add() and atomic_fetch_sub() stay restricted to integer + * types, on pointers they would have to scale by the pointee size. + * - Plain accesses to atomic objects, _Atomic qualified or the atomic_* + * typedefs, are ordinary accesses, unlike in C11 where they are + * implicitly atomic. Every access has to go through the atomic_* + * functions. + * - The 8-byte typedefs carry the alignment their accesses need to be + * atomic where the compiler does not provide it, on 32-bit x86, the + * qualifier form cannot. + */ +#define _Atomic -#define atomic_load_explicit(object, order) \ - atomic_load(object) +#define atomic_init(obj, value) ((void)(*(obj) = (value))) + +#define kill_dependency(y) (y) + +#define ATOMIC_BOOL_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_CHAR8_T_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE FF_ATOMIC_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE FF_ATOMIC_LOCK_FREE + +#define atomic_is_lock_free(obj) ((void)(obj), (bool)(FF_ATOMIC_LOCK_FREE == 2)) -static inline intptr_t atomic_exchange(intptr_t *object, intptr_t desired) +#define atomic_thread_fence(order) ff_atomic_thread_fence(order) +#define atomic_signal_fence(order) ff_atomic_signal_fence(order) + +#define FF_ATOMIC_SIZE(op, size) \ + _Generic((char (*)[size])0, \ + char (*)[1]: ff_atomic_##op##_8, \ + char (*)[2]: ff_atomic_##op##_16, \ + char (*)[4]: ff_atomic_##op##_32, \ + char (*)[8]: ff_atomic_##op##_64) + +static av_always_inline uintptr_t +ff_atomic_load_ptr(const volatile void *object, memory_order order) { - intptr_t ret = *object; - *object = desired; - return ret; + return FF_ATOMIC_SIZE(load, sizeof(void *))(object, order); } -#define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) +static av_always_inline void ff_atomic_store_ptr(volatile void *object, + const volatile void *desired, + memory_order order) +{ + FF_ATOMIC_SIZE(store, sizeof(void *))(object, (uintptr_t)desired, order); +} -static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, - intptr_t desired) +static av_always_inline uintptr_t +ff_atomic_exchange_ptr(volatile void *object, const volatile void *desired, + memory_order order) { - int ret; - if (*object == *expected) { - *object = desired; - ret = 1; - } else { - *expected = *object; - ret = 0; - } - return ret; + return FF_ATOMIC_SIZE(exchange, sizeof(void *))(object, (uintptr_t)desired, + order); } -#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) +static av_always_inline bool ff_atomic_cas_ptr(volatile void *object, + void *expected, + const volatile void *desired, + memory_order order) +{ + return FF_ATOMIC_SIZE(cas, sizeof(void *))(object, expected, + (uintptr_t)desired, order); +} -#define atomic_compare_exchange_weak(object, expected, desired) \ - atomic_compare_exchange_strong(object, expected, desired) +void ff_atomic_unsupported(void); + +/* the pointer helpers, for the objects of the pointer size only */ +#define FF_ATOMIC_PTR(op, object) \ + _Generic((char (*)[sizeof(*(object))])0, \ + char (*)[sizeof(void *)]: ff_atomic_##op##_ptr, \ + default: ff_atomic_unsupported) + +/* MSVC before 19.44 does not treat char as its own type in _Generic. It matches + * either signed char or unsigned char, depending on /J, and rejects a separate + * char association as a duplicate. + * <https://developercommunity.visualstudio.com/t/_Generic-char-signed-char-unsigned-cha/1228885> */ +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1944 +#define FF_ATOMIC_CHAR(x) +#else +#define FF_ATOMIC_CHAR(x) char: x, +#endif + +#define FF_ATOMIC_INT(op, object) \ + FF_ATOMIC_CHAR(FF_ATOMIC_SIZE(op, sizeof(*(object)))) \ + signed char: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + unsigned char: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + short: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + unsigned short: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + int: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + unsigned int: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + long: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + unsigned long: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + long long: FF_ATOMIC_SIZE(op, sizeof(*(object))), \ + unsigned long long: FF_ATOMIC_SIZE(op, sizeof(*(object))) + +/* bool objects have their own set for the normalization */ +#define FF_ATOMIC_FN(op, object) \ + _Generic(*(object), \ + bool: ff_atomic_##op##_bool, \ + FF_ATOMIC_INT(op, object), \ + default: FF_ATOMIC_PTR(op, object)) -#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) +/* the fetch operations are for the integer objects only, bool is excluded + * and on pointers they would have to scale by the pointee size */ +#define FF_ATOMIC_FETCH_FN(op, object) \ + _Generic(*(object), FF_ATOMIC_INT(op, object)) -#define FETCH_MODIFY(opname, op) \ -static inline intptr_t atomic_fetch_ ## opname(intptr_t *object, intptr_t operand) \ -{ \ - intptr_t ret; \ - ret = *object; \ - *object = *object op operand; \ - return ret; \ +/* the width or uintptr_t result back to the non-atomic type C */ +#define ff_atomic_c(object, x) \ + _Generic(*(object), \ + bool: (bool)(x), \ + FF_ATOMIC_CHAR((char)(x)) \ + signed char: (signed char)(x), \ + unsigned char: (unsigned char)(x), \ + short: (short)(x), \ + unsigned short: (unsigned short)(x), \ + int: (int)(x), \ + unsigned int: (unsigned int)(x), \ + long: (long)(x), \ + unsigned long: (unsigned long)(x), \ + long long: (long long)(x), \ + unsigned long long: (unsigned long long)(x), \ + default: (void *)(uintptr_t)(x)) + +#define atomic_load_explicit(object, order) \ + ff_atomic_c(object, FF_ATOMIC_FN(load, object)(object, order)) + +#define atomic_load(object) \ + atomic_load_explicit(object, memory_order_seq_cst) + +#define atomic_store_explicit(object, desired, order) \ + FF_ATOMIC_FN(store, object)(object, desired, order) + +#define atomic_store(object, desired) \ + atomic_store_explicit(object, desired, memory_order_seq_cst) + +#define atomic_exchange_explicit(object, desired, order) \ + ff_atomic_c(object, FF_ATOMIC_FN(exchange, object)(object, desired, order)) + +#define atomic_exchange(object, desired) \ + atomic_exchange_explicit(object, desired, memory_order_seq_cst) + +static av_always_inline memory_order ff_atomic_cas_order(memory_order success, + memory_order failure) +{ + if (success == memory_order_release && failure != memory_order_relaxed) + return memory_order_acq_rel; + return success; } -FETCH_MODIFY(add, +) -FETCH_MODIFY(sub, -) -FETCH_MODIFY(or, |) -FETCH_MODIFY(xor, ^) -FETCH_MODIFY(and, &) +/* expected has to point to an object of the width of the atomic one */ +#define atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) \ + ((void)_Generic((char (*)[sizeof(*(expected))])0, \ + char (*)[sizeof(*(object))]: 0), \ + FF_ATOMIC_FN(cas, object)(object, expected, desired, \ + ff_atomic_cas_order(success, failure))) + +#define atomic_compare_exchange_strong(object, expected, desired) \ + atomic_compare_exchange_strong_explicit(object, expected, desired, \ + memory_order_seq_cst, \ + memory_order_seq_cst) + +#define atomic_compare_exchange_weak_explicit(object, expected, desired, \ + success, failure) \ + atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) -#undef FETCH_MODIFY +#define atomic_compare_exchange_weak(object, expected, desired) \ + atomic_compare_exchange_strong(object, expected, desired) + +#define ff_atomic_fetch(object, operand, op, order) \ + ff_atomic_c(object, FF_ATOMIC_FETCH_FN(op, object)(object, operand, order)) #define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) + ff_atomic_fetch(object, operand, fetch_add, order) #define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) + ff_atomic_fetch(object, operand, fetch_sub, order) #define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) + ff_atomic_fetch(object, operand, fetch_or, order) #define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) + ff_atomic_fetch(object, operand, fetch_xor, order) #define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) + ff_atomic_fetch(object, operand, fetch_and, order) -#define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) +#define atomic_fetch_add(object, operand) \ + atomic_fetch_add_explicit(object, operand, memory_order_seq_cst) + +#define atomic_fetch_sub(object, operand) \ + atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst) + +#define atomic_fetch_or(object, operand) \ + atomic_fetch_or_explicit(object, operand, memory_order_seq_cst) + +#define atomic_fetch_xor(object, operand) \ + atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst) + +#define atomic_fetch_and(object, operand) \ + atomic_fetch_and_explicit(object, operand, memory_order_seq_cst) + +typedef struct atomic_flag { + atomic_bool value; +} atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } #define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) + atomic_exchange_explicit(&(object)->value, 1, order) -#define atomic_flag_clear(object) \ - atomic_store(object, 0) +#define atomic_flag_test_and_set(object) \ + atomic_flag_test_and_set_explicit(object, memory_order_seq_cst) #define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) + atomic_store_explicit(&(object)->value, 0, order) + +#define atomic_flag_clear(object) \ + atomic_flag_clear_explicit(object, memory_order_seq_cst) #endif /* COMPAT_ATOMICS_DUMMY_STDATOMIC_H */ -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
