Lely core libraries 1.9.2
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
128typedef enum {
130#ifdef __ATOMIC_RELAXED
131 memory_order_relaxed = __ATOMIC_RELAXED,
132#else
134#endif
139#ifdef __ATOMIC_CONSUME
140 memory_order_consume = __ATOMIC_CONSUME,
141#else
143#endif
148#ifdef __ATOMIC_ACQUIRE
149 memory_order_acquire = __ATOMIC_ACQUIRE,
150#else
152#endif
157#ifdef __ATOMIC_RELEASE
158 memory_order_release = __ATOMIC_RELEASE,
159#else
161#endif
167#ifdef __ATOMIC_ACQ_REL
168 memory_order_acq_rel = __ATOMIC_ACQ_REL,
169#else
171#endif
173#ifdef __ATOMIC_SEQ_CST
174 memory_order_seq_cst = __ATOMIC_SEQ_CST
175#else
177#endif
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
197typedef struct {
198 _Atomic(ATOMIC_BOOL_TYPE) _value_;
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
240extern "C" {
241#endif
242
244LELY_LIBC_STDATOMIC_INLINE void atomic_thread_fence(memory_order order);
245
251LELY_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
272typedef _Atomic(ATOMIC_BOOL_TYPE) atomic_bool;
273typedef _Atomic(char) atomic_char;
274typedef _Atomic(signed char) atomic_schar;
275typedef _Atomic(unsigned char) atomic_uchar;
276typedef _Atomic(short) atomic_short;
277typedef _Atomic(unsigned short) atomic_ushort;
278typedef _Atomic(int) atomic_int;
279typedef _Atomic(unsigned int) atomic_uint;
280typedef _Atomic(long) atomic_long;
281typedef _Atomic(unsigned long) atomic_ulong;
282typedef _Atomic(long long) atomic_llong;
283typedef _Atomic(unsigned long long) atomic_ullong;
284typedef _Atomic(char16_t) atomic_char16_t;
285typedef _Atomic(char32_t) atomic_char32_t;
286typedef _Atomic(wchar_t) atomic_wchar_t;
287typedef _Atomic(int_least8_t) atomic_int_least8_t;
288typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
289typedef _Atomic(int_least16_t) atomic_int_least16_t;
290typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
291typedef _Atomic(int_least32_t) atomic_int_least32_t;
292typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
293typedef _Atomic(int_least64_t) atomic_int_least64_t;
294typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
295typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
296typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
297typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
298typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
299typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
300typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
301typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
302typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
303typedef _Atomic(intptr_t) atomic_intptr_t;
304typedef _Atomic(uintptr_t) atomic_uintptr_t;
305typedef _Atomic(size_t) atomic_size_t;
306typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
307typedef _Atomic(intmax_t) atomic_intmax_t;
308typedef _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
583extern "C" {
584#endif
585
592LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(
593 volatile atomic_flag *object, memory_order order);
594
599LELY_LIBC_STDATOMIC_INLINE ATOMIC_BOOL_TYPE atomic_flag_test_and_set(
600 volatile atomic_flag *object);
601
606LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear_explicit(
607 volatile atomic_flag *object, memory_order order);
608
613LELY_LIBC_STDATOMIC_INLINE void atomic_flag_clear(volatile atomic_flag *object);
614
615inline void
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
628inline void
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
641inline ATOMIC_BOOL_TYPE
643 volatile atomic_flag *object, memory_order order)
644{
645 return atomic_exchange_explicit(&object->_value_, 1, order);
646}
647
648inline ATOMIC_BOOL_TYPE
650{
652}
653
654inline void
656{
657 atomic_store_explicit(&object->_value_, 0, order);
658}
659
660inline void
662{
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_
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:128
@ memory_order_consume
A load operation performs a consume operation on the affected memory location.
Definition: stdatomic.h:142
@ memory_order_seq_cst
Enforces a single total order on all affected locations.
Definition: stdatomic.h:176
@ memory_order_release
A store operation performs a release operation on the affected memory location.
Definition: stdatomic.h:160
@ memory_order_relaxed
No operation orders memory.
Definition: stdatomic.h:133
@ memory_order_acq_rel
A load operation performs an acquire operation on the affected memory location, and a store operation...
Definition: stdatomic.h:170
@ memory_order_acquire
A load operation performs an acquire operation on the affected memory location.
Definition: stdatomic.h:151
ATOMIC_BOOL_TYPE atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order)
Atomically replaces the value at object with *object & operand.
Definition: stdatomic.h:642
void atomic_flag_clear(volatile atomic_flag *object)
Equivalent to #atomic_flag_test_and_set_explicit(object, memory_order_seq_cst).
Definition: stdatomic.h:661
void atomic_signal_fence(memory_order order)
Equivalent to atomic_thread_fence(order), except that the resulting ordering constraints are establis...
Definition: stdatomic.h:629
void atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order)
Atomically sets the value at object to false.
Definition: stdatomic.h:655
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:649
void atomic_thread_fence(memory_order order)
Inserts a fence with semantics according to order.
Definition: stdatomic.h:616
#define atomic_store_explicit(object, desired, order)
Atomically replaces the value at object with the value of desired.
Definition: stdatomic.h:327
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:197
This header file is part of the C11 and POSIX compatibility library; it includes <uchar....