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 
126 typedef enum {
128 #ifdef __ATOMIC_RELAXED
129  memory_order_relaxed = __ATOMIC_RELAXED,
130 #else
132 #endif
133 
137 #ifdef __ATOMIC_CONSUME
138  memory_order_consume = __ATOMIC_CONSUME,
139 #else
141 #endif
142 
146 #ifdef __ATOMIC_ACQUIRE
147  memory_order_acquire = __ATOMIC_ACQUIRE,
148 #else
150 #endif
151 
155 #ifdef __ATOMIC_RELEASE
156  memory_order_release = __ATOMIC_RELEASE,
157 #else
159 #endif
160 
165 #ifdef __ATOMIC_ACQ_REL
166  memory_order_acq_rel = __ATOMIC_ACQ_REL,
167 #else
169 #endif
170 #ifdef __ATOMIC_SEQ_CST
172  memory_order_seq_cst = __ATOMIC_SEQ_CST
173 #else
175 #endif
176 } memory_order;
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 
198 typedef struct {
199  _Atomic(ATOMIC_BOOL_TYPE) _value_;
200 } atomic_flag;
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
241 extern "C" {
242 #endif
243 
245 LELY_LIBC_STDATOMIC_INLINE void atomic_thread_fence(memory_order order);
246 
252 LELY_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 
273 typedef _Atomic(ATOMIC_BOOL_TYPE) atomic_bool;
274 typedef _Atomic(char) atomic_char;
275 typedef _Atomic(signed char) atomic_schar;
276 typedef _Atomic(unsigned char) atomic_uchar;
277 typedef _Atomic(short) atomic_short;
278 typedef _Atomic(unsigned short) atomic_ushort;
279 typedef _Atomic(int) atomic_int;
280 typedef _Atomic(unsigned int) atomic_uint;
281 typedef _Atomic(long) atomic_long;
282 typedef _Atomic(unsigned long) atomic_ulong;
283 typedef _Atomic(long long) atomic_llong;
284 typedef _Atomic(unsigned long long) atomic_ullong;
285 typedef _Atomic(char16_t) atomic_char16_t;
286 typedef _Atomic(char32_t) atomic_char32_t;
287 typedef _Atomic(wchar_t) atomic_wchar_t;
288 typedef _Atomic(int_least8_t) atomic_int_least8_t;
289 typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
290 typedef _Atomic(int_least16_t) atomic_int_least16_t;
291 typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
292 typedef _Atomic(int_least32_t) atomic_int_least32_t;
293 typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
294 typedef _Atomic(int_least64_t) atomic_int_least64_t;
295 typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
296 typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
297 typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
298 typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
299 typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
300 typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
301 typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
302 typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
303 typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
304 typedef _Atomic(intptr_t) atomic_intptr_t;
305 typedef _Atomic(uintptr_t) atomic_uintptr_t;
306 typedef _Atomic(size_t) atomic_size_t;
307 typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
308 typedef _Atomic(intmax_t) atomic_intmax_t;
309 typedef _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
584 extern "C" {
585 #endif
586 
593 LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(
594  volatile atomic_flag *object, memory_order order);
595 
600 LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set(
601  volatile atomic_flag *object);
602 
607 LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear_explicit(
608  volatile atomic_flag *object, memory_order order);
609 
614 LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear(volatile atomic_flag *object);
615 
616 inline 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 
629 inline 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 
642 inline ATOMIC_BOOL_TYPE
644  volatile atomic_flag *object, memory_order order)
645 {
646  return atomic_exchange_explicit(&object->_value_, 1, order);
647 }
648 
649 inline ATOMIC_BOOL_TYPE
651 {
653 }
654 
655 inline void
657 {
658  atomic_store_explicit(&object->_value_, 0, order);
659 }
660 
661 inline 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_
features.h
memory_order_relaxed
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:131
atomic_flag
An atomic type providing the classic test-and-set functionality.
Definition: stdatomic.h:198
atomic_store_explicit
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
Definition: stdatomic.h:325
atomic_signal_fence
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
atomic_flag_test_and_set
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
memory_order_release
@ memory_order_release
A store operation performs a release operation on the affected memory location.
Definition: stdatomic.h:158
atomic_exchange_explicit
#define atomic_exchange_explicit(object, desired, order)
Atomically replaces the value at object with desired.
Definition: stdatomic.h:368
memory_order_acquire
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:149
stdint.h
memory_order_consume
@ memory_order_consume
A load operation performs a consume operation on the affected memory location.
Definition: stdatomic.h:140
atomic_flag_test_and_set_explicit
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
stdatomic.h
atomic_thread_fence
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:617
memory_order_seq_cst
@ memory_order_seq_cst
Enforces a single total order on all affected locations.
Definition: stdatomic.h:174
memory_order
memory_order
An enumerated type identifying memory constraints.
Definition: stdatomic.h:126
atomic_flag_clear
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
uchar.h
atomic_flag_clear_explicit
void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order)
Atomically sets the value at object to false.
Definition: stdatomic.h:656
stddef.h
memory_order_acq_rel
@ memory_order_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
Definition: stdatomic.h:168