2 * atomic.h: Atomic operations
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2012 Xamarin Inc
11 #ifndef _WAPI_ATOMIC_H_
12 #define _WAPI_ATOMIC_H_
17 #ifdef ENABLE_EXTENSION_MODULE
18 #include "../../../mono-extensions/mono/utils/atomic.h"
21 /* On Windows, we always use the functions provided by the Windows API. */
22 #if defined(__WIN32__) || defined(_WIN32)
25 #include <mono/utils/mono-membar.h>
27 /* mingw is missing InterlockedCompareExchange64 () from winbase.h */
28 #if HAVE_DECL_INTERLOCKEDCOMPAREEXCHANGE64==0
29 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
31 return __sync_val_compare_and_swap (dest, comp, exch);
35 /* mingw is missing InterlockedExchange64 () from winbase.h */
36 #if HAVE_DECL_INTERLOCKEDEXCHANGE64==0
37 static inline gint64 InterlockedExchange64(volatile gint64 *val, gint64 new_val)
42 } while (InterlockedCompareExchange64 (val, new_val, old_val) != old_val);
47 /* mingw is missing InterlockedIncrement64 () from winbase.h */
48 #if HAVE_DECL_INTERLOCKEDINCREMENT64==0
49 static inline gint64 InterlockedIncrement64(volatile gint64 *val)
51 return __sync_add_and_fetch (val, 1);
55 /* mingw is missing InterlockedDecrement64 () from winbase.h */
56 #if HAVE_DECL_INTERLOCKEDDECREMENT64==0
57 static inline gint64 InterlockedDecrement64(volatile gint64 *val)
59 return __sync_sub_and_fetch (val, 1);
63 /* mingw is missing InterlockedAdd () from winbase.h */
64 #if HAVE_DECL_INTERLOCKEDADD==0
65 static inline gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
67 return __sync_add_and_fetch (dest, add);
71 /* mingw is missing InterlockedAdd64 () from winbase.h */
72 #if HAVE_DECL_INTERLOCKEDADD64==0
73 static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
75 return __sync_add_and_fetch (dest, add);
79 /* And now for some dirty hacks... The Windows API doesn't
80 * provide any useful primitives for this (other than getting
81 * into architecture-specific madness), so use CAS. */
83 static inline gint32 InterlockedRead(volatile gint32 *src)
85 return InterlockedCompareExchange (src, 0, 0);
88 static inline gint64 InterlockedRead64(volatile gint64 *src)
90 return InterlockedCompareExchange64 (src, 0, 0);
93 static inline gpointer InterlockedReadPointer(volatile gpointer *src)
95 return InterlockedCompareExchangePointer (src, NULL, NULL);
98 static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
100 InterlockedExchange (dst, val);
103 static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val)
105 InterlockedExchange64 (dst, val);
108 static inline void InterlockedWritePointer(volatile gpointer *dst, gpointer val)
110 InterlockedExchangePointer (dst, val);
113 /* We can't even use CAS for these, so write them out
114 * explicitly according to x86(_64) semantics... */
116 static inline gint8 InterlockedRead8(volatile gint8 *src)
121 static inline gint16 InterlockedRead16(volatile gint16 *src)
126 static inline void InterlockedWrite8(volatile gint8 *dst, gint8 val)
129 mono_memory_barrier ();
132 static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
135 mono_memory_barrier ();
138 /* Prefer GCC atomic ops if the target supports it (see configure.in). */
139 #elif defined(USE_GCC_ATOMIC_OPS)
141 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
142 gint32 exch, gint32 comp)
144 return __sync_val_compare_and_swap (dest, comp, exch);
147 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
149 return __sync_val_compare_and_swap (dest, comp, exch);
152 static inline gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
154 return __sync_add_and_fetch (dest, add);
157 static inline gint32 InterlockedIncrement(volatile gint32 *val)
159 return __sync_add_and_fetch (val, 1);
162 static inline gint32 InterlockedDecrement(volatile gint32 *val)
164 return __sync_sub_and_fetch (val, 1);
167 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
172 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
176 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
182 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
186 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
188 return __sync_fetch_and_add (val, add);
191 static inline gint8 InterlockedRead8(volatile gint8 *src)
193 /* Kind of a hack, but GCC doesn't give us anything better, and it's
194 * certainly not as bad as using a CAS loop. */
195 return __sync_fetch_and_add (src, 0);
198 static inline gint16 InterlockedRead16(volatile gint16 *src)
200 return __sync_fetch_and_add (src, 0);
203 static inline gint32 InterlockedRead(volatile gint32 *src)
205 return __sync_fetch_and_add (src, 0);
208 static inline void InterlockedWrite8(volatile gint8 *dst, gint8 val)
210 /* Nothing useful from GCC at all, so fall back to CAS. */
214 } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
217 static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
222 } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
225 static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
227 /* Nothing useful from GCC at all, so fall back to CAS. */
231 } while (__sync_val_compare_and_swap (dst, old_val, val) != old_val);
234 #if defined (TARGET_OSX) || defined (__arm__) || (defined (__mips__) && !defined (__mips64)) || (defined (__powerpc__) && !defined (__powerpc64__)) || (defined (__sparc__) && !defined (__arch64__))
235 #define BROKEN_64BIT_ATOMICS_INTRINSIC 1
238 #if !defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
240 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
242 return __sync_val_compare_and_swap (dest, comp, exch);
245 static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
247 return __sync_add_and_fetch (dest, add);
250 static inline gint64 InterlockedIncrement64(volatile gint64 *val)
252 return __sync_add_and_fetch (val, 1);
255 static inline gint64 InterlockedDecrement64(volatile gint64 *val)
257 return __sync_sub_and_fetch (val, 1);
260 static inline gint64 InterlockedExchangeAdd64(volatile gint64 *val, gint64 add)
262 return __sync_fetch_and_add (val, add);
265 static inline gint64 InterlockedRead64(volatile gint64 *src)
267 /* Kind of a hack, but GCC doesn't give us anything better. */
268 return __sync_fetch_and_add (src, 0);
273 /* Implement 64-bit cmpxchg by hand or emulate it. */
274 extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp);
276 /* Implement all other 64-bit atomics in terms of a specialized CAS
277 * in this case, since chances are that the other 64-bit atomic
278 * intrinsics are broken too.
281 static inline gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add)
286 } while (InterlockedCompareExchange64 (dest, old_val + add, old_val) != old_val);
290 static inline gint64 InterlockedIncrement64(volatile gint64 *val)
296 } while (InterlockedCompareExchange64 (val, set, get) != get);
300 static inline gint64 InterlockedDecrement64(volatile gint64 *val)
306 } while (InterlockedCompareExchange64 (val, set, get) != get);
310 static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
316 } while (InterlockedCompareExchange64 (dest, set, get) != get);
320 static inline gint64 InterlockedRead64(volatile gint64 *src)
322 return InterlockedCompareExchange64 (src, 0, 0);
327 static inline gpointer InterlockedReadPointer(volatile gpointer *src)
329 return InterlockedCompareExchangePointer (src, NULL, NULL);
332 static inline void InterlockedWritePointer(volatile gpointer *dst, gpointer val)
334 InterlockedExchangePointer (dst, val);
337 /* We always implement this in terms of a 64-bit cmpxchg since
338 * GCC doesn't have an intrisic to model it anyway. */
339 static inline gint64 InterlockedExchange64(volatile gint64 *val, gint64 new_val)
344 } while (InterlockedCompareExchange64 (val, new_val, old_val) != old_val);
348 static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val)
350 /* Nothing useful from GCC at all, so fall back to CAS. */
351 InterlockedExchange64 (dst, val);
354 #elif defined(__ia64__)
356 #ifdef __INTEL_COMPILER
357 #include <ia64intrin.h>
360 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
361 gint32 exch, gint32 comp)
366 #ifdef __INTEL_COMPILER
367 old = _InterlockedCompareExchange (dest, exch, comp);
369 /* cmpxchg4 zero extends the value read from memory */
370 real_comp = (guint64)(guint32)comp;
371 asm volatile ("mov ar.ccv = %2 ;;\n\t"
372 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
373 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
379 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
380 gpointer exch, gpointer comp)
384 #ifdef __INTEL_COMPILER
385 old = _InterlockedCompareExchangePointer (dest, exch, comp);
387 asm volatile ("mov ar.ccv = %2 ;;\n\t"
388 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
389 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
395 static inline gint32 InterlockedIncrement(gint32 volatile *val)
397 #ifdef __INTEL_COMPILER
398 return _InterlockedIncrement (val);
404 } while (InterlockedCompareExchange (val, old + 1, old) != old);
410 static inline gint32 InterlockedDecrement(gint32 volatile *val)
412 #ifdef __INTEL_COMPILER
413 return _InterlockedDecrement (val);
419 } while (InterlockedCompareExchange (val, old - 1, old) != old);
425 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
427 #ifdef __INTEL_COMPILER
428 return _InterlockedExchange (dest, new_val);
434 } while (InterlockedCompareExchange (dest, new_val, res) != res);
440 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
442 #ifdef __INTEL_COMPILER
443 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
449 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
455 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
459 #ifdef __INTEL_COMPILER
460 old = _InterlockedExchangeAdd (val, add);
464 } while (InterlockedCompareExchange (val, old + add, old) != old);
472 #define WAPI_NO_ATOMIC_ASM
474 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
475 extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp);
476 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
477 extern gint32 InterlockedAdd(volatile gint32 *dest, gint32 add);
478 extern gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add);
479 extern gint32 InterlockedIncrement(volatile gint32 *dest);
480 extern gint64 InterlockedIncrement64(volatile gint64 *dest);
481 extern gint32 InterlockedDecrement(volatile gint32 *dest);
482 extern gint64 InterlockedDecrement64(volatile gint64 *dest);
483 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
484 extern gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch);
485 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
486 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
487 extern gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add);
488 extern gint8 InterlockedRead8(volatile gint8 *src);
489 extern gint16 InterlockedRead16(volatile gint16 *src);
490 extern gint32 InterlockedRead(volatile gint32 *src);
491 extern gint64 InterlockedRead64(volatile gint64 *src);
492 extern gpointer InterlockedReadPointer(volatile gpointer *src);
493 extern void InterlockedWrite8(volatile gint8 *dst, gint8 val);
494 extern void InterlockedWrite16(volatile gint16 *dst, gint16 val);
495 extern void InterlockedWrite(volatile gint32 *dst, gint32 val);
496 extern void InterlockedWrite64(volatile gint64 *dst, gint64 val);
497 extern void InterlockedWritePointer(volatile gpointer *dst, gpointer val);
501 #endif /* _WAPI_ATOMIC_H_ */