Lely core libraries  2.2.5
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
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 #else
45 #define __STDC_NO_ATOMICS__ 1
46 #endif
47 
48 #if !__STDC_NO_ATOMICS__
49 
50 #include <lely/libc/uchar.h>
51 
52 #include <stddef.h>
53 #include <stdint.h>
54 
55 #ifndef LELY_LIBC_STDATOMIC_INLINE
56 #define LELY_LIBC_STDATOMIC_INLINE static inline
57 #endif
58 
59 #ifdef __GCC_ATOMIC_BOOL_LOCK_FREE
60 #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
61 #else
62 #define ATOMIC_BOOL_LOCK_FREE 2
63 #endif
64 
65 #ifdef __GCC_ATOMIC_CHAR_LOCK_FREE
66 #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
67 #else
68 #define ATOMIC_CHAR_LOCK_FREE 1
69 #endif
70 
71 #ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE
72 #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
73 #else
74 #define ATOMIC_CHAR16_T_LOCK_FREE 1
75 #endif
76 
77 #ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE
78 #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
79 #else
80 #define ATOMIC_CHAR32_T_LOCK_FREE 1
81 #endif
82 
83 #ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE
84 #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
85 #else
86 #define ATOMIC_WCHAR_T_LOCK_FREE 1
87 #endif
88 
89 #ifdef __GCC_ATOMIC_SHORT_LOCK_FREE
90 #define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
91 #else
92 #define ATOMIC_SHORT_LOCK_FREE 1
93 #endif
94 
95 #ifdef __GCC_ATOMIC_INT_LOCK_FREE
96 #define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
97 #else
98 #define ATOMIC_INT_LOCK_FREE 1
99 #endif
100 
101 #ifdef __GCC_ATOMIC_LONG_LOCK_FREE
102 #define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
103 #else
104 #define ATOMIC_LONG_LOCK_FREE 1
105 #endif
106 
107 #ifdef __GCC_ATOMIC_LLONG_LOCK_FREE
108 #define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
109 #else
110 #define ATOMIC_LLONG_LOCK_FREE 1
111 #endif
112 
113 #ifdef __GCC_ATOMIC_POINTER_LOCK_FREE
114 #define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
115 #else
116 #define ATOMIC_POINTER_LOCK_FREE 1
117 #endif
118 
122 #define ATOMIC_FLAG_INIT \
123  { \
124  ATOMIC_VAR_INIT(0) \
125  }
126 
128 typedef enum {
130 #ifdef __ATOMIC_RELAXED
131  memory_order_relaxed = __ATOMIC_RELAXED,
132 #else
133  memory_order_relaxed = 0,
134 #endif
135 
139 #ifdef __ATOMIC_CONSUME
140  memory_order_consume = __ATOMIC_CONSUME,
141 #else
142  memory_order_consume = 1,
143 #endif
144 
148 #ifdef __ATOMIC_ACQUIRE
149  memory_order_acquire = __ATOMIC_ACQUIRE,
150 #else
151  memory_order_acquire = 2,
152 #endif
153 
157 #ifdef __ATOMIC_RELEASE
158  memory_order_release = __ATOMIC_RELEASE,
159 #else
160  memory_order_release = 3,
161 #endif
162 
167 #ifdef __ATOMIC_ACQ_REL
168  memory_order_acq_rel = __ATOMIC_ACQ_REL,
169 #else
170  memory_order_acq_rel = 4,
171 #endif
172 #ifdef __ATOMIC_SEQ_CST
174  memory_order_seq_cst = __ATOMIC_SEQ_CST
175 #else
176  memory_order_seq_cst = 5,
177 #endif
178 } memory_order;
179 
180 #ifndef LELY_HAVE_CLANG_ATOMIC
181 #undef _Atomic
182 #define _Atomic(T) struct { T volatile _value_; }
183 #endif
184 
185 #ifndef ATOMIC_BOOL_TYPE
186 #ifdef __cplusplus
187 #define ATOMIC_BOOL_TYPE bool
188 #else
189 #define ATOMIC_BOOL_TYPE _Bool
190 #endif
191 #endif
192 
197 typedef struct {
198  _Atomic(ATOMIC_BOOL_TYPE) _value_;
199 } atomic_flag;
200 
205 #if LELY_HAVE_CLANG_ATOMIC
206 #define ATOMIC_VAR_INIT(value) (value)
207 #else
208 #define ATOMIC_VAR_INIT(value) \
209  { \
210  (value) \
211  }
212 #endif
213 
218 #if LELY_HAVE_CLANG_ATOMIC
219 #define atomic_init(obj, value) __c11_atomic_init(obj, value)
220 #else
221 #define atomic_init(obj, value) \
222  atomic_store_explicit(obj, value, memory_order_relaxed)
223 #endif
224 
229 #if defined(__GNUC__) || (__clang__)
230 #define kill_dependency(y) \
231  __extension__({ \
232  __typeof__(y) _tmp_ = (y); \
233  _tmp_; \
234  })
235 #else
236 #define kill_dependency(y)
237 #endif
238 
239 #ifdef __cplusplus
240 extern "C" {
241 #endif
242 
244 LELY_LIBC_STDATOMIC_INLINE void atomic_thread_fence(memory_order order);
245 
251 LELY_LIBC_STDATOMIC_INLINE void atomic_signal_fence(memory_order order);
252 
253 #ifdef __cplusplus
254 }
255 #endif
256 
263 #if LELY_HAVE_CLANG_ATOMIC
264 #define atomic_is_lock_free(obj) (__c11_atomic_is_lock_free(sizeof(*(obj))))
265 #elif LELY_HAVE_GNUC_ATOMIC
266 #define atomic_is_lock_free(obj) \
267  (__atomic_is_lock_free(sizeof((obj)->_value_), &(obj)->_value_))
268 #else
269 #define atomic_is_lock_free(obj) (sizeof((obj)->_value_) <= sizeof(void *))
270 #endif
271 
272 typedef _Atomic(ATOMIC_BOOL_TYPE) atomic_bool;
273 typedef _Atomic(char) atomic_char;
274 typedef _Atomic(signed char) atomic_schar;
275 typedef _Atomic(unsigned char) atomic_uchar;
276 typedef _Atomic(short) atomic_short;
277 typedef _Atomic(unsigned short) atomic_ushort;
278 typedef _Atomic(int) atomic_int;
279 typedef _Atomic(unsigned int) atomic_uint;
280 typedef _Atomic(long) atomic_long;
281 typedef _Atomic(unsigned long) atomic_ulong;
282 typedef _Atomic(long long) atomic_llong;
283 typedef _Atomic(unsigned long long) atomic_ullong;
284 typedef _Atomic(char16_t) atomic_char16_t;
285 typedef _Atomic(char32_t) atomic_char32_t;
286 typedef _Atomic(wchar_t) atomic_wchar_t;
287 typedef _Atomic(int_least8_t) atomic_int_least8_t;
288 typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
289 typedef _Atomic(int_least16_t) atomic_int_least16_t;
290 typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
291 typedef _Atomic(int_least32_t) atomic_int_least32_t;
292 typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
293 typedef _Atomic(int_least64_t) atomic_int_least64_t;
294 typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
295 typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
296 typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
297 typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
298 typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
299 typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
300 typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
301 typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
302 typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
303 typedef _Atomic(intptr_t) atomic_intptr_t;
304 typedef _Atomic(uintptr_t) atomic_uintptr_t;
305 typedef _Atomic(size_t) atomic_size_t;
306 typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
307 typedef _Atomic(intmax_t) atomic_intmax_t;
308 typedef _Atomic(uintmax_t) atomic_uintmax_t;
309 
313 #define atomic_store(object, desired) \
314  (atomic_store_explicit((object), (desired), memory_order_seq_cst))
315 
320 #if LELY_HAVE_CLANG_ATOMIC
321 #define atomic_store_explicit(object, desired, order) \
322  (__c11_atomic_store((object), (desired), (order)))
323 #elif LELY_HAVE_GNUC_ATOMIC
324 #define atomic_store_explicit(object, desired, order) \
325  (__atomic_store_n(&(object)->_value_, (desired), (order)))
326 #else
327 #define atomic_store_explicit(object, desired, order) \
328  ((void)atomic_exchange_explicit((object), (desired), (order)))
329 #endif
330 
332 #define atomic_load(object) \
333  (atomic_load_explicit((object), memory_order_seq_cst))
334 
339 #if LELY_HAVE_CLANG_ATOMIC
340 #define atomic_load_explicit(object, order) \
341  (__c11_atomic_load((object), (order)))
342 #elif LELY_HAVE_GNUC_ATOMIC
343 #define atomic_load_explicit(object, order) \
344  (__atomic_load_n(&(object)->_value_, (order)))
345 #elif LELY_HAVE_SYNC_ATOMIC
346 #define atomic_load_explicit(object, order) \
347  ((void)(order), __sync_fetch_and_add(&(object)->_value_, 0))
348 #endif
349 
354 #define atomic_exchange(object, desired) \
355  (atomic_exchange_explicit((object), (desired), memory_order_seq_cst))
356 
363 #if LELY_HAVE_CLANG_ATOMIC
364 #define atomic_exchange_explicit(object, desired, order) \
365  (__c11_atomic_exchange((object), (desired), (order)))
366 #elif LELY_HAVE_GNUC_ATOMIC
367 #define atomic_exchange_explicit(object, desired, order) \
368  (__atomic_exchange_n(&(object)->_value_, (desired), (order)))
369 #elif LELY_HAVE_SYNC_ATOMIC
370 #define atomic_exchange_explicit(object, desired, order) \
371  __extension__({ \
372  __typeof__(object) __object = (object); \
373  __typeof__(desired) __desired = (desired); \
374  atomic_thread_fence(order); \
375  __sync_lock_test_and_set(&(__object)->_value_, __desired); \
376  })
377 #endif
378 
383 #define atomic_compare_exchange_strong(object, expected, desired) \
384  (atomic_compare_exchange_strong_explicit((object), (expected), \
385  (desired), memory_order_seq_cst, \
386  memory_order_seq_cst))
387 
398 #if LELY_HAVE_CLANG_ATOMIC
399 #define atomic_compare_exchange_strong_explicit( \
400  object, expected, desired, success, failure) \
401  (__c11_atomic_compare_exchange_strong((object), (expected), (desired), \
402  (success), (failure)))
403 #elif LELY_HAVE_GNUC_ATOMIC
404 #define atomic_compare_exchange_strong_explicit( \
405  object, expected, desired, success, failure) \
406  (__atomic_compare_exchange_n(&(object)->_value_, (expected), \
407  (desired), 0, (success), (failure)))
408 #elif LELY_HAVE_SYNC_ATOMIC
409 // clang-format off
410 #define atomic_compare_exchange_strong_explicit(object, expected, desired, \
411  success, failure) \
412  __extension__({ \
413  (void)(success); \
414  (void)(failure); \
415  __typeof__(*(expected)) _expected_ = *(expected); \
416  (ATOMIC_BOOL_TYPE)((*(expected) = __sync_val_compare_and_swap( \
417  &(object)->_value_, _expected_, (desired))) \
418  == _expected_); \
419  })
420 // clang-format on
421 #endif
422 
427 #define atomic_compare_exchange_weak(object, expected, desired) \
428  (atomic_compare_exchange_weak_explicit((object), (expected), \
429  (desired), memory_order_seq_cst, \
430  memory_order_seq_cst))
431 
445 #if LELY_HAVE_CLANG_ATOMIC
446 #define atomic_compare_exchange_weak_explicit( \
447  object, expected, desired, success, failure) \
448  (__c11_atomic_compare_exchange_weak((object), (expected), (desired), \
449  (success), (failure)))
450 #elif LELY_HAVE_GNUC_ATOMIC
451 #define atomic_compare_exchange_weak_explicit( \
452  object, expected, desired, success, failure) \
453  (__atomic_compare_exchange_n(&(object)->_value_, (expected), \
454  (desired), 1, (success), (failure)))
455 #else
456 #define atomic_compare_exchange_weak_explicit( \
457  object, expected, desired, success, failure) \
458  (atomic_compare_exchange_strong_explicit((object), (expected), \
459  (desired), (success), (failure)))
460 #endif
461 
466 #define atomic_fetch_add(object, operand) \
467  (atomic_fetch_add_explicit((object), (operand), memory_order_seq_cst))
468 
475 #if LELY_HAVE_CLANG_ATOMIC
476 #define atomic_fetch_add_explicit(object, operand, order) \
477  (__c11_atomic_fetch_add((object), (operand), (order)))
478 #elif LELY_HAVE_GNUC_ATOMIC
479 #define atomic_fetch_add_explicit(object, operand, order) \
480  (__atomic_fetch_add(&(object)->_value_, (operand), (order)))
481 #elif LELY_HAVE_SYNC_ATOMIC
482 #define atomic_fetch_add_explicit(object, operand, order) \
483  ((void)(order), __sync_fetch_and_add(&(object)->_value_, (operand)))
484 #endif
485 
490 #define atomic_fetch_sub(object, operand) \
491  (atomic_fetch_sub_explicit((object), (operand), memory_order_seq_cst))
492 
499 #if LELY_HAVE_CLANG_ATOMIC
500 #define atomic_fetch_sub_explicit(object, operand, order) \
501  (__c11_atomic_fetch_sub((object), (operand), (order)))
502 #elif LELY_HAVE_GNUC_ATOMIC
503 #define atomic_fetch_sub_explicit(object, operand, order) \
504  (__atomic_fetch_sub(&(object)->_value_, (operand), (order)))
505 #elif LELY_HAVE_SYNC_ATOMIC
506 #define atomic_fetch_sub_explicit(object, operand, order) \
507  ((void)(order), __sync_fetch_and_sub(&(object)->_value_, (operand)))
508 #endif
509 
514 #define atomic_fetch_or(object, operand) \
515  (atomic_fetch_or_explicit((object), (operand), memory_order_seq_cst))
516 
523 #if LELY_HAVE_CLANG_ATOMIC
524 #define atomic_fetch_or_explicit(object, operand, order) \
525  (__c11_atomic_fetch_or((object), (operand), (order)))
526 #elif LELY_HAVE_GNUC_ATOMIC
527 #define atomic_fetch_or_explicit(object, operand, order) \
528  (__atomic_fetch_or(&(object)->_value_, (operand), (order)))
529 #elif LELY_HAVE_SYNC_ATOMIC
530 #define atomic_fetch_or_explicit(object, operand, order) \
531  ((void)(order), __sync_fetch_and_or(&(object)->_value_, (operand)))
532 #endif
533 
538 #define atomic_fetch_xor(object, operand) \
539  (atomic_fetch_xor_explicit((object), (operand), memory_order_seq_cst))
540 
547 #if LELY_HAVE_CLANG_ATOMIC
548 #define atomic_fetch_xor_explicit(object, operand, order) \
549  (__c11_atomic_fetch_xor((object), (operand), (order)))
550 #elif LELY_HAVE_GNUC_ATOMIC
551 #define atomic_fetch_xor_explicit(object, operand, order) \
552  (__atomic_fetch_xor(&(object)->_value_, (operand), (order)))
553 #elif LELY_HAVE_SYNC_ATOMIC
554 #define atomic_fetch_xor_explicit(object, operand, order) \
555  ((void)(order), __sync_fetch_and_xor(&(object)->_value_, (operand)))
556 #endif
557 
562 #define atomic_fetch_and(object, operand) \
563  (atomic_fetch_and_explicit((object), (operand), memory_order_seq_cst))
564 
571 #if LELY_HAVE_CLANG_ATOMIC
572 #define atomic_fetch_and_explicit(object, operand, order) \
573  (__c11_atomic_fetch_and((object), (operand), (order)))
574 #elif LELY_HAVE_GNUC_ATOMIC
575 #define atomic_fetch_and_explicit(object, operand, order) \
576  (__atomic_fetch_and(&(object)->_value_, (operand), (order)))
577 #elif LELY_HAVE_SYNC_ATOMIC
578 #define atomic_fetch_and_explicit(object, operand, order) \
579  ((void)(order), __sync_fetch_and_and(&(object)->_value_, (operand)))
580 #endif
581 
582 #ifdef __cplusplus
583 extern "C" {
584 #endif
585 
592 LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(
593  volatile atomic_flag *object, memory_order order);
594 
599 LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set(
600  volatile atomic_flag *object);
601 
606 LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear_explicit(
607  volatile atomic_flag *object, memory_order order);
608 
613 LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear(volatile atomic_flag *object);
614 
615 inline void
616 atomic_thread_fence(memory_order order)
617 {
618 #if LELY_HAVE_CLANG_ATOMIC
619  __c11_atomic_thread_fence(order);
620 #elif LELY_HAVE_GNUC_ATOMIC
621  __atomic_thread_fence(order);
622 #elif LELY_HAVE_SYNC_ATOMIC
623  if (order != memory_order_relaxed)
624  __sync_synchronize();
625 #endif
626 }
627 
628 inline void
629 atomic_signal_fence(memory_order order)
630 {
631 #if LELY_HAVE_CLANG_ATOMIC
632  __c11_atomic_signal_fence(order);
633 #elif LELY_HAVE_GNUC_ATOMIC
634  __atomic_signal_fence(order);
635 #elif defined(__GNUC__)
636  if (order != memory_order_relaxed)
637  __asm volatile("" ::: "memory");
638 #endif
639 }
640 
641 inline ATOMIC_BOOL_TYPE
642 atomic_flag_test_and_set_explicit(
643  volatile atomic_flag *object, memory_order order)
644 {
645  return atomic_exchange_explicit(&object->_value_, 1, order);
646 }
647 
648 inline ATOMIC_BOOL_TYPE
649 atomic_flag_test_and_set(volatile atomic_flag *object)
650 {
651  return atomic_flag_test_and_set_explicit(object, memory_order_seq_cst);
652 }
653 
654 inline void
655 atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order)
656 {
657  atomic_store_explicit(&object->_value_, 0, order);
658 }
659 
660 inline void
661 atomic_flag_clear(volatile atomic_flag *object)
662 {
663  atomic_flag_test_and_set_explicit(object, memory_order_seq_cst);
664 }
665 
666 #ifdef __cplusplus
667 }
668 #endif
669 
670 #endif // !__STDC_NO_ATOMICS__
671 
672 #endif // !LELY_HAVE_STDATOMIC_H
673 
674 #endif // !LELY_LIBC_STDATOMIC_H_
features.h
stdint.h
stdatomic.h
uchar.h
stddef.h