1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2010 RĂ©mi Denis-Courmont
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.
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.
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 *****************************************************************************/
26 * Atomic operations do not require locking, but they are not very powerful.
29 # if !defined (__cplusplus) && (__STDC_VERSION__ >= 201112L) \
30 && !defined (__STDC_NO_ATOMICS__)
32 /*** Native C11 atomics ***/
33 # include <stdatomic.h>
35 # elif defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
37 /*** Intel/GCC atomics ***/
39 # define ATOMIC_FLAG_INIT false
41 # define ATOMIC_VAR_INIT(value) (value)
43 # define atomic_init(obj, value) \
44 do { *(obj) = (value); } while(0)
46 # define kill_dependency(y) \
49 # define atomic_thread_fence(order) \
52 # define atomic_signal_fence(order) \
55 # define atomic_is_lock_free(obj) \
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). So lets stick to (u)intptr_t. */
62 typedef intptr_t atomic_flag;
63 typedef intptr_t atomic_bool;
64 typedef intptr_t atomic_char;
65 typedef intptr_t atomic_schar;
66 typedef uintptr_t atomic_uchar;
67 typedef intptr_t atomic_short;
68 typedef uintptr_t atomic_ushort;
69 typedef intptr_t atomic_int;
70 typedef uintptr_t atomic_uint;
71 typedef intptr_t atomic_long;
72 typedef uintptr_t atomic_ulong;
75 typedef uintptr_t atomic_char16_t;
76 typedef uintptr_t atomic_char32_t;
77 typedef uintptr_t atomic_wchar_t;
78 typedef intptr_t atomic_int_least8_t;
79 typedef uintptr_t atomic_uint_least8_t;
80 typedef intptr_t atomic_int_least16_t;
81 typedef uintptr_t atomic_uint_least16_t;
82 typedef intptr_t atomic_int_least32_t;
83 typedef uintptr_t atomic_uint_least32_t;
84 //atomic_int_least64_t
85 //atomic_uint_least64_t
86 typedef intptr_t atomic_int_fast8_t;
87 typedef uintptr_t atomic_uint_fast8_t;
88 typedef intptr_t atomic_int_fast16_t;
89 typedef uintptr_t atomic_uint_fast16_t;
90 typedef intptr_t atomic_int_fast32_t;
91 typedef uintptr_t atomic_uint_fast32_t;
93 //atomic_uint_fast64_t
94 typedef intptr_t atomic_intptr_t;
95 typedef uintptr_t atomic_uintptr_t;
96 typedef uintptr_t atomic_size_t;
97 typedef intptr_t atomic_ptrdiff_t;
101 # define atomic_store(object,desired) \
103 *(object) = (desired); \
104 __sync_synchronize(); \
107 # define atomic_store_explicit(object,desired,order) \
108 atomic_store(object,desired)
110 # define atomic_load(object) \
111 (__sync_synchronize(), *(object))
113 # define atomic_load_explicit(object,order) \
117 intptr_t vlc_atomic_exchange(volatile void *object, intptr_t desired)
119 volatile intptr_t *ptr = (volatile intptr_t *)object;
121 /* NOTE: while __sync_lock_test_and_set() is an atomic exchange, its memory
122 * order is too weak (acquire instead of sequentially consistent).
123 * Because of that, for lack of both C11 _Generic() and GNU C compound
124 * statements, atomic exchange needs a helper function.
125 * Thus all atomic types must have the same size. */
127 old = atomic_load(ptr);
128 while (!__sync_bool_compare_and_swap(ptr, old, desired));
133 # define atomic_exchange(object,desired) \
134 vlc_atomic_exchange(object,desired)
136 # define atomic_exchange_explicit(object,desired,order) \
137 atomic_exchange(object,desired)
140 bool vlc_atomic_compare_exchange(volatile void *object, void *expected,
143 volatile intptr_t *ptr = (volatile intptr_t *)object;
144 intptr_t old = *(intptr_t *)expected;
145 intptr_t val = __sync_val_compare_and_swap(ptr, old, desired);
148 *(intptr_t *)expected = val;
154 # define atomic_compare_exchange_strong(object,expected,desired) \
155 vlc_atomic_compare_exchange(object, expected, desired)
157 # define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
158 atomic_compare_exchange_strong(object, expected, desired)
160 # define atomic_compare_exchange_weak(object,expected,desired) \
161 vlc_atomic_compare_exchange(object, expected, desired)
163 # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
164 atomic_compare_exchange_weak(object, expected, desired)
166 # define atomic_fetch_add(object,operand) \
167 __sync_fetch_and_add(object, operand)
169 # define atomic_fetch_add_explicit(object,operand,order) \
170 atomic_fetch_add(object,operand)
172 # define atomic_fetch_sub(object,operand) \
173 __sync_fetch_and_sub(object, operand)
175 # define atomic_fetch_sub_explicit(object,operand,order) \
176 atomic_fetch_sub(object,operand)
178 # define atomic_fetch_or(object,operand) \
179 __sync_fetch_and_or(object, operand)
181 # define atomic_fetch_or_explicit(object,operand,order) \
182 atomic_fetch_or(object,operand)
184 # define atomic_fetch_xor(object,operand) \
185 __sync_fetch_and_sub(object, operand)
187 # define atomic_fetch_xor_explicit(object,operand,order) \
188 atomic_fetch_sub(object,operand)
190 # define atomic_fetch_and(object,operand) \
191 __sync_fetch_and_and(object, operand)
193 # define atomic_fetch_and_explicit(object,operand,order) \
194 atomic_fetch_and(object,operand)
196 # define atomic_flag_test_and_set(object) \
197 atomic_exchange(object, true)
199 # define atomic_flag_test_and_set_explicit(object,order) \
200 atomic_flag_test_and_set(object)
202 # define atomic_flag_clear(object) \
203 atomic_store(object, false)
205 # define atomic_flag_clear_explicit(object,order) \
206 atomic_flag_clear(object)
212 # define ATOMIC_FLAG_INIT false
214 # define ATOMIC_VAR_INIT(value) (value)
216 # define atomic_init(obj, value) \
217 do { *(obj) = (value); } while(0)
219 # define kill_dependency(y) \
222 # define atomic_thread_fence(order) \
225 # define atomic_signal_fence(order) \
228 # define atomic_is_lock_free(obj) \
231 typedef uintptr_t atomic_generic_t;
232 typedef atomic_generic_t atomic_flag;
233 typedef atomic_generic_t atomic_bool;
234 //typedef atomic_generic_t atomic_char;
235 //typedef atomic_generic_t atomic_schar;
236 typedef atomic_generic_t atomic_uchar;
237 //typedef atomic_generic_t atomic_short;
238 typedef atomic_generic_t atomic_ushort;
239 //typedef atomic_generic_t atomic_int;
240 typedef atomic_generic_t atomic_uint;
241 //typedef atomic_generic_t atomic_long;
242 typedef atomic_generic_t atomic_ulong;
243 //typedef atomic_generic_t atomic_llong;
244 //typedef atomic_generic_t atomic_ullong;
245 //typedef atomic_generic_t atomic_char16_t;
246 //typedef atomic_generic_t atomic_char32_t;
247 //typedef atomic_generic_t atomic_wchar_t;
248 //typedef atomic_generic_t atomic_int_least8_t;
249 typedef atomic_generic_t atomic_uint_least8_t;
250 //typedef atomic_generic_t atomic_int_least16_t;
251 typedef atomic_generic_t atomic_uint_least16_t;
252 //typedef atomic_generic_t atomic_int_least32_t;
253 typedef atomic_generic_t atomic_uint_least32_t;
254 //typedef atomic_generic_t atomic_int_least64_t;
255 //typedef atomic_generic_t atomic_uint_least64_t;
256 //typedef atomic_generic_t atomic_int_fast8_t;
257 typedef atomic_generic_t atomic_uint_fast8_t;
258 //typedef atomic_generic_t atomic_int_fast16_t;
259 typedef atomic_generic_t atomic_uint_fast16_t;
260 //typedef atomic_generic_t atomic_int_fast32_t;
261 typedef atomic_generic_t atomic_uint_fast32_t;
262 //typedef atomic_generic_t atomic_int_fast64_t
263 //typedef atomic_generic_t atomic_uint_fast64_t;
264 //typedef atomic_generic_t atomic_intptr_t;
265 typedef atomic_generic_t atomic_uintptr_t;
266 typedef atomic_generic_t atomic_size_t;
267 //typedef atomic_generic_t atomic_ptrdiff_t;
268 //typedef atomic_generic_t atomic_intmax_t;
269 //typedef atomic_generic_t atomic_uintmax_t;
271 #define atomic_store(object,desired) \
273 vlc_global_lock(VLC_ATOMIC_MUTEX); \
274 *(object) = (desired); \
275 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
278 # define atomic_store_explicit(object,desired,order) \
279 atomic_store(object,desired)
281 static inline uintptr_t atomic_load(atomic_generic_t *object)
285 vlc_global_lock(VLC_ATOMIC_MUTEX);
287 vlc_global_unlock(VLC_ATOMIC_MUTEX);
290 # define atomic_load_explicit(object,order) \
294 uintptr_t atomic_exchange(atomic_generic_t *object, uintptr_t desired)
298 vlc_global_lock(VLC_ATOMIC_MUTEX);
301 vlc_global_unlock(VLC_ATOMIC_MUTEX);
304 # define atomic_exchange_explicit(object,desired,order) \
305 atomic_exchange(object,desired)
308 bool vlc_atomic_compare_exchange(atomic_generic_t *object,
309 uintptr_t *expected, uintptr_t desired)
313 vlc_global_lock(VLC_ATOMIC_MUTEX);
314 ret = *object == *expected;
319 vlc_global_unlock(VLC_ATOMIC_MUTEX);
322 # define atomic_compare_exchange_strong(object,expected,desired) \
323 vlc_atomic_compare_exchange(object, expected, desired)
324 # define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
325 atomic_compare_exchange_strong(object, expected, desired)
326 # define atomic_compare_exchange_weak(object,expected,desired) \
327 vlc_atomic_compare_exchange(object, expected, desired)
328 # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
329 atomic_compare_exchange_weak(object, expected, desired)
332 uintmax_t atomic_fetch_add(atomic_generic_t *object, uintptr_t operand)
336 vlc_global_lock(VLC_ATOMIC_MUTEX);
339 vlc_global_unlock(VLC_ATOMIC_MUTEX);
342 # define atomic_fetch_add_explicit(object,operand,order) \
343 atomic_fetch_add(object,operand)
346 uintptr_t atomic_fetch_sub(atomic_generic_t *object, uintptr_t operand)
350 vlc_global_lock(VLC_ATOMIC_MUTEX);
353 vlc_global_unlock(VLC_ATOMIC_MUTEX);
356 # define atomic_fetch_sub_explicit(object,operand,order) \
357 atomic_fetch_sub(object,operand)
360 uintptr_t atomic_fetch_or(atomic_generic_t *object, uintptr_t operand)
364 vlc_global_lock(VLC_ATOMIC_MUTEX);
367 vlc_global_unlock(VLC_ATOMIC_MUTEX);
370 # define atomic_fetch_or_explicit(object,operand,order) \
371 atomic_fetch_or(object,operand)
374 uintptr_t atomic_fetch_xor(atomic_generic_t *object, uintptr_t operand)
378 vlc_global_lock(VLC_ATOMIC_MUTEX);
381 vlc_global_unlock(VLC_ATOMIC_MUTEX);
384 # define atomic_fetch_xor_explicit(object,operand,order) \
385 atomic_fetch_sub(object,operand)
388 uintptr_t atomic_fetch_and(atomic_generic_t *object, uintptr_t operand)
392 vlc_global_lock(VLC_ATOMIC_MUTEX);
395 vlc_global_unlock(VLC_ATOMIC_MUTEX);
398 # define atomic_fetch_and_explicit(object,operand,order) \
399 atomic_fetch_and(object,operand)
401 # define atomic_flag_test_and_set(object) \
402 atomic_exchange(object, true)
404 # define atomic_flag_test_and_set_explicit(object,order) \
405 atomic_flag_test_and_set(object)
407 # define atomic_flag_clear(object) \
408 atomic_store(object, false)
410 # define atomic_flag_clear_explicit(object,order) \
411 atomic_flag_clear(object)
416 * Memory storage space for an atom. Never access it directly.
423 /** Static initializer for \ref vlc_atomic_t */
424 # define VLC_ATOMIC_INIT(val) { (val) }
426 /* All functions return the atom value _after_ the operation. */
427 static inline uintptr_t vlc_atomic_get(vlc_atomic_t *atom)
429 return atomic_load(&atom->u);
432 static inline uintptr_t vlc_atomic_set(vlc_atomic_t *atom, uintptr_t v)
434 atomic_store(&atom->u, v);
438 static inline uintptr_t vlc_atomic_add(vlc_atomic_t *atom, uintptr_t v)
440 return atomic_fetch_add(&atom->u, v) + v;
443 static inline uintptr_t vlc_atomic_sub (vlc_atomic_t *atom, uintptr_t v)
445 return atomic_fetch_sub (&atom->u, v) - v;
448 static inline uintptr_t vlc_atomic_inc (vlc_atomic_t *atom)
450 return vlc_atomic_add (atom, 1);
453 static inline uintptr_t vlc_atomic_dec (vlc_atomic_t *atom)
455 return vlc_atomic_sub (atom, 1);
458 static inline uintptr_t vlc_atomic_swap(vlc_atomic_t *atom, uintptr_t v)
460 return atomic_exchange(&atom->u, v);
463 static inline uintptr_t vlc_atomic_compare_swap(vlc_atomic_t *atom,
464 uintptr_t u, uintptr_t v)
466 atomic_compare_exchange_strong(&atom->u, &u, v);
470 /** Helper to retrieve a single precision from an atom. */
471 static inline float vlc_atomic_getf(vlc_atomic_t *atom)
473 union { float f; uintptr_t i; } u;
474 u.i = vlc_atomic_get(atom);
478 /** Helper to store a single precision into an atom. */
479 static inline float vlc_atomic_setf(vlc_atomic_t *atom, float f)
481 union { float f; uintptr_t i; } u;
483 vlc_atomic_set(atom, u.i);