xref: /freebsd/contrib/libcxxrt/atomic.h (revision bfffb66e)
1f7cb1657SDavid Chisnall 
2f7cb1657SDavid Chisnall #ifndef __has_builtin
3f7cb1657SDavid Chisnall #	define __has_builtin(x) 0
4f7cb1657SDavid Chisnall #endif
5f7cb1657SDavid Chisnall #ifndef __has_feature
6f7cb1657SDavid Chisnall #	define __has_feature(x) 0
7f7cb1657SDavid Chisnall #endif
8bfffb66eSDimitry Andric #ifndef __has_extension
9bfffb66eSDimitry Andric #	define __has_extension(x) 0
10bfffb66eSDimitry Andric #endif
11bfffb66eSDimitry Andric 
12bfffb66eSDimitry Andric #if !__has_extension(c_atomic)
13bfffb66eSDimitry Andric #	define _Atomic(T) T
14bfffb66eSDimitry Andric #endif
15d9e22925SDimitry Andric #if __has_builtin(__c11_atomic_exchange)
16bfffb66eSDimitry Andric #	define ATOMIC_BUILTIN(name) __c11_atomic_##name
17f7cb1657SDavid Chisnall #else
18bfffb66eSDimitry Andric #	define ATOMIC_BUILTIN(name) __atomic_##name##_n
19f7cb1657SDavid Chisnall #endif
20f7cb1657SDavid Chisnall 
21bfffb66eSDimitry Andric namespace
22bfffb66eSDimitry Andric {
23bfffb66eSDimitry Andric 	/**
24bfffb66eSDimitry Andric 	 * C++11 memory orders.  We only need a subset of them.
25bfffb66eSDimitry Andric 	 */
26bfffb66eSDimitry Andric 	enum memory_order
27bfffb66eSDimitry Andric 	{
28bfffb66eSDimitry Andric 		/**
29bfffb66eSDimitry Andric 		 * Acquire order.
30bfffb66eSDimitry Andric 		 */
31bfffb66eSDimitry Andric 		acquire = __ATOMIC_ACQUIRE,
3225482379SDimitry Andric 
33bfffb66eSDimitry Andric 		/**
34bfffb66eSDimitry Andric 		 * Release order.
35bfffb66eSDimitry Andric 		 */
36bfffb66eSDimitry Andric 		release = __ATOMIC_RELEASE,
37bfffb66eSDimitry Andric 
38bfffb66eSDimitry Andric 		/**
39bfffb66eSDimitry Andric 		 * Sequentially consistent memory ordering.
40bfffb66eSDimitry Andric 		 */
41bfffb66eSDimitry Andric 		seqcst = __ATOMIC_SEQ_CST
42bfffb66eSDimitry Andric 	};
43bfffb66eSDimitry Andric 
44bfffb66eSDimitry Andric 	/**
45bfffb66eSDimitry Andric 	 * Atomic, implements a subset of `std::atomic`.
46bfffb66eSDimitry Andric 	 */
47bfffb66eSDimitry Andric 	template<typename T>
48bfffb66eSDimitry Andric 	class atomic
49bfffb66eSDimitry Andric 	{
50bfffb66eSDimitry Andric 		/**
51bfffb66eSDimitry Andric 		 * The underlying value.  Use C11 atomic qualification if available.
52bfffb66eSDimitry Andric 		 */
53bfffb66eSDimitry Andric 		_Atomic(T) val;
54bfffb66eSDimitry Andric 
55bfffb66eSDimitry Andric 		public:
56bfffb66eSDimitry Andric 		/**
57bfffb66eSDimitry Andric 		 * Constructor, takes a value.
58bfffb66eSDimitry Andric 		 */
atomic(T init)59bfffb66eSDimitry Andric 		atomic(T init) : val(init) {}
60bfffb66eSDimitry Andric 
61bfffb66eSDimitry Andric 		/**
62bfffb66eSDimitry Andric 		 * Atomically load with the specified memory order.
63bfffb66eSDimitry Andric 		 */
64bfffb66eSDimitry Andric 		T load(memory_order order = memory_order::seqcst)
65bfffb66eSDimitry Andric 		{
66bfffb66eSDimitry Andric 			return ATOMIC_BUILTIN(load)(&val, order);
67bfffb66eSDimitry Andric 		}
68bfffb66eSDimitry Andric 
69bfffb66eSDimitry Andric 		/**
70bfffb66eSDimitry Andric 		 * Atomically store with the specified memory order.
71bfffb66eSDimitry Andric 		 */
72bfffb66eSDimitry Andric 		void store(T v, memory_order order = memory_order::seqcst)
73bfffb66eSDimitry Andric 		{
74bfffb66eSDimitry Andric 			return ATOMIC_BUILTIN(store)(&val, v, order);
75bfffb66eSDimitry Andric 		}
76bfffb66eSDimitry Andric 
77bfffb66eSDimitry Andric 		/**
78bfffb66eSDimitry Andric 		 * Atomically exchange with the specified memory order.
79bfffb66eSDimitry Andric 		 */
80bfffb66eSDimitry Andric 		T exchange(T v, memory_order order = memory_order::seqcst)
81bfffb66eSDimitry Andric 		{
82bfffb66eSDimitry Andric 			return ATOMIC_BUILTIN(exchange)(&val, v, order);
83bfffb66eSDimitry Andric 		}
84bfffb66eSDimitry Andric 
85bfffb66eSDimitry Andric 		/**
86bfffb66eSDimitry Andric 		 * Atomically exchange with the specified memory order.
87bfffb66eSDimitry Andric 		 */
88bfffb66eSDimitry Andric 		bool compare_exchange(T &          expected,
89bfffb66eSDimitry Andric 		                      T            desired,
90bfffb66eSDimitry Andric 		                      memory_order order = memory_order::seqcst)
91bfffb66eSDimitry Andric 		{
92bfffb66eSDimitry Andric #if __has_builtin(__c11_atomic_compare_exchange_strong)
93bfffb66eSDimitry Andric 			return __c11_atomic_compare_exchange_strong(
94bfffb66eSDimitry Andric 			  &val, &expected, desired, order, order);
95bfffb66eSDimitry Andric #else
96bfffb66eSDimitry Andric 			return __atomic_compare_exchange_n(
97bfffb66eSDimitry Andric 			  &val, &expected, desired, true, order, order);
98bfffb66eSDimitry Andric #endif
99bfffb66eSDimitry Andric 		}
100bfffb66eSDimitry Andric 	};
101bfffb66eSDimitry Andric } // namespace
102bfffb66eSDimitry Andric #undef ATOMIC_BUILTIN
103