Lely core libraries 2.3.4
stdatomic.h
Go to the documentation of this file.
1
23#ifndef LELY_LIBC_STDATOMIC_H_
24#define LELY_LIBC_STDATOMIC_H_
25
26#include <lely/features.h>
27
28#ifndef LELY_HAVE_STDATOMIC_H
29#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
30#define LELY_HAVE_STDATOMIC_H 1
31#endif
32#endif // !LELY_HAVE_STDATOMIC_H
33
34#if LELY_HAVE_STDATOMIC_H
35#include <stdatomic.h>
36#else // !LELY_HAVE_STDATOMIC_H
37
38#if defined(__clang__) && __has_extension(c_atomic)
39#define LELY_HAVE_CLANG_ATOMIC 1
40#elif GNUC_PREREQ(4, 7)
41#define LELY_HAVE_GNUC_ATOMIC 1
42#elif GNUC_PREREQ(4, 1)
43#define LELY_HAVE_SYNC_ATOMIC 1
44#endif
45
46#if LELY_HAVE_CLANG_ATOMIC | LELY_HAVE_GNUC_ATOMIC | LELY_HAVE_SYNC_ATOMIC
47
48#include <lely/libc/uchar.h>
49
50#include <stddef.h>
51#include <stdint.h>
52
53#ifndef LELY_LIBC_STDATOMIC_INLINE
54#define LELY_LIBC_STDATOMIC_INLINE static inline
55#endif
56
57#ifdef __GCC_ATOMIC_BOOL_LOCK_FREE
58#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
59#else
60#define ATOMIC_BOOL_LOCK_FREE 2
61#endif
62
63#ifdef __GCC_ATOMIC_CHAR_LOCK_FREE
64#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
65#else
66#define ATOMIC_CHAR_LOCK_FREE 1
67#endif
68
69#ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE
70#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
71#else
72#define ATOMIC_CHAR16_T_LOCK_FREE 1
73#endif
74
75#ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE
76#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
77#else
78#define ATOMIC_CHAR32_T_LOCK_FREE 1
79#endif
80
81#ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE
82#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
83#else
84#define ATOMIC_WCHAR_T_LOCK_FREE 1
85#endif
86
87#ifdef __GCC_ATOMIC_SHORT_LOCK_FREE
88#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
89#else
90#define ATOMIC_SHORT_LOCK_FREE 1
91#endif
92
93#ifdef __GCC_ATOMIC_INT_LOCK_FREE
94#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
95#else
96#define ATOMIC_INT_LOCK_FREE 1
97#endif
98
99#ifdef __GCC_ATOMIC_LONG_LOCK_FREE
100#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
101#else
102#define ATOMIC_LONG_LOCK_FREE 1
103#endif
104
105#ifdef __GCC_ATOMIC_LLONG_LOCK_FREE
106#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
107#else
108#define ATOMIC_LLONG_LOCK_FREE 1
109#endif
110
111#ifdef __GCC_ATOMIC_POINTER_LOCK_FREE
112#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
113#else
114#define ATOMIC_POINTER_LOCK_FREE 1
115#endif
116
120#define ATOMIC_FLAG_INIT \
121 { \
122 ATOMIC_VAR_INIT(0) \
123 }
124
126typedef enum {
128#ifdef __ATOMIC_RELAXED
129 memory_order_relaxed = __ATOMIC_RELAXED,
130#else
132#endif
137#ifdef __ATOMIC_CONSUME
138 memory_order_consume = __ATOMIC_CONSUME,
139#else
141#endif
146#ifdef __ATOMIC_ACQUIRE
147 memory_order_acquire = __ATOMIC_ACQUIRE,
148#else
150#endif
155#ifdef __ATOMIC_RELEASE
156 memory_order_release = __ATOMIC_RELEASE,
157#else
159#endif
165#ifdef __ATOMIC_ACQ_REL
166 memory_order_acq_rel = __ATOMIC_ACQ_REL,
167#else
169#endif
171#ifdef __ATOMIC_SEQ_CST
172 memory_order_seq_cst = __ATOMIC_SEQ_CST
173#else
175#endif
177
178#ifndef LELY_HAVE_CLANG_ATOMIC
179#undef _Atomic
180#define _Atomic(T) \
181 struct { \
182 T volatile _value_; \
183 }
184#endif
185
186#ifndef ATOMIC_BOOL_TYPE
187#ifdef __cplusplus
188#define ATOMIC_BOOL_TYPE bool
189#else
190#define ATOMIC_BOOL_TYPE _Bool
191#endif
192#endif
193
198typedef struct {
199 _Atomic(ATOMIC_BOOL_TYPE) _value_;
201
206#if LELY_HAVE_CLANG_ATOMIC
207#define ATOMIC_VAR_INIT(value) (value)
208#else
209#define ATOMIC_VAR_INIT(value) \
210 { \
211 (value) \
212 }
213#endif
214
219#if LELY_HAVE_CLANG_ATOMIC
220#define atomic_init(obj, value) __c11_atomic_init(obj, value)
221#else
222#define atomic_init(obj, value) \
223 atomic_store_explicit(obj, value, memory_order_relaxed)
224#endif
225
230#if defined(__GNUC__) || (__clang__)
231#define kill_dependency(y) \
232 __extension__({ \
233 __typeof__(y) _tmp_ = (y); \
234 _tmp_; \
235 })
236#else
237#define kill_dependency(y)
238#endif
239
240#ifdef __cplusplus
241extern "C" {
242#endif
243
245LELY_LIBC_STDATOMIC_INLINE void atomic_thread_fence(memory_order order);
246
252LELY_LIBC_STDATOMIC_INLINE void atomic_signal_fence(memory_order order);
253
254#ifdef __cplusplus
255}
256#endif
257
264#if LELY_HAVE_CLANG_ATOMIC
265#define atomic_is_lock_free(obj) (__c11_atomic_is_lock_free(sizeof(*(obj))))
266#elif LELY_HAVE_GNUC_ATOMIC
267#define atomic_is_lock_free(obj) \
268 (__atomic_is_lock_free(sizeof((obj)->_value_), &(obj)->_value_))
269#else
270#define atomic_is_lock_free(obj) (sizeof((obj)->_value_) <= sizeof(void *))
271#endif
272
273typedef _Atomic(ATOMIC_BOOL_TYPE) atomic_bool;
274typedef _Atomic(char) atomic_char;
275typedef _Atomic(signed char) atomic_schar;
276typedef _Atomic(unsigned char) atomic_uchar;
277typedef _Atomic(short) atomic_short;
278typedef _Atomic(unsigned short) atomic_ushort;
279typedef _Atomic(int) atomic_int;
280typedef _Atomic(unsigned int) atomic_uint;
281typedef _Atomic(long) atomic_long;
282typedef _Atomic(unsigned long) atomic_ulong;
283typedef _Atomic(long long) atomic_llong;
284typedef _Atomic(unsigned long long) atomic_ullong;
285typedef _Atomic(char16_t) atomic_char16_t;
286typedef _Atomic(char32_t) atomic_char32_t;
287typedef _Atomic(wchar_t) atomic_wchar_t;
288typedef _Atomic(int_least8_t) atomic_int_least8_t;
289typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
290typedef _Atomic(int_least16_t) atomic_int_least16_t;
291typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
292typedef _Atomic(int_least32_t) atomic_int_least32_t;
293typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
294typedef _Atomic(int_least64_t) atomic_int_least64_t;
295typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
296typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
297typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
298typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
299typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
300typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
301typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
302typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
303typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
304typedef _Atomic(intptr_t) atomic_intptr_t;
305typedef _Atomic(uintptr_t) atomic_uintptr_t;
306typedef _Atomic(size_t) atomic_size_t;
307typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
308typedef _Atomic(intmax_t) atomic_intmax_t;
309typedef _Atomic(uintmax_t) atomic_uintmax_t;
310
314#define atomic_store(object, desired) \
315 (atomic_store_explicit((object), (desired), memory_order_seq_cst))
316
321#if LELY_HAVE_CLANG_ATOMIC
322#define atomic_store_explicit(object, desired, order) \
323 (__c11_atomic_store((object), (desired), (order)))
324#elif LELY_HAVE_GNUC_ATOMIC
325#define atomic_store_explicit(object, desired, order) \
326 (__atomic_store_n(&(object)->_value_, (desired), (order)))
327#else
328#define atomic_store_explicit(object, desired, order) \
329 ((void)atomic_exchange_explicit((object), (desired), (order)))
330#endif
331
333#define atomic_load(object) \
334 (atomic_load_explicit((object), memory_order_seq_cst))
335
340#if LELY_HAVE_CLANG_ATOMIC
341#define atomic_load_explicit(object, order) \
342 (__c11_atomic_load((object), (order)))
343#elif LELY_HAVE_GNUC_ATOMIC
344#define atomic_load_explicit(object, order) \
345 (__atomic_load_n(&(object)->_value_, (order)))
346#elif LELY_HAVE_SYNC_ATOMIC
347#define atomic_load_explicit(object, order) \
348 ((void)(order), __sync_fetch_and_add(&(object)->_value_, 0))
349#endif
350
355#define atomic_exchange(object, desired) \
356 (atomic_exchange_explicit((object), (desired), memory_order_seq_cst))
357
364#if LELY_HAVE_CLANG_ATOMIC
365#define atomic_exchange_explicit(object, desired, order) \
366 (__c11_atomic_exchange((object), (desired), (order)))
367#elif LELY_HAVE_GNUC_ATOMIC
368#define atomic_exchange_explicit(object, desired, order) \
369 (__atomic_exchange_n(&(object)->_value_, (desired), (order)))
370#elif LELY_HAVE_SYNC_ATOMIC
371#define atomic_exchange_explicit(object, desired, order) \
372 __extension__({ \
373 __typeof__(object) __object = (object); \
374 __typeof__(desired) __desired = (desired); \
375 atomic_thread_fence(order); \
376 __sync_lock_test_and_set(&(__object)->_value_, __desired); \
377 })
378#endif
379
384#define atomic_compare_exchange_strong(object, expected, desired) \
385 (atomic_compare_exchange_strong_explicit((object), (expected), \
386 (desired), memory_order_seq_cst, \
387 memory_order_seq_cst))
388
399#if LELY_HAVE_CLANG_ATOMIC
400#define atomic_compare_exchange_strong_explicit( \
401 object, expected, desired, success, failure) \
402 (__c11_atomic_compare_exchange_strong((object), (expected), (desired), \
403 (success), (failure)))
404#elif LELY_HAVE_GNUC_ATOMIC
405#define atomic_compare_exchange_strong_explicit( \
406 object, expected, desired, success, failure) \
407 (__atomic_compare_exchange_n(&(object)->_value_, (expected), \
408 (desired), 0, (success), (failure)))
409#elif LELY_HAVE_SYNC_ATOMIC
410// clang-format off
411#define atomic_compare_exchange_strong_explicit(object, expected, desired, \
412 success, failure) \
413 __extension__({ \
414 (void)(success); \
415 (void)(failure); \
416 __typeof__(*(expected)) _expected_ = *(expected); \
417 (ATOMIC_BOOL_TYPE)((*(expected) = __sync_val_compare_and_swap( \
418 &(object)->_value_, _expected_, (desired))) \
419 == _expected_); \
420 })
421// clang-format on
422#endif
423
428#define atomic_compare_exchange_weak(object, expected, desired) \
429 (atomic_compare_exchange_weak_explicit((object), (expected), \
430 (desired), memory_order_seq_cst, \
431 memory_order_seq_cst))
432
446#if LELY_HAVE_CLANG_ATOMIC
447#define atomic_compare_exchange_weak_explicit( \
448 object, expected, desired, success, failure) \
449 (__c11_atomic_compare_exchange_weak((object), (expected), (desired), \
450 (success), (failure)))
451#elif LELY_HAVE_GNUC_ATOMIC
452#define atomic_compare_exchange_weak_explicit( \
453 object, expected, desired, success, failure) \
454 (__atomic_compare_exchange_n(&(object)->_value_, (expected), \
455 (desired), 1, (success), (failure)))
456#else
457#define atomic_compare_exchange_weak_explicit( \
458 object, expected, desired, success, failure) \
459 (atomic_compare_exchange_strong_explicit((object), (expected), \
460 (desired), (success), (failure)))
461#endif
462
467#define atomic_fetch_add(object, operand) \
468 (atomic_fetch_add_explicit((object), (operand), memory_order_seq_cst))
469
476#if LELY_HAVE_CLANG_ATOMIC
477#define atomic_fetch_add_explicit(object, operand, order) \
478 (__c11_atomic_fetch_add((object), (operand), (order)))
479#elif LELY_HAVE_GNUC_ATOMIC
480#define atomic_fetch_add_explicit(object, operand, order) \
481 (__atomic_fetch_add(&(object)->_value_, (operand), (order)))
482#elif LELY_HAVE_SYNC_ATOMIC
483#define atomic_fetch_add_explicit(object, operand, order) \
484 ((void)(order), __sync_fetch_and_add(&(object)->_value_, (operand)))
485#endif
486
491#define atomic_fetch_sub(object, operand) \
492 (atomic_fetch_sub_explicit((object), (operand), memory_order_seq_cst))
493
500#if LELY_HAVE_CLANG_ATOMIC
501#define atomic_fetch_sub_explicit(object, operand, order) \
502 (__c11_atomic_fetch_sub((object), (operand), (order)))
503#elif LELY_HAVE_GNUC_ATOMIC
504#define atomic_fetch_sub_explicit(object, operand, order) \
505 (__atomic_fetch_sub(&(object)->_value_, (operand), (order)))
506#elif LELY_HAVE_SYNC_ATOMIC
507#define atomic_fetch_sub_explicit(object, operand, order) \
508 ((void)(order), __sync_fetch_and_sub(&(object)->_value_, (operand)))
509#endif
510
515#define atomic_fetch_or(object, operand) \
516 (atomic_fetch_or_explicit((object), (operand), memory_order_seq_cst))
517
524#if LELY_HAVE_CLANG_ATOMIC
525#define atomic_fetch_or_explicit(object, operand, order) \
526 (__c11_atomic_fetch_or((object), (operand), (order)))
527#elif LELY_HAVE_GNUC_ATOMIC
528#define atomic_fetch_or_explicit(object, operand, order) \
529 (__atomic_fetch_or(&(object)->_value_, (operand), (order)))
530#elif LELY_HAVE_SYNC_ATOMIC
531#define atomic_fetch_or_explicit(object, operand, order) \
532 ((void)(order), __sync_fetch_and_or(&(object)->_value_, (operand)))
533#endif
534
539#define atomic_fetch_xor(object, operand) \
540 (atomic_fetch_xor_explicit((object), (operand), memory_order_seq_cst))
541
548#if LELY_HAVE_CLANG_ATOMIC
549#define atomic_fetch_xor_explicit(object, operand, order) \
550 (__c11_atomic_fetch_xor((object), (operand), (order)))
551#elif LELY_HAVE_GNUC_ATOMIC
552#define atomic_fetch_xor_explicit(object, operand, order) \
553 (__atomic_fetch_xor(&(object)->_value_, (operand), (order)))
554#elif LELY_HAVE_SYNC_ATOMIC
555#define atomic_fetch_xor_explicit(object, operand, order) \
556 ((void)(order), __sync_fetch_and_xor(&(object)->_value_, (operand)))
557#endif
558
563#define atomic_fetch_and(object, operand) \
564 (atomic_fetch_and_explicit((object), (operand), memory_order_seq_cst))
565
572#if LELY_HAVE_CLANG_ATOMIC
573#define atomic_fetch_and_explicit(object, operand, order) \
574 (__c11_atomic_fetch_and((object), (operand), (order)))
575#elif LELY_HAVE_GNUC_ATOMIC
576#define atomic_fetch_and_explicit(object, operand, order) \
577 (__atomic_fetch_and(&(object)->_value_, (operand), (order)))
578#elif LELY_HAVE_SYNC_ATOMIC
579#define atomic_fetch_and_explicit(object, operand, order) \
580 ((void)(order), __sync_fetch_and_and(&(object)->_value_, (operand)))
581#endif
582
583#ifdef __cplusplus
584extern "C" {
585#endif
586
593LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(
594 volatile atomic_flag *object, memory_order order);
595
600LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set(
601 volatile atomic_flag *object);
602
607LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear_explicit(
608 volatile atomic_flag *object, memory_order order);
609
614LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear(volatile atomic_flag *object);
615
616inline void
618{
619#if LELY_HAVE_CLANG_ATOMIC
620 __c11_atomic_thread_fence(order);
621#elif LELY_HAVE_GNUC_ATOMIC
622 __atomic_thread_fence(order);
623#elif LELY_HAVE_SYNC_ATOMIC
624 if (order != memory_order_relaxed)
625 __sync_synchronize();
626#endif
627}
628
629inline void
631{
632#if LELY_HAVE_CLANG_ATOMIC
633 __c11_atomic_signal_fence(order);
634#elif LELY_HAVE_GNUC_ATOMIC
635 __atomic_signal_fence(order);
636#elif defined(__GNUC__)
637 if (order != memory_order_relaxed)
638 __asm volatile("" ::: "memory");
639#endif
640}
641
642inline ATOMIC_BOOL_TYPE
644 volatile atomic_flag *object, memory_order order)
645{
646 return atomic_exchange_explicit(&object->_value_, 1, order);
647}
648
649inline ATOMIC_BOOL_TYPE
651{
653}
654
655inline void
657{
658 atomic_store_explicit(&object->_value_, 0, order);
659}
660
661inline void
663{
665}
666
667#ifdef __cplusplus
668}
669#endif
670
671#endif // LELY_HAVE_CLANG_ATOMIC | LELY_HAVE_GNUC_ATOMIC | LELY_HAVE_SYNC_ATOMIC
672
673#endif // !LELY_HAVE_STDATOMIC_H
674
675#endif // !LELY_LIBC_STDATOMIC_H_
This header file is part of the Lely libraries; it contains the compiler feature definitions.
This header file is part of the C11 and POSIX compatibility library; it includes <stdatomic....
memory_order
An enumerated type identifying memory constraints.
Definition: stdatomic.h:126
@ memory_order_consume
A load operation performs a consume operation on the affected memory location.
Definition: stdatomic.h:140
@ memory_order_seq_cst
Enforces a single total order on all affected locations.
Definition: stdatomic.h:174
@ memory_order_release
A store operation performs a release operation on the affected memory location.
Definition: stdatomic.h:158
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:131
@ memory_order_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
Definition: stdatomic.h:168
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:149
ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order)
Atomically sets the value at object to true.
Definition: stdatomic.h:643
void atomic_flag_clear(volatile atomic_flag *object)
Equivalent to #atomic_flag_test_and_set_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:662
void atomic_signal_fence(memory_order order)
Equivalent to atomic_thread_fence(order), except that the resulting ordering constraints are establis...
Definition: stdatomic.h:630
void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order)
Atomically sets the value at object to false.
Definition: stdatomic.h:656
ATOMIC_BOOL_TYPE atomic_flag_test_and_set(volatile atomic_flag *object)
Equivalent to #atomic_flag_test_and_set_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:650
#define atomic_exchange_explicit(object, desired, order)
Atomically replaces the value at object with desired.
Definition: stdatomic.h:368
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:617
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
Definition: stdatomic.h:325
This header file is part of the C11 and POSIX compatibility library; it includes <stddef....
This header file is part of the C11 and POSIX compatibility library; it includes <stdint....
An atomic type providing the classic test-and-set functionality.
Definition: stdatomic.h:198
This header file is part of the C11 and POSIX compatibility library; it includes <uchar....