v2 / thirdparty / stdatomic / win / atomic.h
559 lines · 448 sloc · 17.27 KB · 07ee934f822c7a2980e0dc31ca635a6c734dcbca
Raw
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#ifndef COMPAT_ATOMICS_WIN32_STDATOMIC_H
20#define COMPAT_ATOMICS_WIN32_STDATOMIC_H
21
22#define WIN32_LEAN_AND_MEAN
23#include <stddef.h>
24#include <stdint.h>
25#include <windows.h>
26
27#ifdef _MSC_VER
28#define cpu_relax() _mm_pause()
29#else
30#define cpu_relax() __asm__ __volatile__ ("pause")
31#endif
32
33#define ATOMIC_FLAG_INIT 0
34
35#define ATOMIC_VAR_INIT(value) (value)
36
37#define atomic_init(obj, value) \
38 do \
39 { \
40 *(obj) = (value); \
41 } while (0)
42
43#define kill_dependency(y) ((void)0)
44
45// memory order policies - we use "sequentially consistent" by default
46
47#define memory_order_relaxed 0
48#define memory_order_consume 1
49#define memory_order_acquire 2
50#define memory_order_release 3
51#define memory_order_acq_rel 4
52#define memory_order_seq_cst 5
53
54#ifdef _MSC_VER
55#define atomic_thread_fence(order) \
56 do { \
57 switch (order) { \
58 case memory_order_release: \
59 _WriteBarrier(); \
60 _ReadWriteBarrier(); \
61 break; \
62 case memory_order_acquire: \
63 _ReadBarrier(); \
64 _ReadWriteBarrier(); \
65 break; \
66 case memory_order_acq_rel: \
67 _ReadBarrier(); \
68 _WriteBarrier(); \
69 _ReadWriteBarrier(); \
70 break; \
71 case memory_order_seq_cst: \
72 MemoryBarrier(); \
73 break; \
74 default: /* relaxed, consume */ \
75 break; \
76 } \
77 } while (0)
78#else
79#define atomic_thread_fence(order) do { \
80 switch (order) { \
81 case memory_order_relaxed: \
82 break; \
83 case memory_order_acquire: \
84 case memory_order_consume: \
85 case memory_order_release: \
86 case memory_order_acq_rel: \
87 __asm__ __volatile__ ("" : : : "memory"); \
88 break; \
89 case memory_order_seq_cst: \
90 __asm__ __volatile__ ("mfence" : : : "memory"); \
91 break; \
92 default: \
93 __asm__ __volatile__ ("mfence" : : : "memory"); \
94 break; \
95 } \
96} while (0)
97#endif
98
99#define atomic_signal_fence(order) \
100 ((void)0)
101
102#define atomic_is_lock_free(obj) 0
103
104typedef intptr_t atomic_flag;
105typedef _Atomic bool atomic_bool;
106typedef _Atomic char atomic_char;
107typedef _Atomic signed char atomic_schar;
108typedef _Atomic unsigned char atomic_uchar;
109typedef _Atomic short atomic_short;
110typedef _Atomic unsigned short atomic_ushort;
111typedef _Atomic int atomic_int;
112typedef _Atomic unsigned int atomic_uint;
113typedef _Atomic long atomic_long;
114typedef _Atomic unsigned long atomic_ulong;
115typedef _Atomic long long atomic_llong;
116typedef _Atomic unsigned long long atomic_ullong;
117typedef intptr_t atomic_wchar_t;
118typedef intptr_t atomic_int_least8_t;
119typedef intptr_t atomic_uint_least8_t;
120typedef intptr_t atomic_int_least16_t;
121typedef intptr_t atomic_uint_least16_t;
122typedef intptr_t atomic_int_least32_t;
123typedef intptr_t atomic_uint_least32_t;
124typedef intptr_t atomic_int_least64_t;
125typedef intptr_t atomic_uint_least64_t;
126typedef intptr_t atomic_int_fast8_t;
127typedef intptr_t atomic_uint_fast8_t;
128typedef intptr_t atomic_int_fast16_t;
129typedef intptr_t atomic_uint_fast16_t;
130typedef intptr_t atomic_int_fast32_t;
131typedef intptr_t atomic_uint_fast32_t;
132typedef intptr_t atomic_int_fast64_t;
133typedef intptr_t atomic_uint_fast64_t;
134typedef _Atomic intptr_t atomic_intptr_t;
135typedef _Atomic uintptr_t atomic_uintptr_t;
136typedef _Atomic size_t atomic_size_t;
137typedef intptr_t atomic_ptrdiff_t;
138typedef intptr_t atomic_intmax_t;
139typedef intptr_t atomic_uintmax_t;
140
141#ifdef __TINYC__
142/*
143 For TCC it is missing the x64 version of _InterlockedExchangeAdd64 so we
144 fake it (works the same) with InterlockedCompareExchange64 until it
145 succeeds
146*/
147
148__CRT_INLINE LONGLONG _InterlockedExchangeAdd64(LONGLONG volatile *Addend, LONGLONG Value)
149{
150 LONGLONG Old;
151 do
152 {
153 Old = *Addend;
154 } while (InterlockedCompareExchange64(Addend, Old + Value, Old) != Old);
155 return Old;
156}
157
158__CRT_INLINE LONG _InterlockedExchangeAdd(LONG volatile *Addend, LONG Value)
159{
160 LONG Old;
161 do
162 {
163 Old = *Addend;
164 } while (InterlockedCompareExchange(Addend, Old + Value, Old) != Old);
165 return Old;
166}
167
168#ifndef InterlockedIncrement64
169#define InterlockedIncrement64 _InterlockedExchangeAdd64
170#endif
171
172#endif
173
174#define atomic_store(object, desired) \
175 do \
176 { \
177 MemoryBarrier(); \
178 *(object) = (desired); \
179 MemoryBarrier(); \
180 } while (0)
181
182#define atomic_store_explicit(object, desired, order) \
183 atomic_store(object, desired)
184
185#define atomic_load(object) \
186 (MemoryBarrier(), *(object))
187
188#define atomic_load_explicit(object, order) \
189 atomic_load(object)
190
191#define atomic_exchange(object, desired) \
192 InterlockedExchangePointer(object, desired)
193
194#define atomic_exchange_explicit(object, desired, order) \
195 atomic_exchange(object, desired)
196
197static inline int atomic_compare_exchange_strong(intptr_t volatile *object, intptr_t volatile *expected,
198 intptr_t desired)
199{
200 intptr_t old = *expected;
201 *expected = (intptr_t)InterlockedCompareExchangePointer(
202 (PVOID *)object, (PVOID)desired, (PVOID)old);
203 return *expected == old;
204}
205
206#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
207 atomic_compare_exchange_strong(object, expected, desired)
208
209#define atomic_compare_exchange_weak(object, expected, desired) \
210 atomic_compare_exchange_strong(object, expected, desired)
211
212#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
213 atomic_compare_exchange_weak(object, expected, desired)
214
215#ifdef _WIN64
216
217#define atomic_fetch_add(object, operand) \
218 InterlockedExchangeAdd64(object, operand)
219
220#define atomic_fetch_sub(object, operand) \
221 InterlockedExchangeAdd64(object, -(operand))
222
223#define atomic_fetch_or(object, operand) \
224 InterlockedOr64(object, operand)
225
226#define atomic_fetch_xor(object, operand) \
227 InterlockedXor64(object, operand)
228
229#define atomic_fetch_and(object, operand) \
230 InterlockedAnd64(object, operand)
231#else
232#define atomic_fetch_add(object, operand) \
233 InterlockedExchangeAdd(object, operand)
234
235#define atomic_fetch_sub(object, operand) \
236 InterlockedExchangeAdd(object, -(operand))
237
238#define atomic_fetch_or(object, operand) \
239 InterlockedOr(object, operand)
240
241#define atomic_fetch_xor(object, operand) \
242 InterlockedXor(object, operand)
243
244#define atomic_fetch_and(object, operand) \
245 InterlockedAnd(object, operand)
246#endif /* _WIN64 */
247
248/* specialized versions with explicit object size */
249
250#define atomic_load_ptr atomic_load
251#define atomic_store_ptr atomic_store
252#define atomic_compare_exchange_weak_ptr atomic_compare_exchange_weak
253#define atomic_compare_exchange_strong_ptr atomic_compare_exchange_strong
254#define atomic_exchange_ptr atomic_exchange
255#define atomic_fetch_add_ptr atomic_fetch_add
256#define atomic_fetch_sub_ptr atomic_fetch_sub
257#define atomic_fetch_and_ptr atomic_fetch_and
258#define atomic_fetch_or_ptr atomic_fetch_or
259#define atomic_fetch_xor_ptr atomic_fetch_xor
260
261static inline void atomic_store_u64(unsigned long long volatile * object, unsigned long long desired) {
262 do {
263 MemoryBarrier();
264 *(object) = (desired);
265 MemoryBarrier();
266 } while (0);
267}
268
269static inline unsigned long long atomic_load_u64(unsigned long long volatile * object) {
270 return (MemoryBarrier(), *(object));
271}
272
273#define atomic_exchange_u64(object, desired) \
274 InterlockedExchange64(object, desired)
275
276static inline int atomic_compare_exchange_strong_u64(unsigned long long volatile * object, unsigned long long volatile * expected,
277 unsigned long long desired)
278{
279 unsigned long long old = *expected;
280 *expected = InterlockedCompareExchange64(object, desired, old);
281 return *expected == old;
282}
283
284#define atomic_compare_exchange_weak_u64(object, expected, desired) \
285 atomic_compare_exchange_strong_u64(object, expected, desired)
286
287#define atomic_fetch_add_u64(object, operand) \
288 InterlockedExchangeAdd64(object, operand)
289
290#define atomic_fetch_sub_u64(object, operand) \
291 InterlockedExchangeAdd64(object, -(operand))
292
293#define atomic_fetch_or_u64(object, operand) \
294 InterlockedOr64(object, operand)
295
296#define atomic_fetch_xor_u64(object, operand) \
297 InterlockedXor64(object, operand)
298
299#define atomic_fetch_and_u64(object, operand) \
300 InterlockedAnd64(object, operand)
301
302
303
304static inline void atomic_store_u32(unsigned volatile * object, unsigned desired) {
305 do {
306 MemoryBarrier();
307 *(object) = (desired);
308 MemoryBarrier();
309 } while (0);
310}
311
312static inline unsigned atomic_load_u32(unsigned volatile * object) {
313 return (MemoryBarrier(), *(object));
314}
315
316#define atomic_exchange_u32(object, desired) \
317 InterlockedExchange(object, desired)
318
319static inline int atomic_compare_exchange_strong_u32(unsigned volatile * object, unsigned volatile * expected,
320 unsigned desired)
321{
322 unsigned old = *expected;
323 *expected = InterlockedCompareExchange((void *)object, desired, old);
324 return *expected == old;
325}
326
327#define atomic_compare_exchange_weak_u32(object, expected, desired) \
328 atomic_compare_exchange_strong_u32(object, expected, desired)
329
330#define atomic_fetch_add_u32(object, operand) \
331 InterlockedExchangeAdd(object, operand)
332
333#define atomic_fetch_sub_u32(object, operand) \
334 InterlockedExchangeAdd(object, -(operand))
335
336#define atomic_fetch_or_u32(object, operand) \
337 InterlockedOr(object, operand)
338
339#define atomic_fetch_xor_u32(object, operand) \
340 InterlockedXor(object, operand)
341
342#define atomic_fetch_and_u32(object, operand) \
343 InterlockedAnd(object, operand)
344
345#ifdef _MSC_VER
346
347#define InterlockedExchangeAdd16 _InterlockedExchangeAdd16
348
349#else
350
351#define InterlockedExchange16 ManualInterlockedExchange16
352#define InterlockedExchangeAdd16 ManualInterlockedExchangeAdd16
353
354static inline uint16_t ManualInterlockedExchange16(volatile uint16_t* object, uint16_t desired) {
355 __asm__ __volatile__ (
356 "xchgw %0, %1"
357 : "+r" (desired),
358 "+m" (*object)
359 :
360 : "memory"
361 );
362 return desired;
363}
364
365static inline unsigned short ManualInterlockedExchangeAdd16(unsigned short volatile* Addend, unsigned short Value) {
366 __asm__ __volatile__ (
367 "lock xaddw %w[value], %[mem]"
368 : [mem] "+m" (*Addend), [value] "+r" (Value)
369 : : "memory"
370 );
371 return Value;
372}
373#endif
374
375static inline void atomic_store_u16(unsigned short volatile * object, unsigned short desired) {
376 do {
377 MemoryBarrier();
378 *(object) = (desired);
379 MemoryBarrier();
380 } while (0);
381}
382
383static inline unsigned short atomic_load_u16(unsigned short volatile * object) {
384 return (MemoryBarrier(), *(object));
385}
386
387#define atomic_exchange_u16(object, desired) \
388 InterlockedExchange16(object, desired)
389
390static inline int atomic_compare_exchange_strong_u16(unsigned short volatile * object, unsigned short volatile * expected,
391 unsigned short desired)
392{
393 unsigned short old = *expected;
394 *expected = InterlockedCompareExchange16(object, desired, old);
395 return *expected == old;
396}
397
398#define atomic_compare_exchange_weak_u16(object, expected, desired) \
399 atomic_compare_exchange_strong_u16((void*)object, expected, desired)
400
401#define atomic_fetch_add_u16(object, operand) \
402 InterlockedExchangeAdd16(object, operand)
403
404#define atomic_fetch_sub_u16(object, operand) \
405 InterlockedExchangeAdd16(object, -(operand))
406
407#define atomic_fetch_or_u16(object, operand) \
408 InterlockedOr16(object, operand)
409
410#define atomic_fetch_xor_u16(object, operand) \
411 InterlockedXor16(object, operand)
412
413#define atomic_fetch_and_u16(object, operand) \
414 InterlockedAnd16(object, operand)
415
416
417#define atomic_fetch_add_explicit(object, operand, order) \
418 atomic_fetch_add(object, operand)
419
420#define atomic_fetch_sub_explicit(object, operand, order) \
421 atomic_fetch_sub(object, operand)
422
423#define atomic_fetch_or_explicit(object, operand, order) \
424 atomic_fetch_or(object, operand)
425
426#define atomic_fetch_xor_explicit(object, operand, order) \
427 atomic_fetch_xor(object, operand)
428
429#define atomic_fetch_and_explicit(object, operand, order) \
430 atomic_fetch_and(object, operand)
431
432#define atomic_flag_test_and_set(object) \
433 atomic_exchange(object, 1)
434
435#define atomic_flag_test_and_set_explicit(object, order) \
436 atomic_flag_test_and_set(object)
437
438#define atomic_flag_clear(object) \
439 atomic_store(object, 0)
440
441#define atomic_flag_clear_explicit(object, order) \
442 atomic_flag_clear(object)
443
444#ifdef _MSC_VER
445
446#define InterlockedCompareExchange8 _InterlockedCompareExchange8
447#define InterlockedExchangeAdd8 _InterlockedExchangeAdd8
448#define InterlockedOr8 _InterlockedOr8
449#define InterlockedXor8 _InterlockedXor8
450#define InterlockedAnd8 _InterlockedAnd8
451
452#else
453
454#define InterlockedExchange8 ManualInterlockedExchange8
455#define InterlockedCompareExchange8 ManualInterlockedCompareExchange8
456#define InterlockedExchangeAdd8 ManualInterlockedExchangeAdd8
457#define InterlockedOr8 ManualInterlockedOr8
458#define InterlockedXor8 ManualInterlockedXor8
459#define InterlockedAnd8 ManualInterlockedAnd8
460
461static inline char ManualInterlockedExchange8(char volatile* object, char desired) {
462 __asm__ __volatile__ (
463 "xchgb %0, %1"
464 : "+q" (desired), "+m" (*object)
465 :
466 : "memory"
467 );
468 return desired;
469}
470
471static inline unsigned char ManualInterlockedCompareExchange8(unsigned char volatile * dest, unsigned char exchange, unsigned char comparand) {
472 unsigned char result;
473
474 __asm__ volatile (
475 "lock cmpxchgb %[exchange], %[dest]"
476 : "=a" (result), [dest] "+m" (*dest)
477 : [exchange] "q" (exchange), "a" (comparand)
478 : "memory"
479 );
480
481 return result;
482}
483
484static inline unsigned char ManualInterlockedExchangeAdd8(unsigned char volatile * dest, unsigned char value) {
485 unsigned char oldValue;
486 unsigned char newValue;
487 do {
488 oldValue = *dest;
489 } while (ManualInterlockedCompareExchange8(dest, oldValue + value, oldValue) != oldValue);
490 return oldValue;
491}
492
493static inline unsigned char ManualInterlockedOr8(unsigned char volatile * dest, unsigned char value) {
494 unsigned char oldValue;
495 do {
496 oldValue = *dest;
497 } while (ManualInterlockedCompareExchange8(dest, oldValue | value, oldValue) != oldValue);
498 return oldValue;
499}
500
501static inline unsigned char ManualInterlockedXor8(unsigned char volatile * dest, unsigned char value) {
502 unsigned char oldValue;
503 do {
504 oldValue = *dest;
505 } while (ManualInterlockedCompareExchange8(dest, oldValue ^ value, oldValue) != oldValue);
506 return oldValue;
507}
508
509static inline unsigned char ManualInterlockedAnd8(unsigned char volatile * dest, unsigned char value) {
510 unsigned char oldValue;
511 do {
512 oldValue = *dest;
513 } while (ManualInterlockedCompareExchange8(dest, oldValue & value, oldValue) != oldValue);
514 return oldValue;
515}
516#endif
517
518static inline void atomic_store_byte(unsigned char volatile * object, unsigned char desired) {
519 do {
520 MemoryBarrier();
521 *(object) = (desired);
522 MemoryBarrier();
523 } while (0);
524}
525
526static inline unsigned char atomic_load_byte(unsigned char volatile * object) {
527 return (MemoryBarrier(), *(object));
528}
529
530#define atomic_exchange_byte(object, desired) \
531 InterlockedExchange8(object, desired)
532
533static inline int atomic_compare_exchange_strong_byte(unsigned char volatile * object, unsigned char volatile * expected,
534 unsigned char desired)
535{
536 unsigned char old = *expected;
537 *expected = InterlockedCompareExchange8(object, desired, old);
538 return *expected == old;
539}
540
541#define atomic_compare_exchange_weak_byte(object, expected, desired) \
542 atomic_compare_exchange_strong_byte(object, expected, desired)
543
544#define atomic_fetch_add_byte(object, operand) \
545 InterlockedExchangeAdd8(object, operand)
546
547#define atomic_fetch_sub_byte(object, operand) \
548 InterlockedExchangeAdd8(object, -(operand))
549
550#define atomic_fetch_or_byte(object, operand) \
551 InterlockedOr8(object, operand)
552
553#define atomic_fetch_xor_byte(object, operand) \
554 InterlockedXor8(object, operand)
555
556#define atomic_fetch_and_byte(object, operand) \
557 InterlockedAnd8(object, operand)
558
559#endif /* COMPAT_ATOMICS_WIN32_STDATOMIC_H */
560