Merge branch 'atomics' into 'master'

Rework atomics configurations

Closes #932

See merge request cairo/cairo!652
This commit is contained in:
Luca Bacci 2026-05-12 20:07:44 +00:00
commit 019e668e1b
2 changed files with 68 additions and 33 deletions

View file

@ -766,22 +766,28 @@ endforeach
extra_link_args += pthread_link_args
# Atomics are an optional feature in C11. Also need to check that C11 atomics are lock free.
# On Windows we use the Interlocked family of functions
if host_machine.system() != 'windows'
if cc.links(files('meson-cc-tests/atomic-ops-c11.c'), name: 'Atomic ops: c11')
conf.set('HAVE_C11_ATOMIC_PRIMITIVES', 1)
elif cc.links(files('meson-cc-tests/atomic-ops-cxx11.c'), name: 'Atomic ops: cxx11')
conf.set('HAVE_CXX11_ATOMIC_PRIMITIVES', 1)
elif cc.links(files('meson-cc-tests/atomic-ops-gcc-legacy.c'), name: 'Atomic ops: gcc legacy')
conf.set('HAVE_GCC_LEGACY_ATOMICS', 1)
elif cc.has_header('atomic_ops.h')
conf.set('HAVE_LIB_ATOMIC_OPS', 1)
elif cc.has_header('libkern/OSAtomic.h')
conf.set('HAVE_OS_ATOMIC_OPS', 1)
else
warning('Atomic ops not supported.')
endif
cpp_enabled = host_machine.system() == 'windows'
if not cpp_enabled and cc.links(files('meson-cc-tests/atomic-ops-c11.c'), name: 'Atomic ops: c11')
# Currently we avoid C11 atomics when using both C and C++. The standards
# do not guarantee compatibility between C11 atomics and C++11 std::atomic
# (though effort is underway, see C++/N2741). We can enable this for selected
# compilers over time.
#
# When not using C++, check if C11 atomics are available and whether atomic
# ints and pointers are lock-free.
conf.set('HAVE_C11_ATOMIC_PRIMITIVES', 1)
elif cc.links(files('meson-cc-tests/atomic-ops-cxx11.c'), name: 'Atomic ops: cxx11')
conf.set('HAVE_CXX11_ATOMIC_PRIMITIVES', 1)
elif cc.links(files('meson-cc-tests/atomic-ops-gcc-legacy.c'), name: 'Atomic ops: gcc legacy')
conf.set('HAVE_GCC_LEGACY_ATOMICS', 1)
elif host_machine.system() != 'windows' and dependency('atomic_ops', required: false).found()
internal_deps += [dependency('atomic_ops')]
conf.set('HAVE_LIB_ATOMIC_OPS', 1)
elif host_machine.system() == 'darwin' and cc.has_header('libkern/OSAtomic.h')
conf.set('HAVE_OS_ATOMIC_OPS', 1)
elif not cc.has_define('_MSC_VER')
warning('Atomic ops not supported.')
endif
test_mkdir_c_args = []

View file

