PR #24223 opened by Kacper Michajłow (kasper93) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24223 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24223.patch
From d2cf405490f530d7450bda77ae91a3f3504ba125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Fri, 21 Aug 2026 02:11:43 +0200 Subject: [PATCH 1/3] compat/atomics/win32: rewrite and fix stdatomic.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old emulation had several problems. It typedef'd every atomic type to intptr_t and implemented the operations on that storage, which broke in several ways. - atomic_int_least64_t and the other 64-bit types were 4 bytes on 32-bit targets, silently truncating stored values. - atomic_compare_exchange_strong() took intptr_t *expected instead of a pointer to the corresponding non-atomic type. Basically, producing OOB reads and writes when working with < 64-bit atomic types on 64-bit targets. Note that while all atomic_* types are typedef'd to intptr_t, the caller provides non atomic values, like int*. - Unsigned wraparound left garbage in the high bits of the storage, so later comparisons of loaded values failed. - atomic_fetch_sub() negated the operand in its own unsigned type, turning small unsigned subtractions into additions of huge values. - atomic_exchange() returned PVOID and loads and stores were plain non-volatile accesses. - atomic_signal_fence() was a no-op instead of a compiler barrier. Rewrite this using _Generic dispatch, to make this implementation usable by callers, as native stdatomic.h it aims to emulate. While at it make the impl more conformant with the C23 standard. ATOMIC_VAR_INIT is not provided anymore, it was removed in C23 and has no users in the tree. Signed-off-by: Kacper Michajłow <[email protected]> --- compat/atomics/win32/stdatomic.h | 377 ++++++++++++++++++++++--------- 1 file changed, 272 insertions(+), 105 deletions(-) diff --git a/compat/atomics/win32/stdatomic.h b/compat/atomics/win32/stdatomic.h index 4f8ac2bb60..062b28cbd8 100644 --- a/compat/atomics/win32/stdatomic.h +++ b/compat/atomics/win32/stdatomic.h @@ -19,162 +19,329 @@ #ifndef COMPAT_ATOMICS_WIN32_STDATOMIC_H #define COMPAT_ATOMICS_WIN32_STDATOMIC_H +#include <stdbool.h> #include <stddef.h> #include <stdint.h> + +#include <intrin.h> #include <windows.h> -#define ATOMIC_FLAG_INIT 0 +#include "libavutil/attributes.h" +#include "libavutil/avassert.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; + +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 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 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; + +#define ATOMIC_BOOL_LOCK_FREE 2 +#define ATOMIC_CHAR_LOCK_FREE 2 +#define ATOMIC_CHAR8_T_LOCK_FREE 2 +#define ATOMIC_CHAR16_T_LOCK_FREE 2 +#define ATOMIC_CHAR32_T_LOCK_FREE 2 +#define ATOMIC_WCHAR_T_LOCK_FREE 2 +#define ATOMIC_SHORT_LOCK_FREE 2 +#define ATOMIC_INT_LOCK_FREE 2 +#define ATOMIC_LONG_LOCK_FREE 2 +#define ATOMIC_LLONG_LOCK_FREE 2 +#define ATOMIC_POINTER_LOCK_FREE 2 + +#define atomic_is_lock_free(obj) ((void)(obj), (bool)true) #define atomic_init(obj, value) \ do { \ *(obj) = (value); \ -} while(0) - -#define kill_dependency(y) ((void)0) - -#define atomic_thread_fence(order) \ - MemoryBarrier(); - -#define atomic_signal_fence(order) \ - ((void)0) - -#define atomic_is_lock_free(obj) 0 - -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; - -#define atomic_store(object, desired) \ -do { \ - *(object) = (desired); \ - MemoryBarrier(); \ } while (0) -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) +#define kill_dependency(y) (y) -#define atomic_load(object) \ - (MemoryBarrier(), *(object)) +#define atomic_thread_fence(order) \ + ((void)(order), MemoryBarrier()) -#define atomic_load_explicit(object, order) \ - atomic_load(object) +/* Only compiler reordering has to be inhibited, the full barrier is + * stronger than required but always correct. */ +#define atomic_signal_fence(order) \ + ((void)(order), MemoryBarrier()) -#define atomic_exchange(object, desired) \ - InterlockedExchangePointer((PVOID volatile *)object, (PVOID)desired) +#define win32_atomic_c(object, x) \ + _Generic(*(object), \ + bool: (bool)(x), \ + 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)) -#define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) - -static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, - intptr_t desired) +static av_always_inline int64_t win32_atomic_load(const volatile void *object, + size_t size) { - intptr_t old = *expected; - *expected = (intptr_t)InterlockedCompareExchangePointer( - (PVOID *)object, (PVOID)desired, (PVOID)old); - return *expected == old; + int64_t ret; + + MemoryBarrier(); + switch (size) { + case 1: + ret = *(const volatile int8_t *)object; + break; + case 2: + ret = *(const volatile int16_t *)object; + break; + case 4: + ret = *(const volatile int32_t *)object; + break; + case 8: +#ifdef _WIN64 + ret = *(const volatile int64_t *)object; +#else + /* 8-byte plain loads can tear on 32-bit x86 */ + ret = InterlockedCompareExchange64((volatile int64_t *)object, 0, 0); +#endif + break; + default: + av_unreachable("invalid size"); + } + MemoryBarrier(); + return ret; } +static av_always_inline void win32_atomic_store(volatile void *object, + int64_t desired, size_t size) +{ + MemoryBarrier(); + switch (size) { + case 1: + *(volatile int8_t *)object = desired; + break; + case 2: + *(volatile int16_t *)object = desired; + break; + case 4: + *(volatile int32_t *)object = desired; + break; + case 8: +#ifdef _WIN64 + *(volatile int64_t *)object = desired; +#else + /* 8-byte plain stores can tear on 32-bit x86 */ + InterlockedExchange64(object, desired); +#endif + break; + default: + av_unreachable("invalid size"); + } + MemoryBarrier(); +} + +static av_always_inline int64_t win32_atomic_exchange(volatile void *object, + int64_t desired, + size_t size) +{ + switch (size) { + case 1: + return InterlockedExchange8(object, desired); + case 2: + return InterlockedExchange16(object, desired); + case 4: + return InterlockedExchange(object, desired); + case 8: + return InterlockedExchange64(object, desired); + default: + av_unreachable("invalid size"); + } +} + +#define WIN32_ATOMIC_CMP_XCHG(bytes, type, InterlockedFn) \ + case bytes: { \ + type *e = expected; \ + type old = *e; \ + type prev = InterlockedFn(object, desired, old); \ + if (prev == old) \ + return 1; \ + *e = prev; \ + return 0; \ + } + +static av_always_inline bool win32_atomic_compare_exchange(volatile void *object, + void *expected, + int64_t desired, + size_t size) +{ + switch (size) { + /* the 8-bit compare-exchange doesn't have Interlocked* macro defined */ + WIN32_ATOMIC_CMP_XCHG(1, char, _InterlockedCompareExchange8) + WIN32_ATOMIC_CMP_XCHG(2, short, InterlockedCompareExchange16) + WIN32_ATOMIC_CMP_XCHG(4, long, InterlockedCompareExchange) + WIN32_ATOMIC_CMP_XCHG(8, int64_t, InterlockedCompareExchange64) + default: + av_unreachable("invalid size"); + } +} + +#undef WIN32_ATOMIC_CMP_XCHG + +#define WIN32_ATOMIC_FETCH_MODIFY(opname, Interlocked) \ +static av_always_inline int64_t win32_atomic_fetch_##opname( \ + volatile void *object, int64_t operand, size_t size) \ +{ \ + switch (size) { \ + case 1: \ + return Interlocked##8(object, operand); \ + case 2: \ + return Interlocked##16(object, operand); \ + case 4: \ + return Interlocked(object, operand); \ + case 8: \ + return Interlocked##64(object, operand); \ + default: \ + av_unreachable("invalid size"); \ + } \ +} + +WIN32_ATOMIC_FETCH_MODIFY(add, InterlockedExchangeAdd) +WIN32_ATOMIC_FETCH_MODIFY(or, InterlockedOr) +WIN32_ATOMIC_FETCH_MODIFY(xor, InterlockedXor) +WIN32_ATOMIC_FETCH_MODIFY(and, InterlockedAnd) + +#undef WIN32_ATOMIC_FETCH_MODIFY + +#define atomic_load(object) \ + win32_atomic_c(object, win32_atomic_load(object, sizeof(*(object)))) + +#define atomic_load_explicit(object, order) \ + ((void)(order), atomic_load(object)) + +#define atomic_store(object, desired) \ + win32_atomic_store(object, win32_atomic_c(object, desired), \ + sizeof(*(object))) + +#define atomic_store_explicit(object, desired, order) \ + ((void)(order), atomic_store(object, desired)) + +#define atomic_exchange(object, desired) \ + win32_atomic_c(object, \ + win32_atomic_exchange(object, \ + win32_atomic_c(object, desired), \ + sizeof(*(object)))) + +#define atomic_exchange_explicit(object, desired, order) \ + ((void)(order), atomic_exchange(object, desired)) + +#define atomic_compare_exchange_strong(object, expected, desired) \ + win32_atomic_compare_exchange(object, expected, \ + win32_atomic_c(object, desired), \ + sizeof(*(object))) + #define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) + ((void)(success), (void)(failure), \ + 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, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) + atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) + +#define win32_atomic_fetch(object, operand, op) \ + win32_atomic_c(object, \ + win32_atomic_fetch_##op(object, \ + win32_atomic_c(object, operand), \ + sizeof(*(object)))) -#ifdef _WIN64 #define atomic_fetch_add(object, operand) \ - InterlockedExchangeAdd64(object, operand) + win32_atomic_fetch(object, operand, add) #define atomic_fetch_sub(object, operand) \ - InterlockedExchangeAdd64(object, -(operand)) + win32_atomic_fetch(object, 0 - (uint64_t)win32_atomic_c(object, operand), add) #define atomic_fetch_or(object, operand) \ - InterlockedOr64(object, operand) + win32_atomic_fetch(object, operand, or) #define atomic_fetch_xor(object, operand) \ - InterlockedXor64(object, operand) + win32_atomic_fetch(object, operand, xor) #define atomic_fetch_and(object, operand) \ - InterlockedAnd64(object, operand) -#else -#define atomic_fetch_add(object, operand) \ - InterlockedExchangeAdd(object, operand) - -#define atomic_fetch_sub(object, operand) \ - InterlockedExchangeAdd(object, -(operand)) - -#define atomic_fetch_or(object, operand) \ - InterlockedOr(object, operand) - -#define atomic_fetch_xor(object, operand) \ - InterlockedXor(object, operand) - -#define atomic_fetch_and(object, operand) \ - InterlockedAnd(object, operand) -#endif /* _WIN64 */ + win32_atomic_fetch(object, operand, and) #define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) + ((void)(order), atomic_fetch_add(object, operand)) #define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) + ((void)(order), atomic_fetch_sub(object, operand)) #define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) + ((void)(order), atomic_fetch_or(object, operand)) #define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) + ((void)(order), atomic_fetch_xor(object, operand)) #define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) + ((void)(order), atomic_fetch_and(object, operand)) + +typedef struct atomic_flag { + atomic_bool value; +} atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } #define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) + atomic_exchange(&(object)->value, 1) #define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) + ((void)(order), atomic_flag_test_and_set(object)) #define atomic_flag_clear(object) \ - atomic_store(object, 0) + atomic_store(&(object)->value, 0) #define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) + ((void)(order), atomic_flag_clear(object)) #endif /* COMPAT_ATOMICS_WIN32_STDATOMIC_H */ -- 2.52.0 From c1a3e539a0e184a7dba24dc0a1265f9dad58e393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Fri, 21 Aug 2026 02:11:43 +0200 Subject: [PATCH 2/3] avcodec/vvc: remove workaround for broken win32 stdatomic emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compat header now takes a pointer to the corresponding non-atomic type in atomic_compare_exchange_strong() as the standard requires, so plain int is correct everywhere. Note that VVC is the only place that worked around this, all other users were simply broken with the old emulation. Signed-off-by: Kacper Michajłow <[email protected]> --- libavcodec/vvc/thread.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c index 164ad83430..a80ec773cd 100644 --- a/libavcodec/vvc/thread.c +++ b/libavcodec/vvc/thread.c @@ -646,11 +646,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) if (!atomic_load(&ft->ret)) { if ((ret = run[stage](s, lc, t)) < 0) { -#ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H - intptr_t zero = 0; -#else int zero = 0; -#endif atomic_compare_exchange_strong(&ft->ret, &zero, ret); av_log(s->avctx, AV_LOG_ERROR, "frame %5d, %s(%3d, %3d) failed with %d\r\n", -- 2.52.0 From e093e492a28d126edb676b5df7c9db58d42ce392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Thu, 20 Aug 2026 10:27:07 +0200 Subject: [PATCH 3/3] compat/atomics/dummy: rewrite and fix stdatomic.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | 319 ++++++++++++++++++++----------- 1 file changed, 211 insertions(+), 108 deletions(-) diff --git a/compat/atomics/dummy/stdatomic.h b/compat/atomics/dummy/stdatomic.h index 59d85f915d..c692b7cd31 100644 --- a/compat/atomics/dummy/stdatomic.h +++ b/compat/atomics/dummy/stdatomic.h @@ -16,161 +16,264 @@ * 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" +#include "libavutil/avassert.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; + +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 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 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; + +#define ATOMIC_BOOL_LOCK_FREE 2 +#define ATOMIC_CHAR_LOCK_FREE 2 +#define ATOMIC_CHAR8_T_LOCK_FREE 2 +#define ATOMIC_CHAR16_T_LOCK_FREE 2 +#define ATOMIC_CHAR32_T_LOCK_FREE 2 +#define ATOMIC_WCHAR_T_LOCK_FREE 2 +#define ATOMIC_SHORT_LOCK_FREE 2 +#define ATOMIC_INT_LOCK_FREE 2 +#define ATOMIC_LONG_LOCK_FREE 2 +#define ATOMIC_LLONG_LOCK_FREE 2 +#define ATOMIC_POINTER_LOCK_FREE 2 + +#define atomic_is_lock_free(obj) ((void)(obj), (bool)true) #define atomic_init(obj, value) \ do { \ *(obj) = (value); \ -} while(0) - -#define kill_dependency(y) ((void)0) - -#define atomic_thread_fence(order) \ - ((void)0) - -#define atomic_signal_fence(order) \ - ((void)0) - -#define atomic_is_lock_free(obj) 0 - -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; - -#define atomic_store(object, desired) \ -do { \ - *(object) = (desired); \ } while (0) -#define atomic_store_explicit(object, desired, order) \ - atomic_store(object, desired) +#define kill_dependency(y) (y) + +#define atomic_thread_fence(order) \ + ((void)(order)) + +#define atomic_signal_fence(order) \ + ((void)(order)) + +#define dummy_atomic_c(object, x) \ + _Generic(*(object), \ + bool: (bool)(x), \ + 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)) + +static av_always_inline int64_t dummy_atomic_load(const void *object, + size_t size) +{ + switch (size) { + case 1: { int8_t v; memcpy(&v, object, sizeof(v)); return v; } + case 2: { int16_t v; memcpy(&v, object, sizeof(v)); return v; } + case 4: { int32_t v; memcpy(&v, object, sizeof(v)); return v; } + case 8: { int64_t v; memcpy(&v, object, sizeof(v)); return v; } + default: + av_unreachable("invalid size"); + } +} + +static av_always_inline void dummy_atomic_store(void *object, int64_t desired, + size_t size) +{ + switch (size) { + case 1: { int8_t v = desired; memcpy(object, &v, sizeof(v)); break; } + case 2: { int16_t v = desired; memcpy(object, &v, sizeof(v)); break; } + case 4: { int32_t v = desired; memcpy(object, &v, sizeof(v)); break; } + case 8: { int64_t v = desired; memcpy(object, &v, sizeof(v)); break; } + default: + av_unreachable("invalid size"); + } +} + +static av_always_inline int64_t dummy_atomic_exchange(void *object, + int64_t desired, + size_t size) +{ + int64_t old = dummy_atomic_load(object, size); + dummy_atomic_store(object, desired, size); + return old; +} + +static av_always_inline bool dummy_atomic_compare_exchange(void *object, + void *expected, + int64_t desired, + size_t size) +{ + int64_t old = dummy_atomic_load(object, size); + int64_t exp = dummy_atomic_load(expected, size); + + if (old == exp) { + dummy_atomic_store(object, desired, size); + return 1; + } + dummy_atomic_store(expected, old, size); + return 0; +} + +#define DUMMY_ATOMIC_FETCH_MODIFY(opname, op) \ +static av_always_inline int64_t dummy_atomic_fetch_##opname( \ + void *object, int64_t operand, size_t size) \ +{ \ + int64_t old = dummy_atomic_load(object, size); \ + dummy_atomic_store(object, (uint64_t)old op (uint64_t)operand, size); \ + return old; \ +} + +DUMMY_ATOMIC_FETCH_MODIFY(add, +) +DUMMY_ATOMIC_FETCH_MODIFY(or, |) +DUMMY_ATOMIC_FETCH_MODIFY(xor, ^) +DUMMY_ATOMIC_FETCH_MODIFY(and, &) + +#undef DUMMY_ATOMIC_FETCH_MODIFY #define atomic_load(object) \ - (*(object)) + dummy_atomic_c(object, dummy_atomic_load(object, sizeof(*(object)))) #define atomic_load_explicit(object, order) \ - atomic_load(object) + ((void)(order), atomic_load(object)) -static inline intptr_t atomic_exchange(intptr_t *object, intptr_t desired) -{ - intptr_t ret = *object; - *object = desired; - return ret; -} +#define atomic_store(object, desired) \ + dummy_atomic_store(object, dummy_atomic_c(object, desired), \ + sizeof(*(object))) + +#define atomic_store_explicit(object, desired, order) \ + ((void)(order), atomic_store(object, desired)) + +#define atomic_exchange(object, desired) \ + dummy_atomic_c(object, \ + dummy_atomic_exchange(object, \ + dummy_atomic_c(object, desired), \ + sizeof(*(object)))) #define atomic_exchange_explicit(object, desired, order) \ - atomic_exchange(object, desired) + ((void)(order), atomic_exchange(object, desired)) -static inline int atomic_compare_exchange_strong(intptr_t *object, intptr_t *expected, - intptr_t desired) -{ - int ret; - if (*object == *expected) { - *object = desired; - ret = 1; - } else { - *expected = *object; - ret = 0; - } - return ret; -} +#define atomic_compare_exchange_strong(object, expected, desired) \ + dummy_atomic_compare_exchange(object, expected, \ + dummy_atomic_c(object, desired), \ + sizeof(*(object))) #define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ - atomic_compare_exchange_strong(object, expected, desired) + ((void)(success), (void)(failure), \ + 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, success, failure) \ - atomic_compare_exchange_weak(object, expected, desired) + atomic_compare_exchange_strong_explicit(object, expected, desired, \ + success, failure) -#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; \ -} +#define dummy_atomic_fetch(object, operand, op) \ + dummy_atomic_c(object, \ + dummy_atomic_fetch_##op(object, \ + dummy_atomic_c(object, operand), \ + sizeof(*(object)))) -FETCH_MODIFY(add, +) -FETCH_MODIFY(sub, -) -FETCH_MODIFY(or, |) -FETCH_MODIFY(xor, ^) -FETCH_MODIFY(and, &) +#define atomic_fetch_add(object, operand) \ + dummy_atomic_fetch(object, operand, add) -#undef FETCH_MODIFY +#define atomic_fetch_sub(object, operand) \ + dummy_atomic_fetch(object, 0 - (uint64_t)dummy_atomic_c(object, operand), add) + +#define atomic_fetch_or(object, operand) \ + dummy_atomic_fetch(object, operand, or) + +#define atomic_fetch_xor(object, operand) \ + dummy_atomic_fetch(object, operand, xor) + +#define atomic_fetch_and(object, operand) \ + dummy_atomic_fetch(object, operand, and) #define atomic_fetch_add_explicit(object, operand, order) \ - atomic_fetch_add(object, operand) + ((void)(order), atomic_fetch_add(object, operand)) #define atomic_fetch_sub_explicit(object, operand, order) \ - atomic_fetch_sub(object, operand) + ((void)(order), atomic_fetch_sub(object, operand)) #define atomic_fetch_or_explicit(object, operand, order) \ - atomic_fetch_or(object, operand) + ((void)(order), atomic_fetch_or(object, operand)) #define atomic_fetch_xor_explicit(object, operand, order) \ - atomic_fetch_xor(object, operand) + ((void)(order), atomic_fetch_xor(object, operand)) #define atomic_fetch_and_explicit(object, operand, order) \ - atomic_fetch_and(object, operand) + ((void)(order), atomic_fetch_and(object, operand)) + +typedef struct atomic_flag { + atomic_bool value; +} atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } #define atomic_flag_test_and_set(object) \ - atomic_exchange(object, 1) + atomic_exchange(&(object)->value, 1) #define atomic_flag_test_and_set_explicit(object, order) \ - atomic_flag_test_and_set(object) + ((void)(order), atomic_flag_test_and_set(object)) #define atomic_flag_clear(object) \ - atomic_store(object, 0) + atomic_store(&(object)->value, 0) #define atomic_flag_clear_explicit(object, order) \ - atomic_flag_clear(object) + ((void)(order), atomic_flag_clear(object)) #endif /* COMPAT_ATOMICS_DUMMY_STDATOMIC_H */ -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
