From: Hal Finkel Date: Fri, 3 Oct 2014 04:29:40 +0000 (+0000) Subject: Add an implementation of C11's stdatomic.h X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=39f1f1f1c67c5680403fc8cc177395a2011328fd;p=clang Add an implementation of C11's stdatomic.h Adds a Clang-specific implementation of C11's stdatomic.h header. On systems, such as FreeBSD, where a stdatomic.h header is already provided, we defer to that header instead (using our __has_include_next technology). Otherwise, we provide an implementation in terms of our __c11_atomic_* intrinsics (that were created for this purpose). C11 7.1.4p1 requires function declarations for atomic_thread_fence, atomic_signal_fence, atomic_flag_test_and_set, atomic_flag_test_and_set_explicit, and atomic_flag_clear, and requires that they have external linkage. Accordingly, we provide these declarations, but if a user elides the shadowing macros and uses them, then they must have a libc (or similar) that actually provides definitions. atomic_flag is implemented using _Bool as the underlying type. This is consistent with the implementation provided by FreeBSD and also GCC 4.9 (at least when __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1). Patch by Richard Smith (rebased and slightly edited by me -- Richard said I should drive at this point). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218957 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index 9a70198941..9c813baf1b 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -819,7 +819,16 @@ C11 atomic operations Use ``__has_feature(c_atomic)`` or ``__has_extension(c_atomic)`` to determine if support for atomic types using ``_Atomic`` is enabled. Clang also provides :ref:`a set of builtins ` which can be used to implement -the ```` operations on ``_Atomic`` types. +the ```` operations on ``_Atomic`` types. Use +``__has_include()`` to determine if C11's ```` header +is available. + +Clang will use the system's ```` header when one is available, and +will otherwise use its own. When using its own, implementations of the atomic +operations are provided as macros. In the cases where C11 also requires a real +function, this header provides only the declaration of that function (along +with a shadowing macro implementation), and you must link to a library which +provides a definition of the function if you use it instead of the macro. C11 generic selections ^^^^^^^^^^^^^^^^^^^^^^ @@ -1597,12 +1606,14 @@ __c11_atomic builtins Clang provides a set of builtins which are intended to be used to implement C11's ```` header. These builtins provide the semantics of the ``_explicit`` form of the corresponding C11 operation, and are named with a -``__c11_`` prefix. The supported operations are: +``__c11_`` prefix. The supported operations, and the differences from +the corresponding C11 operations, are: * ``__c11_atomic_init`` * ``__c11_atomic_thread_fence`` * ``__c11_atomic_signal_fence`` -* ``__c11_atomic_is_lock_free`` +* ``__c11_atomic_is_lock_free`` (The argument is the size of the + ``_Atomic(...)'' object, instead of its address) * ``__c11_atomic_store`` * ``__c11_atomic_load`` * ``__c11_atomic_exchange`` @@ -1614,6 +1625,11 @@ C11's ```` header. These builtins provide the semantics of the * ``__c11_atomic_fetch_or`` * ``__c11_atomic_fetch_xor`` +The macros ``__ATOMIC_RELAXED``, ``__ATOMIC_CONSUME``, ``__ATOMIC_ACQUIRE``, +``__ATOMIC_RELEASE``, ``__ATOMIC_ACQ_REL``, and ``_ATOMIC_SEQ_CST`` are +provided, with values corresponding to the enumerators of C11's +``memory_order`` enumeration. + Low-level ARM exclusive memory builtins --------------------------------------- diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index f545780785..22a2c316ee 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -33,6 +33,7 @@ set(files smmintrin.h stdalign.h stdarg.h + stdatomic.h stdbool.h stddef.h __stddef_max_align_t.h diff --git a/lib/Headers/stdatomic.h b/lib/Headers/stdatomic.h new file mode 100644 index 0000000000..e3c34767a2 --- /dev/null +++ b/lib/Headers/stdatomic.h @@ -0,0 +1,190 @@ +/*===---- stdatomic.h - Standard header for atomic types and operations -----=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __CLANG_STDATOMIC_H +#define __CLANG_STDATOMIC_H + +/* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for + * example, already has a Clang-compatible stdatomic.h header. + */ +#if __STDC_HOSTED__ && __has_include_next() +# include_next +#else + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* 7.17.1 Introduction */ + +#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_T_LOCK_FREE __GCC_ATOMIC_SHORT_T_LOCK_FREE +#define ATOMIC_INT_T_LOCK_FREE __GCC_ATOMIC_INT_T_LOCK_FREE +#define ATOMIC_LONG_T_LOCK_FREE __GCC_ATOMIC_LONG_T_LOCK_FREE +#define ATOMIC_LLONG_T_LOCK_FREE __GCC_ATOMIC_LLONG_T_LOCK_FREE +#define ATOMIC_POINTER_T_LOCK_FREE __GCC_ATOMIC_POINTER_T_LOCK_FREE + +/* 7.17.2 Initialization */ + +#define ATOMIC_VAR_INIT(value) (value) +#define atomic_init __c11_atomic_init + +/* 7.17.3 Order and consistency */ + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +#define kill_dependency(y) (y) + +/* 7.17.4 Fences */ + +// These should be provided by the libc implementation. +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +/* 7.17.5 Lock-free property */ + +#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) + +/* 7.17.6 Atomic integer types */ + +#ifdef __cplusplus +typedef _Atomic(bool) atomic_bool; +#else +typedef _Atomic(_Bool) atomic_bool; +#endif +typedef _Atomic(char) atomic_char; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(short) atomic_short; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(int) atomic_int; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(long) atomic_long; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(uint_least16_t) atomic_char16_t; +typedef _Atomic(uint_least32_t) atomic_char32_t; +typedef _Atomic(wchar_t) atomic_wchar_t; +typedef _Atomic(int_least8_t) atomic_int_least8_t; +typedef _Atomic(uint_least8_t) atomic_uint_least8_t; +typedef _Atomic(int_least16_t) atomic_int_least16_t; +typedef _Atomic(uint_least16_t) atomic_uint_least16_t; +typedef _Atomic(int_least32_t) atomic_int_least32_t; +typedef _Atomic(uint_least32_t) atomic_uint_least32_t; +typedef _Atomic(int_least64_t) atomic_int_least64_t; +typedef _Atomic(uint_least64_t) atomic_uint_least64_t; +typedef _Atomic(int_fast8_t) atomic_int_fast8_t; +typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; +typedef _Atomic(int_fast16_t) atomic_int_fast16_t; +typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; +typedef _Atomic(int_fast32_t) atomic_int_fast32_t; +typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; +typedef _Atomic(int_fast64_t) atomic_int_fast64_t; +typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +typedef _Atomic(intmax_t) atomic_intmax_t; +typedef _Atomic(uintmax_t) atomic_uintmax_t; + +/* 7.17.7 Operations on atomic types */ + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +/* 7.17.8 Atomic flag type and operations */ + +typedef struct atomic_flag { atomic_bool _Value; } atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } + +// These should be provided by the libc implementation. +#ifdef __cplusplus +bool atomic_flag_test_and_set(volatile atomic_flag *); +bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +#else +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +#endif +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) + +#ifdef __cplusplus +} +#endif + +#endif /* __STDC_HOSTED__ */ +#endif /* __CLANG_STDATOMIC_H */ + diff --git a/test/CodeGen/atomic-ops.c b/test/CodeGen/atomic-ops.c index de9b1887d7..b146eee532 100644 --- a/test/CodeGen/atomic-ops.c +++ b/test/CodeGen/atomic-ops.c @@ -7,12 +7,9 @@ #ifndef ALREADY_INCLUDED #define ALREADY_INCLUDED -// Basic IRGen tests for __c11_atomic_* and GNU __atomic_* +#include -typedef enum memory_order { - memory_order_relaxed, memory_order_consume, memory_order_acquire, - memory_order_release, memory_order_acq_rel, memory_order_seq_cst -} memory_order; +// Basic IRGen tests for __c11_atomic_* and GNU __atomic_* int fi1(_Atomic(int) *i) { // CHECK-LABEL: @fi1 @@ -34,6 +31,12 @@ int fi1b(int *i) { return __atomic_load_n(i, memory_order_seq_cst); } +int fi1c(atomic_int *i) { + // CHECK-LABEL: @fi1c + // CHECK: load atomic i32* {{.*}} seq_cst + return atomic_load(i); +} + void fi2(_Atomic(int) *i) { // CHECK-LABEL: @fi2 // CHECK: store atomic i32 {{.*}} seq_cst @@ -53,6 +56,12 @@ void fi2b(int *i) { __atomic_store_n(i, 1, memory_order_seq_cst); } +void fi2c(atomic_int *i) { + // CHECK-LABEL: @fi2c + // CHECK: store atomic i32 {{.*}} seq_cst + atomic_store(i, 1); +} + int fi3(_Atomic(int) *i) { // CHECK-LABEL: @fi3 // CHECK: atomicrmw and @@ -89,8 +98,15 @@ int fi3d(int *i) { return __atomic_nand_fetch(i, 1, memory_order_seq_cst); } +int fi3e(atomic_int *i) { + // CHECK-LABEL: @fi3e + // CHECK: atomicrmw or + // CHECK-NOT: {{ or }} + return atomic_fetch_or(i, 1); +} + _Bool fi4(_Atomic(int) *i) { - // CHECK-LABEL: @fi4 + // CHECK-LABEL: @fi4( // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0 // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1 @@ -101,7 +117,7 @@ _Bool fi4(_Atomic(int) *i) { } _Bool fi4a(int *i) { - // CHECK-LABEL: @fi4 + // CHECK-LABEL: @fi4a // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0 // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1 @@ -113,7 +129,7 @@ _Bool fi4a(int *i) { } _Bool fi4b(int *i) { - // CHECK-LABEL: @fi4 + // CHECK-LABEL: @fi4b( // CHECK: [[PAIR:%[.0-9A-Z_a-z]+]] = cmpxchg weak i32* [[PTR:%[.0-9A-Z_a-z]+]], i32 [[EXPECTED:%[.0-9A-Z_a-z]+]], i32 [[DESIRED:%[.0-9A-Z_a-z]+]] // CHECK: [[OLD:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 0 // CHECK: [[CMP:%[.0-9A-Z_a-z]+]] = extractvalue { i32, i1 } [[PAIR]], 1 @@ -123,6 +139,13 @@ _Bool fi4b(int *i) { return __atomic_compare_exchange_n(i, &cmp, 1, 1, memory_order_acquire, memory_order_acquire); } +_Bool fi4c(atomic_int *i) { + // CHECK-LABEL: @fi4c + // CHECK: cmpxchg i32* + int cmp = 0; + return atomic_compare_exchange_strong(i, &cmp, 1); +} + float ff1(_Atomic(float) *d) { // CHECK-LABEL: @ff1 // CHECK: load atomic i32* {{.*}} monotonic diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c index 320abc5ad4..7d571ac213 100644 --- a/test/Sema/atomic-ops.c +++ b/test/Sema/atomic-ops.c @@ -2,10 +2,7 @@ // Basic parsing/Sema tests for __c11_atomic_* -typedef enum memory_order { - memory_order_relaxed, memory_order_consume, memory_order_acquire, - memory_order_release, memory_order_acq_rel, memory_order_seq_cst -} memory_order; +#include struct S { char c[3]; }; @@ -40,6 +37,14 @@ _Static_assert(__atomic_is_lock_free(8, 0), ""); _Static_assert(__atomic_is_lock_free(16, 0), ""); // expected-error {{not an integral constant expression}} _Static_assert(__atomic_is_lock_free(17, 0), ""); // expected-error {{not an integral constant expression}} +_Static_assert(atomic_is_lock_free((atomic_char*)0), ""); +_Static_assert(atomic_is_lock_free((atomic_short*)0), ""); +_Static_assert(atomic_is_lock_free((atomic_int*)0), ""); +_Static_assert(atomic_is_lock_free((atomic_long*)0), ""); +// expected-error@+1 {{__int128 is not supported on this target}} +_Static_assert(atomic_is_lock_free((_Atomic(__int128)*)0), ""); // expected-error {{not an integral constant expression}} +_Static_assert(atomic_is_lock_free(0 + (atomic_char*)0), ""); + char i8; short i16; int i32; @@ -171,6 +176,62 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d, __c11_atomic_init(&const_atomic, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}} __c11_atomic_store(&const_atomic, 0, memory_order_release); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}} __c11_atomic_load(&const_atomic, memory_order_acquire); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}} + + // Ensure the macros behave appropriately. + atomic_int n = ATOMIC_VAR_INIT(123); + atomic_init(&n, 456); + atomic_init(&n, (void*)0); // expected-warning {{passing 'void *' to parameter of type 'int'}} + + const atomic_wchar_t cawt; + atomic_init(&cawt, L'x'); // expected-error {{non-const}} + atomic_wchar_t awt; + atomic_init(&awt, L'x'); + + int x = kill_dependency(12); + + atomic_thread_fence(); // expected-error {{too few arguments to function call}} + atomic_thread_fence(memory_order_seq_cst); + atomic_signal_fence(memory_order_seq_cst); + void (*pfn)(memory_order) = &atomic_thread_fence; + pfn = &atomic_signal_fence; + + int k = atomic_load_explicit(&n, memory_order_relaxed); + atomic_store_explicit(&n, k, memory_order_relaxed); + atomic_store(&n, atomic_load(&n)); + + k = atomic_exchange(&n, 72); + k = atomic_exchange_explicit(&n, k, memory_order_release); + + atomic_compare_exchange_strong(&n, k, k); // expected-warning {{take the address with &}} + atomic_compare_exchange_weak(&n, &k, k); + atomic_compare_exchange_strong_explicit(&n, &k, k, memory_order_seq_cst); // expected-error {{too few arguments}} + atomic_compare_exchange_weak_explicit(&n, &k, k, memory_order_seq_cst, memory_order_acquire); + + atomic_fetch_add(&k, n); // expected-error {{must be a pointer to _Atomic}} + k = atomic_fetch_add(&n, k); + k = atomic_fetch_sub(&n, k); + k = atomic_fetch_and(&n, k); + k = atomic_fetch_or(&n, k); + k = atomic_fetch_xor(&n, k); + k = atomic_fetch_add_explicit(&n, k, memory_order_acquire); + k = atomic_fetch_sub_explicit(&n, k, memory_order_release); + k = atomic_fetch_and_explicit(&n, k, memory_order_acq_rel); + k = atomic_fetch_or_explicit(&n, k, memory_order_consume); + k = atomic_fetch_xor_explicit(&n, k, memory_order_relaxed); + + // C11 7.17.1/4: atomic_flag is a structure type. + struct atomic_flag must_be_struct = ATOMIC_FLAG_INIT; + // C11 7.17.8/5 implies that it is also a typedef type. + atomic_flag guard = ATOMIC_FLAG_INIT; + _Bool old_val = atomic_flag_test_and_set(&guard); + if (old_val) atomic_flag_clear(&guard); + + old_val = (atomic_flag_test_and_set)(&guard); + if (old_val) (atomic_flag_clear)(&guard); + + const atomic_flag const_guard; + atomic_flag_test_and_set(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}} + atomic_flag_clear(&const_guard); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_bool *' (aka 'const _Atomic(_Bool) *') invalid)}} } _Atomic(int*) PR12527_a; @@ -403,3 +464,5 @@ void memory_checks(_Atomic(int) *Ap, int *p, int val) { (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_acq_rel, memory_order_relaxed); (void)__atomic_compare_exchange_n(p, p, val, 0, memory_order_seq_cst, memory_order_relaxed); } + +