Change the gmp download URL to https://gmplib.org/download
[vlc/gmpfix.git] / include / vlc_atomic.h
blobaf88eabb5e7af12d38e78ae972db728d496aa68f
1 /*****************************************************************************
2 * vlc_atomic.h:
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 *****************************************************************************/
21 #ifndef VLC_ATOMIC_H
22 # define VLC_ATOMIC_H
24 /**
25 * \file
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 # else
37 # define ATOMIC_FLAG_INIT false
39 # define ATOMIC_VAR_INIT(value) (value)
41 # define atomic_init(obj, value) \
42 do { *(obj) = (value); } while(0)
44 # define kill_dependency(y) \
45 ((void)0)
47 # define atomic_thread_fence(order) \
48 __sync_synchronize()
50 # define atomic_signal_fence(order) \
51 ((void)0)
53 # define atomic_is_lock_free(obj) \
54 false
56 /* In principles, __sync_*() only supports int, long and long long and their
57 * unsigned equivalents, i.e. 4-bytes and 8-bytes types, although GCC also
58 * supports 1 and 2-bytes types. Some non-x86 architectures do not support
59 * 8-byte atomic types (or not efficiently). */
60 # if defined (_MSC_VER)
61 /* Some atomic operations of the Interlocked API are only
62 available for desktop apps. Thus we define the atomic types to
63 be at least 32 bits wide. */
64 typedef int_least32_t atomic_flag;
65 typedef int_least32_t atomic_bool;
66 typedef int_least32_t atomic_char;
67 typedef int_least32_t atomic_schar;
68 typedef uint_least32_t atomic_uchar;
69 typedef int_least32_t atomic_short;
70 typedef uint_least32_t atomic_ushort;
71 # else
72 typedef bool atomic_flag;
73 typedef bool atomic_bool;
74 typedef char atomic_char;
75 typedef signed char atomic_schar;
76 typedef unsigned char atomic_uchar;
77 typedef short atomic_short;
78 typedef unsigned short atomic_ushort;
79 # endif
80 typedef int atomic_int;
81 typedef unsigned int atomic_uint;
82 typedef long atomic_long;
83 typedef unsigned long atomic_ulong;
84 typedef long long atomic_llong;
85 typedef unsigned long long atomic_ullong;
86 //typedef char16_t atomic_char16_t;
87 //typedef char32_t atomic_char32_t;
88 typedef wchar_t atomic_wchar_t;
89 typedef int_least8_t atomic_int_least8_t;
90 typedef uint_least8_t atomic_uint_least8_t;
91 typedef int_least16_t atomic_int_least16_t;
92 typedef uint_least16_t atomic_uint_least16_t;
93 typedef int_least32_t atomic_int_least32_t;
94 typedef uint_least32_t atomic_uint_least32_t;
95 typedef int_least64_t atomic_int_least64_t;
96 typedef uint_least64_t atomic_uint_least64_t;
97 typedef int_fast8_t atomic_int_fast8_t;
98 typedef uint_fast8_t atomic_uint_fast8_t;
99 typedef int_fast16_t atomic_int_fast16_t;
100 typedef uint_fast16_t atomic_uint_fast16_t;
101 typedef int_fast32_t atomic_int_fast32_t;
102 typedef uint_fast32_t atomic_uint_fast32_t;
103 typedef int_fast64_t atomic_int_fast64_t;
104 typedef uint_fast64_t atomic_uint_fast64_t;
105 typedef intptr_t atomic_intptr_t;
106 typedef uintptr_t atomic_uintptr_t;
107 typedef size_t atomic_size_t;
108 typedef ptrdiff_t atomic_ptrdiff_t;
109 typedef intmax_t atomic_intmax_t;
110 typedef uintmax_t atomic_uintmax_t;
112 # if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || (defined (__clang__) && (defined (__x86_64__) || defined (__i386__)))
114 /*** Intel/GCC atomics ***/
116 # define atomic_store(object,desired) \
117 do { \
118 *(object) = (desired); \
119 __sync_synchronize(); \
120 } while (0)
122 # define atomic_store_explicit(object,desired,order) \
123 atomic_store(object,desired)
125 # define atomic_load(object) \
126 (__sync_synchronize(), *(object))
128 # define atomic_load_explicit(object,order) \
129 atomic_load(object)
131 # define atomic_exchange(object,desired) \
132 ({ \
133 typeof (object) _obj = (object); \
134 typeof (*object) _old; \
135 do \
136 _old = atomic_load(_obj); \
137 while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \
138 _old; \
141 # define atomic_exchange_explicit(object,desired,order) \
142 atomic_exchange(object,desired)
144 # define atomic_compare_exchange(object,expected,desired) \
145 ({ \
146 typeof (object) _exp = (expected); \
147 typeof (*object) _old = *_exp; \
148 *_exp = __sync_val_compare_and_swap((object), _old, (desired)); \
149 *_exp == _old; \
152 # define atomic_compare_exchange_strong(object,expected,desired) \
153 atomic_compare_exchange(object, expected, desired)
155 # define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
156 atomic_compare_exchange_strong(object, expected, desired)
158 # define atomic_compare_exchange_weak(object,expected,desired) \
159 atomic_compare_exchange(object, expected, desired)
161 # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
162 atomic_compare_exchange_weak(object, expected, desired)
164 # define atomic_fetch_add(object,operand) \
165 __sync_fetch_and_add(object, operand)
167 # define atomic_fetch_add_explicit(object,operand,order) \
168 atomic_fetch_add(object,operand)
170 # define atomic_fetch_sub(object,operand) \
171 __sync_fetch_and_sub(object, operand)
173 # define atomic_fetch_sub_explicit(object,operand,order) \
174 atomic_fetch_sub(object,operand)
176 # define atomic_fetch_or(object,operand) \
177 __sync_fetch_and_or(object, operand)
179 # define atomic_fetch_or_explicit(object,operand,order) \
180 atomic_fetch_or(object,operand)
182 # define atomic_fetch_xor(object,operand) \
183 __sync_fetch_and_sub(object, operand)
185 # define atomic_fetch_xor_explicit(object,operand,order) \
186 atomic_fetch_sub(object,operand)
188 # define atomic_fetch_and(object,operand) \
189 __sync_fetch_and_and(object, operand)
191 # define atomic_fetch_and_explicit(object,operand,order) \
192 atomic_fetch_and(object,operand)
194 # define atomic_flag_test_and_set(object) \
195 atomic_exchange(object, true)
197 # define atomic_flag_test_and_set_explicit(object,order) \
198 atomic_flag_test_and_set(object)
200 # define atomic_flag_clear(object) \
201 atomic_store(object, false)
203 # define atomic_flag_clear_explicit(object,order) \
204 atomic_flag_clear(object)
206 # elif defined (__GNUC__)
208 /*** No atomics ***/
210 # define atomic_store(object,desired) \
211 do { \
212 typeof (object) _obj = (object); \
213 typeof (*object) _des = (desired); \
214 vlc_global_lock(VLC_ATOMIC_MUTEX); \
215 *_obj = _des; \
216 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
217 } while (0)
218 # define atomic_store_explicit(object,desired,order) \
219 atomic_store(object,desired)
221 # define atomic_load(object) \
222 ({ \
223 typeof (object) _obj = (object); \
224 typeof (*object) _old; \
225 vlc_global_lock(VLC_ATOMIC_MUTEX); \
226 _old = *_obj; \
227 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
228 _old; \
230 # define atomic_load_explicit(object,order) \
231 atomic_load(object)
233 # define atomic_exchange(object,desired) \
234 ({ \
235 typeof (object) _obj = (object); \
236 typeof (*object) _des = (desired); \
237 typeof (*object) _old; \
238 vlc_global_lock(VLC_ATOMIC_MUTEX); \
239 _old = *_obj; \
240 *_obj = _des; \
241 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
242 _old; \
244 # define atomic_exchange_explicit(object,desired,order) \
245 atomic_exchange(object,desired)
247 # define atomic_compare_exchange_strong(object,expected,desired) \
248 ({ \
249 typeof (object) _obj = (object); \
250 typeof (object) _exp = (expected); \
251 typeof (*object) _des = (desired); \
252 bool ret; \
253 vlc_global_lock(VLC_ATOMIC_MUTEX); \
254 ret = *_obj == *_exp; \
255 if (ret) \
256 *_obj = _des; \
257 else \
258 *_exp = *_obj; \
259 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
260 ret; \
262 # define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
263 atomic_compare_exchange_strong(object, expected, desired)
264 # define atomic_compare_exchange_weak(object,expected,desired) \
265 atomic_compare_exchange_strong(object, expected, desired)
266 # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
267 atomic_compare_exchange_weak(object, expected, desired)
269 # define atomic_fetch_OP(object,desired,op) \
270 ({ \
271 typeof (object) _obj = (object); \
272 typeof (*object) _des = (desired); \
273 typeof (*object) _old; \
274 vlc_global_lock(VLC_ATOMIC_MUTEX); \
275 _old = *_obj; \
276 *_obj = (*_obj) op (_des); \
277 vlc_global_unlock(VLC_ATOMIC_MUTEX); \
278 _old; \
281 # define atomic_fetch_add(object,operand) \
282 atomic_fetch_OP(object,operand,+)
283 # define atomic_fetch_add_explicit(object,operand,order) \
284 atomic_fetch_add(object,operand)
286 # define atomic_fetch_sub(object,operand) \
287 atomic_fetch_OP(object,operand,-)
288 # define atomic_fetch_sub_explicit(object,operand,order) \
289 atomic_fetch_sub(object,operand)
291 # define atomic_fetch_or(object,operand) \
292 atomic_fetch_OP(object,operand,|)
293 # define atomic_fetch_or_explicit(object,operand,order) \
294 atomic_fetch_or(object,operand)
296 # define atomic_fetch_xor(object,operand) \
297 atomic_fetch_OP(object,operand,^)
298 # define atomic_fetch_xor_explicit(object,operand,order) \
299 atomic_fetch_sub(object,operand)
301 # define atomic_fetch_and(object,operand) \
302 atomic_fetch_OP(object,operand,&)
303 # define atomic_fetch_and_explicit(object,operand,order) \
304 atomic_fetch_and(object,operand)
306 # define atomic_flag_test_and_set(object) \
307 atomic_exchange(object, true)
309 # define atomic_flag_test_and_set_explicit(object,order) \
310 atomic_flag_test_and_set(object)
312 # define atomic_flag_clear(object) \
313 atomic_store(object, false)
315 # define atomic_flag_clear_explicit(object,order) \
316 atomic_flag_clear(object)
318 # elif defined (_MSC_VER)
320 # include <windows.h>
322 /*** Use the Interlocked API. ***/
324 /* Define macros in order to dispatch to the correct function depending on the type.
325 Several ranges are need because some operations are not implemented for all types. */
326 # define atomic_type_dispatch_32_64(operation, object, ...) \
327 (sizeof(*object) == 4 ? operation((LONG *)object, __VA_ARGS__) : \
328 sizeof(*object) == 8 ? operation##64((LONGLONG *)object, __VA_ARGS__) : \
329 (abort(), 0))
331 # define atomic_type_dispatch_16_64(operation, object, ...) \
332 (sizeof(*object) == 2 ? operation##16((short *)object, __VA_ARGS__) : \
333 atomic_type_dispatch_32_64(operation, object, __VA_ARGS__))
335 # define atomic_type_dispatch_8_64(operation, object, ...) \
336 (sizeof(*object) == 1 ? operation##8((char *)object, __VA_ARGS__) : \
337 atomic_type_dispatch_16_64(operation, object, __VA_ARGS__))
339 # define atomic_store(object,desired) \
340 atomic_type_dispatch_16_64(InterlockedExchange, object, desired)
341 # define atomic_store_explicit(object,desired,order) \
342 atomic_store(object, desired)
344 # define atomic_load(object) \
345 atomic_type_dispatch_16_64(InterlockedCompareExchange, object, 0, 0)
346 # define atomic_load_explicit(object,order) \
347 atomic_load(object)
349 # define atomic_exchange(object,desired) \
350 atomic_type_dispatch_16_64(InterlockedExchange, object, desired)
351 # define atomic_exchange_explicit(object,desired,order) \
352 atomic_exchange(object, desired)
354 # define atomic_compare_exchange_strong(object,expected,desired) \
355 atomic_type_dispatch_16_64(InterlockedCompareExchange, object, *expected, desired) == *expected
356 # define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
357 atomic_compare_exchange_strong(object, expected, desired)
358 # define atomic_compare_exchange_weak(object,expected,desired) \
359 atomic_compare_exchange_strong(object, expected, desired)
360 # define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
361 atomic_compare_exchange_weak(object, expected, desired)
363 # define atomic_fetch_add(object,operand) \
364 atomic_type_dispatch_32_64(InterlockedExchangeAdd, object, operand)
365 # define atomic_fetch_add_explicit(object,operand,order) \
366 atomic_fetch_add(object, operand)
368 # define atomic_fetch_sub(object,operand) \
369 atomic_type_dispatch_32_64(InterlockedExchangeAdd, object, -(LONGLONG)operand)
370 # define atomic_fetch_sub_explicit(object,operand,order) \
371 atomic_fetch_sub(object, operand)
373 # define atomic_fetch_or(object,operand) \
374 atomic_type_dispatch_8_64(InterlockedOr, object, operand)
375 # define atomic_fetch_or_explicit(object,operand,order) \
376 atomic_fetch_or(object, operand)
378 # define atomic_fetch_xor(object,operand) \
379 atomic_type_dispatch_8_64(InterlockedXor, object, operand)
380 # define atomic_fetch_xor_explicit(object,operand,order) \
381 atomic_fetch_sub(object, operand)
383 # define atomic_fetch_and(object,operand) \
384 atomic_type_dispatch_8_64(InterlockedAnd, object, operand)
385 # define atomic_fetch_and_explicit(object,operand,order) \
386 atomic_fetch_and(object, operand)
388 # define atomic_flag_test_and_set(object) \
389 atomic_exchange(object, true)
391 # define atomic_flag_test_and_set_explicit(object,order) \
392 atomic_flag_test_and_set(object)
394 # define atomic_flag_clear(object) \
395 atomic_store(object, false)
397 # define atomic_flag_clear_explicit(object,order) \
398 atomic_flag_clear(object)
400 # else
401 # error FIXME: implement atomic operations for this compiler.
402 # endif
403 # endif
405 typedef atomic_uint_least32_t vlc_atomic_float;
407 static inline void vlc_atomic_init_float(vlc_atomic_float *var, float f)
409 union { float f; uint32_t i; } u;
410 u.f = f;
411 atomic_init(var, u.i);
414 /** Helper to retrieve a single precision from an atom. */
415 static inline float vlc_atomic_load_float(vlc_atomic_float *atom)
417 union { float f; uint32_t i; } u;
418 u.i = atomic_load(atom);
419 return u.f;
422 /** Helper to store a single precision into an atom. */
423 static inline void vlc_atomic_store_float(vlc_atomic_float *atom, float f)
425 union { float f; uint32_t i; } u;
426 u.f = f;
427 atomic_store(atom, u.i);
430 #endif