@ -274,26 +274,35 @@ _cairo_atomic_ptr_get (cairo_atomic_intptr_t *x)
#endif /* HAVE_GCC_LEGACY_ATOMICS */
#if HAVE_LIB_ATOMIC_OPS
#include <atomic_ops.h>
#include <limits.h>
#define HAS_ATOMIC_OPS 1
typedef AO_t cairo_atomic_int_t;
typedef int cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
# define _cairo_atomic_int_get_relaxed(x) (AO_load_full (x))
# define _cairo_atomic_int_set_relaxed(x, val) (AO_store_full ((x), (val)))
/* Casts from signed to unsigned must not change representation */
static_assert((unsigned)-1 == UINT_MAX,
"We require two's complement representation of signed integrals");
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
# define _cairo_atomic_int_get(x) ((int)AO_int_load_full ((unsigned *)(x)))
# define _cairo_atomic_int_get_relaxed(x) ((int)AO_int_load ((unsigned *)(x)))
# define _cairo_atomic_int_set_relaxed(x, val) (AO_int_store ((unsigned *)(x), (unsigned)(val)))
typedef intptr_t cairo_atomic_intptr_t;
# define _cairo_atomic_int_inc(x) ((void) AO_int_fetch_and_add1_full((unsigned *)(x)))
# define _cairo_atomic_int_dec(x) ((void) AO_int_fetch_and_sub1_full((unsigned *)(x)))
# define _cairo_atomic_int_dec_and_test(x) (AO_int_fetch_and_sub1_full((unsigned *)(x)) == 1U)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_int_compare_and_swap_full((unsigned *)x, (unsigned)(oldv), (unsigned)(newv))
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) AO_int_fetch_compare_and_swap_full((unsigned *)x, (unsigned)(oldv), (unsigned)(newv))
typedef AO_t cairo_atomic_intptr_t;
static_assert (sizeof (AO_t) >= sizeof (void *), "AO_t cannot be used for pointers");
# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, (AO_t)oldv, (AO_t)newv)
# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) AO_fetch_compare_and_swap_full(x, (AO_t)oldv, (AO_t)newv)
#endif
@ -330,7 +339,7 @@ typedef intptr_t cairo_atomic_intptr_t;
#endif /* HAVE_OS_ATOMIC_OPS */
#if !defined(HAS_ATOMIC_OPS) && defined(_WIN32)
#if !defined(HAS_ATOMIC_OPS) && defined(_MSC_VER)
#include <windows.h>
#define HAS_ATOMIC_OPS 1
@ -353,13 +362,27 @@ _cairo_atomic_int_get (cairo_atomic_int_t *x)
# define _cairo_atomic_int_dec_and_test(x) (InterlockedDecrement (x) == 0)
static cairo_always_inline cairo_bool_t
_cairo_atomic_int_cmpxchg (cairo_atomic_int_t *x,
int oldv,
int newv)
_cairo_atomic_int_cmpxchg_impl (cairo_atomic_int_t *x,
int oldv,
int newv)
{
return InterlockedCompareExchange (x, (LONG)newv, (LONG)oldv) == oldv;
}
#define _cairo_atomic_int_cmpxchg(x, oldv, newv) \
_cairo_atomic_int_cmpxchg_impl(x, oldv, newv)
static cairo_always_inline int
_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x,
int oldv,
int newv)
{
return (int) InterlockedCompareExchange (x, (LONG)newv, (LONG)oldv);
}
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) \
_cairo_atomic_int_cmpxchg_return_old_impl(x, oldv, newv)
static cairo_always_inline void *
_cairo_atomic_ptr_get (cairo_atomic_intptr_t *x)
{
@ -368,17 +391,23 @@ _cairo_atomic_ptr_get (cairo_atomic_intptr_t *x)
}
static cairo_always_inline cairo_bool_t
_cairo_atomic_ptr_cmpxchg (cairo_atomic_intptr_t *x, void *oldv, void *newv)
_cairo_atomic_ptr_cmpxchg_impl (cairo_atomic_intptr_t *x, void *oldv, void *newv)
{
return InterlockedCompareExchangePointer (x, newv, oldv) == oldv;
}
#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
_cairo_atomic_ptr_cmpxchg_impl(x, oldv, newv)
static cairo_always_inline void *
_cairo_atomic_ptr_cmpxchg_return_old (cairo_atomic_intptr_t *x, void *oldv, void *newv)
_cairo_atomic_ptr_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, void *oldv, void *newv)
{
return InterlockedCompareExchangePointer (x, newv, oldv);
}
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
_cairo_atomic_ptr_cmpxchg_return_old_impl(x, oldv, newv)
#endif /* !defined(HAS_ATOMIC_OPS) && defined(_WIN32) */