]> git.sesse.net Git - vlc/blob - include/vlc_atomic.h
libvlc_MetaRequest: increment item i_preparse_depth
[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 # else
36
37 #  define ATOMIC_FLAG_INIT false
38
39 #  define ATOMIC_VAR_INIT(value) (value)
40
41 #  define atomic_init(obj, value) \
42     do { *(obj) = (value); } while(0)
43
44 #  define kill_dependency(y) \
45     ((void)0)
46
47 #  define atomic_thread_fence(order) \
48     __sync_synchronize()
49
50 #  define atomic_signal_fence(order) \
51     ((void)0)
52
53 #  define atomic_is_lock_free(obj) \
54     false
55
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;
111
112 # if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || (defined (__clang__) && (defined (__x86_64__) || defined (__i386__)))
113
114 /*** Intel/GCC atomics ***/
115
116 #  define atomic_store(object,desired) \
117     do { \
118         *(object) = (desired); \
119         __sync_synchronize(); \
120     } while (0)
121
122 #  define atomic_store_explicit(object,desired,order) \
123     atomic_store(object,desired)
124
125 #  define atomic_load(object) \
126     (__sync_synchronize(), *(object))
127
128 #  define atomic_load_explicit(object,order) \
129     atomic_load(object)
130
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; \
139 })
140
141 #  define atomic_exchange_explicit(object,desired,order) \
142     atomic_exchange(object,desired)
143
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; \
150 })
151
152 #  define atomic_compare_exchange_strong(object,expected,desired) \
153     atomic_compare_exchange(object, expected, desired)
154
155 #  define atomic_compare_exchange_strong_explicit(object,expected,desired,order) \
156     atomic_compare_exchange_strong(object, expected, desired)
157
158 #  define atomic_compare_exchange_weak(object,expected,desired) \
159     atomic_compare_exchange(object, expected, desired)
160
161 #  define atomic_compare_exchange_weak_explicit(object,expected,desired,order) \
162     atomic_compare_exchange_weak(object, expected, desired)
163
164 #  define atomic_fetch_add(object,operand) \
165     __sync_fetch_and_add(object, operand)
166
167 #  define atomic_fetch_add_explicit(object,operand,order) \
168     atomic_fetch_add(object,operand)
169
170 #  define atomic_fetch_sub(object,operand) \
171     __sync_fetch_and_sub(object, operand)
172
173 #  define atomic_fetch_sub_explicit(object,operand,order) \
174     atomic_fetch_sub(object,operand)
175
176 #  define atomic_fetch_or(object,operand) \
177     __sync_fetch_and_or(object, operand)
178
179 #  define atomic_fetch_or_explicit(object,operand,order) \
180     atomic_fetch_or(object,operand)
181
182 #  define atomic_fetch_xor(object,operand) \
183     __sync_fetch_and_sub(object, operand)
184
185 #  define atomic_fetch_xor_explicit(object,operand,order) \
186     atomic_fetch_sub(object,operand)
187
188 #  define atomic_fetch_and(object,operand) \
189     __sync_fetch_and_and(object, operand)
190
191 #  define atomic_fetch_and_explicit(object,operand,order) \
192     atomic_fetch_and(object,operand)
193
194 #  define atomic_flag_test_and_set(object) \
195     atomic_exchange(object, true)
196
197 #  define atomic_flag_test_and_set_explicit(object,order) \
198     atomic_flag_test_and_set(object)
199
200 #  define atomic_flag_clear(object) \
201     atomic_store(object, false)
202
203 #  define atomic_flag_clear_explicit(object,order) \
204     atomic_flag_clear(object)
205
206 # elif defined (__GNUC__)
207
208 /*** No atomics ***/
209
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)
220
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; \
229 })
230 #  define atomic_load_explicit(object,order) \
231     atomic_load(object)
232
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; \
243 })
244 #  define atomic_exchange_explicit(object,desired,order) \
245     atomic_exchange(object,desired)
246
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; \
261 })
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)
268
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; \
279 })
280
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)
285
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)
290
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)
295
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)
300
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)
305
306 #  define atomic_flag_test_and_set(object) \
307     atomic_exchange(object, true)
308
309 #  define atomic_flag_test_and_set_explicit(object,order) \
310     atomic_flag_test_and_set(object)
311
312 #  define atomic_flag_clear(object) \
313     atomic_store(object, false)
314
315 #  define atomic_flag_clear_explicit(object,order) \
316     atomic_flag_clear(object)
317
318 # elif defined (_MSC_VER)
319
320 # include <windows.h>
321
322 /*** Use the Interlocked API. ***/
323
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))
330
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__))
334
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__))
338
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)
343
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)
348
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)
353
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)
362
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)
367
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)
372
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)
377
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)
382
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)
387
388 #  define atomic_flag_test_and_set(object) \
389     atomic_exchange(object, true)
390
391 #  define atomic_flag_test_and_set_explicit(object,order) \
392     atomic_flag_test_and_set(object)
393
394 #  define atomic_flag_clear(object) \
395     atomic_store(object, false)
396
397 #  define atomic_flag_clear_explicit(object,order) \
398     atomic_flag_clear(object)
399
400 # else
401 #  error FIXME: implement atomic operations for this compiler.
402 # endif
403 # endif
404
405 typedef atomic_uint_least32_t vlc_atomic_float;
406
407 static inline void vlc_atomic_init_float(vlc_atomic_float *var, float f)
408 {
409     union { float f; uint32_t i; } u;
410     u.f = f;
411     atomic_init(var, u.i);
412 }
413
414 /** Helper to retrieve a single precision from an atom. */
415 static inline float vlc_atomic_load_float(vlc_atomic_float *atom)
416 {
417     union { float f; uint32_t i; } u;
418     u.i = atomic_load(atom);
419     return u.f;
420 }
421
422 /** Helper to store a single precision into an atom. */
423 static inline void vlc_atomic_store_float(vlc_atomic_float *atom, float f)
424 {
425     union { float f; uint32_t i; } u;
426     u.f = f;
427     atomic_store(atom, u.i);
428 }
429
430 #endif