]> git.sesse.net Git - vlc/blob - include/vlc_atomic.h
vlc_atomic: work-around clang issue #11174
[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
32 /*** Native C11 atomics ***/
33 #  include <stdatomic.h>
34
35 # elif defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || (defined (__clang__) && (defined (__x86_64__) || defined (__i386__)))
36
37 /*** Intel/GCC atomics ***/
38
39 #  define ATOMIC_FLAG_INIT false
40
41 #  define ATOMIC_VAR_INIT(value) (value)
42
43 #  define atomic_init(obj, value) \
44     do { *(obj) = (value); } while(0)
45
46 #  define kill_dependency(y) \
47     ((void)0)
48
49 #  define atomic_thread_fence(order) \
50     __sync_synchronize()
51
52 #  define atomic_signal_fence(order) \
53     ((void)0)
54
55 #  define atomic_is_lock_free(obj) \
56     false
57
58 /* In principles, __sync_*() only supports int, long and long long and their
59  * unsigned equivalents, i.e. 4-bytes and 8-bytes types, although GCC also
60  * supports 1 and 2-bytes types. Some non-x86 architectures do not support
61  * 8-byte atomic types (or not efficiently). */
62 typedef          bool      atomic_flag;
63 typedef          bool      atomic_bool;
64 typedef          char      atomic_char;
65 typedef   signed char      atomic_schar;
66 typedef unsigned char      atomic_uchar;
67 typedef          short     atomic_short;
68 typedef unsigned short     atomic_ushort;
69 typedef          int       atomic_int;
70 typedef unsigned int       atomic_uint;
71 typedef          long      atomic_long;
72 typedef unsigned long      atomic_ulong;
73 typedef          long long atomic_llong;
74 typedef unsigned long long atomic_ullong;
75 //typedef          char16_t  atomic_char16_t;
76 //typedef          char32_t  atomic_char32_t;
77 typedef          wchar_t   atomic_wchar_t;
78 typedef       int_least8_t atomic_int_least8_t;
79 typedef      uint_least8_t atomic_uint_least8_t;
80 typedef      int_least16_t atomic_int_least16_t;
81 typedef     uint_least16_t atomic_uint_least16_t;
82 typedef      int_least32_t atomic_int_least32_t;
83 typedef     uint_least32_t atomic_uint_least32_t;
84 typedef      int_least64_t atomic_int_least64_t;
85 typedef     uint_least64_t atomic_uint_least64_t;
86 typedef       int_fast8_t atomic_int_fast8_t;
87 typedef      uint_fast8_t atomic_uint_fast8_t;
88 typedef      int_fast16_t atomic_int_fast16_t;
89 typedef     uint_fast16_t atomic_uint_fast16_t;
90 typedef      int_fast32_t atomic_int_fast32_t;
91 typedef     uint_fast32_t atomic_uint_fast32_t;
92 typedef      int_fast64_t atomic_int_fast64_t;
93 typedef     uint_fast64_t atomic_uint_fast64_t;
94 typedef          intptr_t atomic_intptr_t;
95 typedef         uintptr_t atomic_uintptr_t;
96 typedef            size_t atomic_size_t;
97 typedef         ptrdiff_t atomic_ptrdiff_t;
98 typedef          intmax_t atomic_intmax_t;
99 typedef         uintmax_t atomic_uintmax_t;
100
101 #  define atomic_store(object,desired) \
102     do { \
103         *(object) = (desired); \
104         __sync_synchronize(); \
105     } while (0)
106
107 #  define atomic_store_explicit(object,desired,order) \
108     atomic_store(object,desired)
109
110 #  define atomic_load(object) \
111     (__sync_synchronize(), *(object))
112
113 #  define atomic_load_explicit(object,order) \
114     atomic_load(object)
115
116 #  define atomic_exchange(object,desired) \
117 ({  \
118     typeof (object) _obj = (object); \
119     typeof (*object) _old; \
120     do \
121         _old = atomic_load(_obj); \
122     while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \
123     _old; \
124 })
125
126 #  define atomic_exchange_explicit(object,desired,order) \
127     atomic_exchange(object,desired)
128
129 #  define atomic_compare_exchange(object,expected,desired) \
130 ({  \
131     typeof (object) _exp = (expected); \
132     typeof (*object) _old = *_exp; \
133     *_exp = __sync_val_compare_and_swap((object), _old, (desired)); \
134     *_exp == _old; \
135 })
136
137 #  define atomic_compare_exchange_strong(object,expected,desired) \
138     atomic_compare_exchange(object, expected, desired)
139
140 #  define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
141     atomic_compare_exchange_strong(object, expected, desired)
142
143 #  define atomic_compare_exchange_weak(object,expected,desired) \
144     atomic_compare_exchange(object, expected, desired)
145
146 #  define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
147     atomic_compare_exchange_weak(object, expected, desired)
148
149 #  define atomic_fetch_add(object,operand) \
150     __sync_fetch_and_add(object, operand)
151
152 #  define atomic_fetch_add_explicit(object,operand,order) \
153     atomic_fetch_add(object,operand)
154
155 #  define atomic_fetch_sub(object,operand) \
156     __sync_fetch_and_sub(object, operand)
157
158 #  define atomic_fetch_sub_explicit(object,operand,order) \
159     atomic_fetch_sub(object,operand)
160
161 #  define atomic_fetch_or(object,operand) \
162     __sync_fetch_and_or(object, operand)
163
164 #  define atomic_fetch_or_explicit(object,operand,order) \
165     atomic_fetch_or(object,operand)
166
167 #  define atomic_fetch_xor(object,operand) \
168     __sync_fetch_and_sub(object, operand)
169
170 #  define atomic_fetch_xor_explicit(object,operand,order) \
171     atomic_fetch_sub(object,operand)
172
173 #  define atomic_fetch_and(object,operand) \
174     __sync_fetch_and_and(object, operand)
175
176 #  define atomic_fetch_and_explicit(object,operand,order) \
177     atomic_fetch_and(object,operand)
178
179 #  define atomic_flag_test_and_set(object) \
180     atomic_exchange(object, true)
181
182 #  define atomic_flag_test_and_set_explicit(object,order) \
183     atomic_flag_test_and_set(object)
184
185 #  define atomic_flag_clear(object) \
186     atomic_store(object, false)
187
188 #  define atomic_flag_clear_explicit(object,order) \
189     atomic_flag_clear(object)
190
191 # else
192
193 /*** No atomics ***/
194
195 #  define ATOMIC_FLAG_INIT false
196
197 #  define ATOMIC_VAR_INIT(value) (value)
198
199 #  define atomic_init(obj, value) \
200     do { *(obj) = (value); } while(0)
201
202 #  define kill_dependency(y) \
203     ((void)0)
204
205 #  define atomic_thread_fence(order) \
206     __sync_synchronize()
207
208 #  define atomic_signal_fence(order) \
209     ((void)0)
210
211 #  define atomic_is_lock_free(obj) \
212     false
213
214 typedef uintptr_t atomic_generic_t;
215 typedef atomic_generic_t atomic_flag;
216 typedef atomic_generic_t atomic_bool;
217 //typedef atomic_generic_t atomic_char;
218 //typedef atomic_generic_t atomic_schar;
219 typedef atomic_generic_t atomic_uchar;
220 //typedef atomic_generic_t atomic_short;
221 typedef atomic_generic_t atomic_ushort;
222 //typedef atomic_generic_t atomic_int;
223 typedef atomic_generic_t atomic_uint;
224 //typedef atomic_generic_t atomic_long;
225 typedef atomic_generic_t atomic_ulong;
226 //typedef atomic_generic_t atomic_llong;
227 //typedef atomic_generic_t atomic_ullong;
228 //typedef atomic_generic_t atomic_char16_t;
229 //typedef atomic_generic_t atomic_char32_t;
230 //typedef atomic_generic_t atomic_wchar_t;
231 //typedef atomic_generic_t atomic_int_least8_t;
232 typedef atomic_generic_t atomic_uint_least8_t;
233 //typedef atomic_generic_t atomic_int_least16_t;
234 typedef atomic_generic_t atomic_uint_least16_t;
235 //typedef atomic_generic_t atomic_int_least32_t;
236 typedef atomic_generic_t atomic_uint_least32_t;
237 //typedef atomic_generic_t atomic_int_least64_t;
238 //typedef atomic_generic_t atomic_uint_least64_t;
239 //typedef atomic_generic_t atomic_int_fast8_t;
240 typedef atomic_generic_t atomic_uint_fast8_t;
241 //typedef atomic_generic_t atomic_int_fast16_t;
242 typedef atomic_generic_t atomic_uint_fast16_t;
243 //typedef atomic_generic_t atomic_int_fast32_t;
244 typedef atomic_generic_t atomic_uint_fast32_t;
245 //typedef atomic_generic_t atomic_int_fast64_t
246 //typedef atomic_generic_t atomic_uint_fast64_t;
247 //typedef atomic_generic_t atomic_intptr_t;
248 typedef atomic_generic_t atomic_uintptr_t;
249 typedef atomic_generic_t atomic_size_t;
250 //typedef atomic_generic_t atomic_ptrdiff_t;
251 //typedef atomic_generic_t atomic_intmax_t;
252 //typedef atomic_generic_t atomic_uintmax_t;
253
254 #define atomic_store(object,desired) \
255     do { \
256         vlc_global_lock(VLC_ATOMIC_MUTEX); \
257         *(object) = (desired); \
258         vlc_global_unlock(VLC_ATOMIC_MUTEX); \
259     } while (0)
260
261 #  define atomic_store_explicit(object,desired,order) \
262     atomic_store(object,desired)
263
264 static inline uintptr_t atomic_load(atomic_generic_t *object)
265 {
266     uintptr_t value;
267
268     vlc_global_lock(VLC_ATOMIC_MUTEX);
269     value = *object;
270     vlc_global_unlock(VLC_ATOMIC_MUTEX);
271     return value;
272 }
273 #  define atomic_load_explicit(object,order) \
274     atomic_load(object)
275
276 static inline
277 uintptr_t atomic_exchange(atomic_generic_t *object, uintptr_t desired)
278 {
279     uintptr_t value;
280
281     vlc_global_lock(VLC_ATOMIC_MUTEX);
282     value = *object;
283     *object = desired;
284     vlc_global_unlock(VLC_ATOMIC_MUTEX);
285     return value;
286 }
287 #  define atomic_exchange_explicit(object,desired,order) \
288     atomic_exchange(object,desired)
289
290 static inline
291 bool vlc_atomic_compare_exchange(atomic_generic_t *object,
292                                  uintptr_t *expected, uintptr_t desired)
293 {
294     bool ret;
295
296     vlc_global_lock(VLC_ATOMIC_MUTEX);
297     ret = *object == *expected;
298     if (ret)
299         *object = desired;
300     else
301         *expected = *object;
302     vlc_global_unlock(VLC_ATOMIC_MUTEX);
303     return ret;
304 }
305 #  define atomic_compare_exchange_strong(object,expected,desired) \
306     vlc_atomic_compare_exchange(object, expected, desired)
307 #  define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
308     atomic_compare_exchange_strong(object, expected, desired)
309 #  define atomic_compare_exchange_weak(object,expected,desired) \
310     vlc_atomic_compare_exchange(object, expected, desired)
311 #  define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
312     atomic_compare_exchange_weak(object, expected, desired)
313
314 static inline
315 uintmax_t atomic_fetch_add(atomic_generic_t *object, uintptr_t operand)
316 {
317     uintptr_t value;
318
319     vlc_global_lock(VLC_ATOMIC_MUTEX);
320     value = *object;
321     *object += operand;
322     vlc_global_unlock(VLC_ATOMIC_MUTEX);
323     return value;
324 }
325 #  define atomic_fetch_add_explicit(object,operand,order) \
326     atomic_fetch_add(object,operand)
327
328 static inline
329 uintptr_t atomic_fetch_sub(atomic_generic_t *object, uintptr_t operand)
330 {
331     uintptr_t value;
332
333     vlc_global_lock(VLC_ATOMIC_MUTEX);
334     value = *object;
335     *object -= operand;
336     vlc_global_unlock(VLC_ATOMIC_MUTEX);
337     return value;
338 }
339 #  define atomic_fetch_sub_explicit(object,operand,order) \
340     atomic_fetch_sub(object,operand)
341
342 static inline
343 uintptr_t atomic_fetch_or(atomic_generic_t *object, uintptr_t operand)
344 {
345     uintptr_t value;
346
347     vlc_global_lock(VLC_ATOMIC_MUTEX);
348     value = *object;
349     *object |= operand;
350     vlc_global_unlock(VLC_ATOMIC_MUTEX);
351     return value;
352 }
353 #  define atomic_fetch_or_explicit(object,operand,order) \
354     atomic_fetch_or(object,operand)
355
356 static inline
357 uintptr_t atomic_fetch_xor(atomic_generic_t *object, uintptr_t operand)
358 {
359     uintptr_t value;
360
361     vlc_global_lock(VLC_ATOMIC_MUTEX);
362     value = *object;
363     *object ^= operand;
364     vlc_global_unlock(VLC_ATOMIC_MUTEX);
365     return value;
366 }
367 #  define atomic_fetch_xor_explicit(object,operand,order) \
368     atomic_fetch_sub(object,operand)
369
370 static inline
371 uintptr_t atomic_fetch_and(atomic_generic_t *object, uintptr_t operand)
372 {
373     uintptr_t value;
374
375     vlc_global_lock(VLC_ATOMIC_MUTEX);
376     value = *object;
377     *object &= operand;
378     vlc_global_unlock(VLC_ATOMIC_MUTEX);
379     return value;
380 }
381 #  define atomic_fetch_and_explicit(object,operand,order) \
382     atomic_fetch_and(object,operand)
383
384 #  define atomic_flag_test_and_set(object) \
385     atomic_exchange(object, true)
386
387 #  define atomic_flag_test_and_set_explicit(object,order) \
388     atomic_flag_test_and_set(object)
389
390 #  define atomic_flag_clear(object) \
391     atomic_store(object, false)
392
393 #  define atomic_flag_clear_explicit(object,order) \
394     atomic_flag_clear(object)
395
396 # endif
397
398 /**
399  * Memory storage space for an atom. Never access it directly.
400  */
401 typedef union
402 {
403     atomic_uintptr_t u;
404 } vlc_atomic_t;
405
406 /** Static initializer for \ref vlc_atomic_t */
407 # define VLC_ATOMIC_INIT(val) { (val) }
408
409 /* All functions return the atom value _after_ the operation. */
410 static inline uintptr_t vlc_atomic_get(vlc_atomic_t *atom)
411 {
412     return atomic_load(&atom->u);
413 }
414
415 static inline uintptr_t vlc_atomic_set(vlc_atomic_t *atom, uintptr_t v)
416 {
417     atomic_store(&atom->u, v);
418     return v;
419 }
420
421 static inline uintptr_t vlc_atomic_add(vlc_atomic_t *atom, uintptr_t v)
422 {
423     return atomic_fetch_add(&atom->u, v) + v;
424 }
425
426 static inline uintptr_t vlc_atomic_sub (vlc_atomic_t *atom, uintptr_t v)
427 {
428     return atomic_fetch_sub (&atom->u, v) - v;
429 }
430
431 static inline uintptr_t vlc_atomic_inc (vlc_atomic_t *atom)
432 {
433     return vlc_atomic_add (atom, 1);
434 }
435
436 static inline uintptr_t vlc_atomic_dec (vlc_atomic_t *atom)
437 {
438     return vlc_atomic_sub (atom, 1);
439 }
440
441 static inline uintptr_t vlc_atomic_swap(vlc_atomic_t *atom, uintptr_t v)
442 {
443     return atomic_exchange(&atom->u, v);
444 }
445
446 static inline uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *atom,
447                                                 uintptr_t u, uintptr_t v)
448 {
449     atomic_compare_exchange_strong(&atom->u, &u, v);
450     return u;
451 }
452
453 /** Helper to retrieve a single precision from an atom. */
454 static inline float vlc_atomic_getf(vlc_atomic_t *atom)
455 {
456     union { float f; uintptr_t i; } u;
457     u.i = vlc_atomic_get(atom);
458     return u.f;
459 }
460
461 /** Helper to store a single precision into an atom. */
462 static inline float vlc_atomic_setf(vlc_atomic_t *atom, float f)
463 {
464     union { float f; uintptr_t i; } u;
465     u.f = f;
466     vlc_atomic_set(atom, u.i);
467     return f;
468 }
469
470 #endif