xref: /third_party/elfutils/lib/stdatomic-fbsd.h (revision da0c48c4)
1/*-
2 * Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
3 *                    David Chisnall <theraven@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30#ifndef _STDATOMIC_H_
31#define	_STDATOMIC_H_
32
33#include <stddef.h>
34#include <stdint.h>
35
36#if !defined(__has_feature)
37#define __has_feature(x) 0
38#endif
39#if !defined(__has_builtin)
40#define __has_builtin(x) 0
41#endif
42#if !defined(__GNUC_PREREQ__)
43#if defined(__GNUC__) && defined(__GNUC_MINOR__)
44#define __GNUC_PREREQ__(maj, min)					\
45	((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
46#else
47#define __GNUC_PREREQ__(maj, min) 0
48#endif
49#endif
50
51#if !defined(__CLANG_ATOMICS) && !defined(__GNUC_ATOMICS)
52#if __has_feature(c_atomic)
53#define	__CLANG_ATOMICS
54#elif __GNUC_PREREQ__(4, 7)
55#define	__GNUC_ATOMICS
56#elif !defined(__GNUC__)
57#error "stdatomic.h does not support your compiler"
58#endif
59#endif
60
61/*
62 * language independent type to represent a Boolean value
63 */
64
65typedef int __Bool;
66
67/*
68 * 7.17.1 Atomic lock-free macros.
69 */
70
71#ifdef __GCC_ATOMIC_BOOL_LOCK_FREE
72#define	ATOMIC_BOOL_LOCK_FREE		__GCC_ATOMIC_BOOL_LOCK_FREE
73#endif
74#ifdef __GCC_ATOMIC_CHAR_LOCK_FREE
75#define	ATOMIC_CHAR_LOCK_FREE		__GCC_ATOMIC_CHAR_LOCK_FREE
76#endif
77#ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE
78#define	ATOMIC_CHAR16_T_LOCK_FREE	__GCC_ATOMIC_CHAR16_T_LOCK_FREE
79#endif
80#ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE
81#define	ATOMIC_CHAR32_T_LOCK_FREE	__GCC_ATOMIC_CHAR32_T_LOCK_FREE
82#endif
83#ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE
84#define	ATOMIC_WCHAR_T_LOCK_FREE	__GCC_ATOMIC_WCHAR_T_LOCK_FREE
85#endif
86#ifdef __GCC_ATOMIC_SHORT_LOCK_FREE
87#define	ATOMIC_SHORT_LOCK_FREE		__GCC_ATOMIC_SHORT_LOCK_FREE
88#endif
89#ifdef __GCC_ATOMIC_INT_LOCK_FREE
90#define	ATOMIC_INT_LOCK_FREE		__GCC_ATOMIC_INT_LOCK_FREE
91#endif
92#ifdef __GCC_ATOMIC_LONG_LOCK_FREE
93#define	ATOMIC_LONG_LOCK_FREE		__GCC_ATOMIC_LONG_LOCK_FREE
94#endif
95#ifdef __GCC_ATOMIC_LLONG_LOCK_FREE
96#define	ATOMIC_LLONG_LOCK_FREE		__GCC_ATOMIC_LLONG_LOCK_FREE
97#endif
98#ifdef __GCC_ATOMIC_POINTER_LOCK_FREE
99#define	ATOMIC_POINTER_LOCK_FREE	__GCC_ATOMIC_POINTER_LOCK_FREE
100#endif
101
102#if !defined(__CLANG_ATOMICS)
103#define	_Atomic(T)			struct { volatile __typeof__(T) __val; }
104#endif
105
106/*
107 * 7.17.2 Initialization.
108 */
109
110#if defined(__CLANG_ATOMICS)
111#define	ATOMIC_VAR_INIT(value)		(value)
112#define	atomic_init(obj, value)		__c11_atomic_init(obj, value)
113#else
114#define	ATOMIC_VAR_INIT(value)		{ .__val = (value) }
115#define	atomic_init(obj, value)		((void)((obj)->__val = (value)))
116#endif
117
118/*
119 * Clang and recent GCC both provide predefined macros for the memory
120 * orderings.  If we are using a compiler that doesn't define them, use the
121 * clang values - these will be ignored in the fallback path.
122 */
123
124#ifndef __ATOMIC_RELAXED
125#define __ATOMIC_RELAXED		0
126#endif
127#ifndef __ATOMIC_CONSUME
128#define __ATOMIC_CONSUME		1
129#endif
130#ifndef __ATOMIC_ACQUIRE
131#define __ATOMIC_ACQUIRE		2
132#endif
133#ifndef __ATOMIC_RELEASE
134#define __ATOMIC_RELEASE		3
135#endif
136#ifndef __ATOMIC_ACQ_REL
137#define __ATOMIC_ACQ_REL		4
138#endif
139#ifndef __ATOMIC_SEQ_CST
140#define __ATOMIC_SEQ_CST		5
141#endif
142
143/*
144 * 7.17.3 Order and consistency.
145 *
146 * The memory_order_* constants that denote the barrier behaviour of the
147 * atomic operations.
148 */
149
150typedef enum {
151    memory_order_relaxed = __ATOMIC_RELAXED,
152    memory_order_consume = __ATOMIC_CONSUME,
153    memory_order_acquire = __ATOMIC_ACQUIRE,
154    memory_order_release = __ATOMIC_RELEASE,
155    memory_order_acq_rel = __ATOMIC_ACQ_REL,
156    memory_order_seq_cst = __ATOMIC_SEQ_CST
157} memory_order;
158
159/*
160 * 7.17.4 Fences.
161 */
162
163//#define __unused
164
165//static __inline void
166//atomic_thread_fence(memory_order __order __unused)
167//{
168//
169//#ifdef __CLANG_ATOMICS
170//    __c11_atomic_thread_fence(__order);
171//#elif defined(__GNUC_ATOMICS)
172//    __atomic_thread_fence(__order);
173//#else
174//    __sync_synchronize();
175//#endif
176//}
177//
178//static __inline void
179//atomic_signal_fence(memory_order __order __unused)
180//{
181//
182//#ifdef __CLANG_ATOMICS
183//    __c11_atomic_signal_fence(__order);
184//#elif defined(__GNUC_ATOMICS)
185//    __atomic_signal_fence(__order);
186//#else
187//    __asm volatile ("" ::: "memory");
188//#endif
189//}
190
191//#undef __unused
192
193/*
194 * 7.17.5 Lock-free property.
195 */
196
197#if defined(_KERNEL)
198/* Atomics in kernelspace are always lock-free. */
199#define	atomic_is_lock_free(obj) \
200	((void)(obj), (__Bool)1)
201#elif defined(__CLANG_ATOMICS)
202#define	atomic_is_lock_free(obj) \
203	__atomic_is_lock_free(sizeof(*(obj)), obj)
204#elif defined(__GNUC_ATOMICS)
205#define	atomic_is_lock_free(obj) \
206	__atomic_is_lock_free(sizeof((obj)->__val), &(obj)->__val)
207#else
208#define	atomic_is_lock_free(obj) \
209	((void)(obj), sizeof((obj)->__val) <= sizeof(void *))
210#endif
211
212/*
213 * 7.17.6 Atomic integer types.
214 */
215
216typedef _Atomic(__Bool)			atomic_bool;
217typedef _Atomic(char)			atomic_char;
218typedef _Atomic(signed char)		atomic_schar;
219typedef _Atomic(unsigned char)		atomic_uchar;
220typedef _Atomic(short)			atomic_short;
221typedef _Atomic(unsigned short)		atomic_ushort;
222typedef _Atomic(int)			atomic_int;
223typedef _Atomic(unsigned int)		atomic_uint;
224typedef _Atomic(long)			atomic_long;
225typedef _Atomic(unsigned long)		atomic_ulong;
226typedef _Atomic(long long)		atomic_llong;
227typedef _Atomic(unsigned long long)	atomic_ullong;
228#if 0
229typedef _Atomic(char16_t)		atomic_char16_t;
230typedef _Atomic(char32_t)		atomic_char32_t;
231#endif
232typedef _Atomic(wchar_t)		atomic_wchar_t;
233typedef _Atomic(int_least8_t)		atomic_int_least8_t;
234typedef _Atomic(uint_least8_t)		atomic_uint_least8_t;
235typedef _Atomic(int_least16_t)		atomic_int_least16_t;
236typedef _Atomic(uint_least16_t)		atomic_uint_least16_t;
237typedef _Atomic(int_least32_t)		atomic_int_least32_t;
238typedef _Atomic(uint_least32_t)		atomic_uint_least32_t;
239typedef _Atomic(int_least64_t)		atomic_int_least64_t;
240typedef _Atomic(uint_least64_t)		atomic_uint_least64_t;
241typedef _Atomic(int_fast8_t)		atomic_int_fast8_t;
242typedef _Atomic(uint_fast8_t)		atomic_uint_fast8_t;
243typedef _Atomic(int_fast16_t)		atomic_int_fast16_t;
244typedef _Atomic(uint_fast16_t)		atomic_uint_fast16_t;
245typedef _Atomic(int_fast32_t)		atomic_int_fast32_t;
246typedef _Atomic(uint_fast32_t)		atomic_uint_fast32_t;
247typedef _Atomic(int_fast64_t)		atomic_int_fast64_t;
248typedef _Atomic(uint_fast64_t)		atomic_uint_fast64_t;
249typedef _Atomic(intptr_t)		atomic_intptr_t;
250typedef _Atomic(uintptr_t)		atomic_uintptr_t;
251typedef _Atomic(size_t)			atomic_size_t;
252typedef _Atomic(ptrdiff_t)		atomic_ptrdiff_t;
253typedef _Atomic(intmax_t)		atomic_intmax_t;
254typedef _Atomic(uintmax_t)		atomic_uintmax_t;
255
256/*
257 * 7.17.7 Operations on atomic types.
258 */
259
260/*
261 * Compiler-specific operations.
262 */
263
264#if defined(__CLANG_ATOMICS)
265#define	atomic_compare_exchange_strong_explicit(object, expected,	\
266    desired, success, failure)						\
267	__c11_atomic_compare_exchange_strong(object, expected, desired,	\
268	    success, failure)
269#define	atomic_compare_exchange_weak_explicit(object, expected,		\
270    desired, success, failure)						\
271	__c11_atomic_compare_exchange_weak(object, expected, desired,	\
272	    success, failure)
273#define	atomic_exchange_explicit(object, desired, order)		\
274	__c11_atomic_exchange(object, desired, order)
275#define	atomic_fetch_add_explicit(object, operand, order)		\
276	__c11_atomic_fetch_add(object, operand, order)
277#define	atomic_fetch_and_explicit(object, operand, order)		\
278	__c11_atomic_fetch_and(object, operand, order)
279#define	atomic_fetch_or_explicit(object, operand, order)		\
280	__c11_atomic_fetch_or(object, operand, order)
281#define	atomic_fetch_sub_explicit(object, operand, order)		\
282	__c11_atomic_fetch_sub(object, operand, order)
283#define	atomic_fetch_xor_explicit(object, operand, order)		\
284	__c11_atomic_fetch_xor(object, operand, order)
285#define	atomic_load_explicit(object, order)				\
286	__c11_atomic_load(object, order)
287#define	atomic_store_explicit(object, desired, order)			\
288	__c11_atomic_store(object, desired, order)
289#elif defined(__GNUC_ATOMICS)
290#define	atomic_compare_exchange_strong_explicit(object, expected,	\
291    desired, success, failure)						\
292	__atomic_compare_exchange_n(&(object)->__val, expected,		\
293	    desired, 0, success, failure)
294#define	atomic_compare_exchange_weak_explicit(object, expected,		\
295    desired, success, failure)						\
296	__atomic_compare_exchange_n(&(object)->__val, expected,		\
297	    desired, 1, success, failure)
298#define	atomic_exchange_explicit(object, desired, order)		\
299	__atomic_exchange_n(&(object)->__val, desired, order)
300#define	atomic_fetch_add_explicit(object, operand, order)		\
301	__atomic_fetch_add(&(object)->__val, operand, order)
302#define	atomic_fetch_and_explicit(object, operand, order)		\
303	__atomic_fetch_and(&(object)->__val, operand, order)
304#define	atomic_fetch_or_explicit(object, operand, order)		\
305	__atomic_fetch_or(&(object)->__val, operand, order)
306#define	atomic_fetch_sub_explicit(object, operand, order)		\
307	__atomic_fetch_sub(&(object)->__val, operand, order)
308#define	atomic_fetch_xor_explicit(object, operand, order)		\
309	__atomic_fetch_xor(&(object)->__val, operand, order)
310#define	atomic_load_explicit(object, order)				\
311	__atomic_load_n(&(object)->__val, order)
312#define	atomic_store_explicit(object, desired, order)			\
313	__atomic_store_n(&(object)->__val, desired, order)
314#else
315#define	__atomic_apply_stride(object, operand) \
316	(((__typeof__((object)->__val))0) + (operand))
317#define	atomic_compare_exchange_strong_explicit(object, expected,	\
318    desired, success, failure)	__extension__ ({			\
319	__typeof__(expected) __ep = (expected);				\
320	__typeof__(*__ep) __e = *__ep;					\
321	(void)(success); (void)(failure);				\
322	(__Bool)((*__ep = __sync_val_compare_and_swap(&(object)->__val,	\
323	    __e, desired)) == __e);					\
324})
325#define	atomic_compare_exchange_weak_explicit(object, expected,		\
326    desired, success, failure)						\
327	atomic_compare_exchange_strong_explicit(object, expected,	\
328		desired, success, failure)
329#if __has_builtin(__sync_swap)
330/* Clang provides a full-barrier atomic exchange - use it if available. */
331#define	atomic_exchange_explicit(object, desired, order)		\
332	((void)(order), __sync_swap(&(object)->__val, desired))
333#else
334/*
335 * __sync_lock_test_and_set() is only an acquire barrier in theory (although in
336 * practice it is usually a full barrier) so we need an explicit barrier before
337 * it.
338 */
339#define	atomic_exchange_explicit(object, desired, order)		\
340__extension__ ({							\
341	__typeof__(object) __o = (object);				\
342	__typeof__(desired) __d = (desired);				\
343	(void)(order);							\
344	__sync_synchronize();						\
345	__sync_lock_test_and_set(&(__o)->__val, __d);			\
346})
347#endif
348#define	atomic_fetch_add_explicit(object, operand, order)		\
349	((void)(order), __sync_fetch_and_add(&(object)->__val,		\
350	    __atomic_apply_stride(object, operand)))
351#define	atomic_fetch_and_explicit(object, operand, order)		\
352	((void)(order), __sync_fetch_and_and(&(object)->__val, operand))
353#define	atomic_fetch_or_explicit(object, operand, order)		\
354	((void)(order), __sync_fetch_and_or(&(object)->__val, operand))
355#define	atomic_fetch_sub_explicit(object, operand, order)		\
356	((void)(order), __sync_fetch_and_sub(&(object)->__val,		\
357	    __atomic_apply_stride(object, operand)))
358#define	atomic_fetch_xor_explicit(object, operand, order)		\
359	((void)(order), __sync_fetch_and_xor(&(object)->__val, operand))
360#define	atomic_load_explicit(object, order)				\
361	((void)(order), __sync_fetch_and_add(&(object)->__val, 0))
362#define	atomic_store_explicit(object, desired, order)			\
363	((void)atomic_exchange_explicit(object, desired, order))
364#endif
365
366/*
367 * Convenience functions.
368 *
369 * Don't provide these in kernel space. In kernel space, we should be
370 * disciplined enough to always provide explicit barriers.
371 */
372
373#ifndef _KERNEL
374#define	atomic_compare_exchange_strong(object, expected, desired)	\
375	atomic_compare_exchange_strong_explicit(object, expected,	\
376	    desired, memory_order_seq_cst, memory_order_seq_cst)
377#define	atomic_compare_exchange_weak(object, expected, desired)		\
378	atomic_compare_exchange_weak_explicit(object, expected,		\
379	    desired, memory_order_seq_cst, memory_order_seq_cst)
380#define	atomic_exchange(object, desired)				\
381	atomic_exchange_explicit(object, desired, memory_order_seq_cst)
382#define	atomic_fetch_add(object, operand)				\
383	atomic_fetch_add_explicit(object, operand, memory_order_seq_cst)
384#define	atomic_fetch_and(object, operand)				\
385	atomic_fetch_and_explicit(object, operand, memory_order_seq_cst)
386#define	atomic_fetch_or(object, operand)				\
387	atomic_fetch_or_explicit(object, operand, memory_order_seq_cst)
388#define	atomic_fetch_sub(object, operand)				\
389	atomic_fetch_sub_explicit(object, operand, memory_order_seq_cst)
390#define	atomic_fetch_xor(object, operand)				\
391	atomic_fetch_xor_explicit(object, operand, memory_order_seq_cst)
392#define	atomic_load(object)						\
393	atomic_load_explicit(object, memory_order_seq_cst)
394#define	atomic_store(object, desired)					\
395	atomic_store_explicit(object, desired, memory_order_seq_cst)
396#endif /* !_KERNEL */
397
398/*
399 * 7.17.8 Atomic flag type and operations.
400 *
401 * XXX: Assume atomic_bool can be used as an atomic_flag. Is there some
402 * kind of compiler built-in type we could use?
403 */
404
405typedef struct {
406    atomic_bool	__flag;
407} atomic_flag;
408
409#define	ATOMIC_FLAG_INIT		{ ATOMIC_VAR_INIT(0) }
410
411static __inline __Bool
412atomic_flag_test_and_set_explicit(volatile atomic_flag *__object,
413                                  memory_order __order)
414{
415    return (atomic_exchange_explicit(&__object->__flag, 1, __order));
416}
417
418static __inline void
419atomic_flag_clear_explicit(volatile atomic_flag *__object, memory_order __order)
420{
421
422    atomic_store_explicit(&__object->__flag, 0, __order);
423}
424
425#ifndef _KERNEL
426static __inline __Bool
427atomic_flag_test_and_set(volatile atomic_flag *__object)
428{
429
430    return (atomic_flag_test_and_set_explicit(__object,
431                                              memory_order_seq_cst));
432}
433
434static __inline void
435atomic_flag_clear(volatile atomic_flag *__object)
436{
437
438    atomic_flag_clear_explicit(__object, memory_order_seq_cst);
439}
440#endif /* !_KERNEL */
441
442#endif /* !_STDATOMIC_H_ */