]> git.sesse.net Git - vlc/blob - include/vlc_atomic.h
Move vlc_atomic_t to <vlc_atomic.h> and correct definition
[vlc] / include / vlc_atomic.h
1 /*****************************************************************************
2  * vlc_atomic.h:
3  *****************************************************************************
4  * Copyright (C) 2010 RĂ©mi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifndef VLC_ATOMIC_H
22 # define VLC_ATOMIC_H
23
24 /**
25  * \file
26  * Atomic operations do not require locking, but they are not very powerful.
27  */
28
29 # if !defined (__cplusplus) && (__STDC_VERSION__ >= 201112L) \
30   && !defined (__STDC_NO_ATOMICS__)
31 #  include <stdatomic.h>
32
33 # else /* if (???) */
34
35 #  define ATOMIC_FLAG_INIT false
36
37 #  define ATOMIC_VAR_INIT(value) (value)
38
39 #  define atomic_init(obj, value) \
40     do { *(obj) = (value); } while(0)
41
42 #  define kill_dependency(y) \
43     ((void)0)
44
45 #  define atomic_thread_fence(order) \
46     __sync_synchronize()
47
48 #  define atomic_signal_fence(order) \
49     ((void)0)
50
51 #  define atomic_is_lock_free(obj) \
52     false
53
54 /* In principles, __sync_*() only supports int, long and long long and their
55  * unsigned equivalents, i.e. 4-bytes and 8-bytes types, although GCC also
56  * supports 1 and 2-bytes types. Some non-x86 architectures do not support
57  * 8-byte atomic types (or not efficiently). So lets stick to (u)intptr_t. */
58 typedef  intptr_t atomic_flag;
59 typedef  intptr_t atomic_bool;
60 typedef  intptr_t atomic_char;
61 typedef  intptr_t atomic_schar;
62 typedef uintptr_t atomic_uchar;
63 typedef  intptr_t atomic_short;
64 typedef uintptr_t atomic_ushort;
65 typedef  intptr_t atomic_int;
66 typedef uintptr_t atomic_uint;
67 typedef  intptr_t atomic_long;
68 typedef uintptr_t atomic_ulong;
69 //atomic_llong
70 //atomic_ullong
71 typedef uintptr_t atomic_char16_t;
72 typedef uintptr_t atomic_char32_t;
73 typedef uintptr_t atomic_wchar_t;
74 typedef  intptr_t atomic_int_least8_t;
75 typedef uintptr_t atomic_uint_least8_t;
76 typedef  intptr_t atomic_int_least16_t;
77 typedef uintptr_t atomic_uint_least16_t;
78 typedef  intptr_t atomic_int_least32_t;
79 typedef uintptr_t atomic_uint_least32_t;
80 //atomic_int_least64_t
81 //atomic_uint_least64_t
82 typedef  intptr_t atomic_int_fast8_t;
83 typedef uintptr_t atomic_uint_fast8_t;
84 typedef  intptr_t atomic_int_fast16_t;
85 typedef uintptr_t atomic_uint_fast16_t;
86 typedef  intptr_t atomic_int_fast32_t;
87 typedef uintptr_t atomic_uint_fast32_t;
88 //atomic_int_fast64_t
89 //atomic_uint_fast64_t
90 typedef  intptr_t atomic_intptr_t;
91 typedef uintptr_t atomic_uintptr_t;
92 typedef uintptr_t atomic_size_t;
93 typedef  intptr_t atomic_ptrdiff_t;
94 //atomic_intmax_t
95 //atomic_uintmax_t
96
97 #  define atomic_store(object,desired) \
98     do { \
99         *(object) = (desired); \
100         __sync_synchronize(); \
101     } while (0)
102
103 #  define atomic_store_explicit(object,desired,order) \
104     atomic_store(object,desired)
105
106 #  define atomic_load(object) \
107     (__sync_synchronize(), *(object))
108
109 #  define atomic_load_explicit(object,order) \
110     atomic_load(object)
111
112 static inline
113 intptr_t vlc_atomic_exchange(volatile void *object, intptr_t desired)
114 {
115     volatile intptr_t *ptr = (volatile intptr_t *)object;
116     intptr_t old;
117     /* NOTE: while __sync_lock_test_and_set() is an atomic exchange, its memory
118      * order is too weak (acquire instead of sequentially consistent).
119      * Because of that, for lack of both C11 _Generic() and GNU C compound
120      * statements, atomic exchange needs a helper function.
121      * Thus all atomic types must have the same size. */
122     do
123         old = atomic_load(ptr);
124     while (!__sync_bool_compare_and_swap(ptr, old, desired));
125
126     return old;
127 }
128
129 #  define atomic_exchange(object,desired) \
130     vlc_atomic_exchange(object,desired)
131
132 #  define atomic_exchange_explicit(object,desired,order) \
133     atomic_exchange(object,desired)
134
135 static inline
136 bool vlc_atomic_compare_exchange(volatile void *object, void *expected,
137                                  intptr_t desired)
138 {
139     volatile intptr_t *ptr = (volatile intptr_t *)object;
140     intptr_t old = *(intptr_t *)expected;
141     intptr_t val = __sync_val_compare_and_swap(ptr, old, desired);
142     if (old != val)
143     {
144         *(intptr_t *)expected = val;
145         return false;
146     }
147     return true;
148 }
149
150 #  define atomic_compare_exchange_strong(object,expected,desired) \
151     vlc_atomic_compare_exchange(object, expected, desired)
152
153 #  define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
154     atomic_compare_exchange_strong(object, expected, desired)
155
156 #  define atomic_compare_exchange_weak(object,expected,desired) \
157     vlc_atomic_compare_exchange(object, expected, desired)
158
159 #  define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
160     atomic_compare_exchange_weak(object, expected, desired)
161
162 #  define atomic_fetch_add(object,operand) \
163     __sync_fetch_and_add(object, operand)
164
165 #  define atomic_fetch_add_explicit(object,operand,order) \
166     atomic_fetch_add(object,operand)
167
168 #  define atomic_fetch_sub(object,operand) \
169     __sync_fetch_and_sub(object, operand)
170
171 #  define atomic_fetch_sub_explicit(object,operand,order) \
172     atomic_fetch_sub(object,operand)
173
174 #  define atomic_fetch_or(object,operand) \
175     __sync_fetch_and_or(object, operand)
176
177 #  define atomic_fetch_or_explicit(object,operand,order) \
178     atomic_fetch_or(object,operand)
179
180 #  define atomic_fetch_xor(object,operand) \
181     __sync_fetch_and_sub(object, operand)
182
183 #  define atomic_fetch_xor_explicit(object,operand,order) \
184     atomic_fetch_sub(object,operand)
185
186 #  define atomic_fetch_and(object,operand) \
187     __sync_fetch_and_and(object, operand)
188
189 #  define atomic_fetch_and_explicit(object,operand,order) \
190     atomic_fetch_and(object,operand)
191
192 #  define atomic_flag_test_and_set(object) \
193     atomic_exchange(object, true)
194
195 #  define atomic_flag_test_and_set_explicit(object,order) \
196     atomic_flag_test_and_set(object)
197
198 #  define atomic_flag_clear(object) \
199     atomic_store(object, false)
200
201 #  define atomic_flag_clear_explicit(object,order) \
202     atomic_flag_clear(object)
203
204 # endif
205
206 /**
207  * Memory storage space for an atom. Never access it directly.
208  */
209 typedef union
210 {
211     atomic_uintptr_t u;
212 } vlc_atomic_t;
213
214 /** Static initializer for \ref vlc_atomic_t */
215 # define VLC_ATOMIC_INIT(val) { (val) }
216
217 /* All functions return the atom value _after_ the operation. */
218 static inline uintptr_t vlc_atomic_get(const vlc_atomic_t *atom)
219 {
220     return atomic_load(&atom->u);
221 }
222
223 static inline uintptr_t vlc_atomic_set(vlc_atomic_t *atom, uintptr_t v)
224 {
225     atomic_store(&atom->u, v);
226     return v;
227 }
228
229 static inline uintptr_t vlc_atomic_add(vlc_atomic_t *atom, uintptr_t v)
230 {
231     return atomic_fetch_add(&atom->u, v) + v;
232 }
233
234 static inline uintptr_t vlc_atomic_sub (vlc_atomic_t *atom, uintptr_t v)
235 {
236     return atomic_fetch_sub (&atom->u, v) - v;
237 }
238
239 static inline uintptr_t vlc_atomic_inc (vlc_atomic_t *atom)
240 {
241     return vlc_atomic_add (atom, 1);
242 }
243
244 static inline uintptr_t vlc_atomic_dec (vlc_atomic_t *atom)
245 {
246     return vlc_atomic_sub (atom, 1);
247 }
248
249 static inline uintptr_t vlc_atomic_swap(vlc_atomic_t *atom, uintptr_t v)
250 {
251     return atomic_exchange(&atom->u, v);
252 }
253
254 static inline uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *atom,
255                                                 uintptr_t u, uintptr_t v)
256 {
257     return atomic_compare_exchange_strong(&atom->u, &u, v);
258 }
259
260 /** Helper to retrieve a single precision from an atom. */
261 static inline float vlc_atomic_getf(const vlc_atomic_t *atom)
262 {
263     union { float f; uintptr_t i; } u;
264     u.i = vlc_atomic_get(atom);
265     return u.f;
266 }
267
268 /** Helper to store a single precision into an atom. */
269 static inline float vlc_atomic_setf(vlc_atomic_t *atom, float f)
270 {
271     union { float f; uintptr_t i; } u;
272     u.f = f;
273     vlc_atomic_set(atom, u.i);
274     return f;
275 }
276
277 #endif