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)
26 /* mingw is missing InterlockedCompareExchange64 () from winbase.h */
27 #if HAVE_DECL_INTERLOCKEDCOMPAREEXCHANGE64==0
28 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
30 return __sync_val_compare_and_swap (dest, comp, exch);
34 /* Prefer GCC atomic ops if the target supports it (see configure.in). */
35 #elif defined(USE_GCC_ATOMIC_OPS)
37 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
38 gint32 exch, gint32 comp)
40 return __sync_val_compare_and_swap (dest, comp, exch);
43 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
45 return __sync_val_compare_and_swap (dest, comp, exch);
48 static inline gint32 InterlockedIncrement(volatile gint32 *val)
50 return __sync_add_and_fetch (val, 1);
53 static inline gint32 InterlockedDecrement(volatile gint32 *val)
55 return __sync_add_and_fetch (val, -1);
58 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
63 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
67 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
73 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
77 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
79 return __sync_fetch_and_add (val, add);
82 #if defined (TARGET_OSX)
83 #define BROKEN_64BIT_ATOMICS_INTRINSIC 1
86 #if !defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
88 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
90 return __sync_val_compare_and_swap (dest, comp, exch);
95 #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
98 static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
100 register volatile gint32 *dest asm("g1") = _dest;
101 register gint32 comp asm("o4") = _comp;
102 register gint32 exch asm("o5") = _exch;
104 __asm__ __volatile__(
105 /* cas [%%g1], %%o4, %%o5 */
108 : "0" (exch), "r" (dest), "r" (comp)
115 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
117 register volatile gpointer *dest asm("g1") = _dest;
118 register gpointer comp asm("o4") = _comp;
119 register gpointer exch asm("o5") = _exch;
121 __asm__ __volatile__(
123 /* casx [%%g1], %%o4, %%o5 */
126 /* cas [%%g1], %%o4, %%o5 */
130 : "0" (exch), "r" (dest), "r" (comp)
137 static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
139 register volatile gint32 *dest asm("g1") = _dest;
140 register gint32 tmp asm("o4");
141 register gint32 ret asm("o5");
143 __asm__ __volatile__(
144 "1: ld [%%g1], %%o4\n\t"
145 " add %%o4, 1, %%o5\n\t"
146 /* cas [%%g1], %%o4, %%o5 */
147 " .word 0xdbe0500c\n\t"
148 " cmp %%o4, %%o5\n\t"
151 : "=&r" (tmp), "=&r" (ret)
159 static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
161 register volatile gint32 *dest asm("g1") = _dest;
162 register gint32 tmp asm("o4");
163 register gint32 ret asm("o5");
165 __asm__ __volatile__(
166 "1: ld [%%g1], %%o4\n\t"
167 " sub %%o4, 1, %%o5\n\t"
168 /* cas [%%g1], %%o4, %%o5 */
169 " .word 0xdbe0500c\n\t"
170 " cmp %%o4, %%o5\n\t"
173 : "=&r" (tmp), "=&r" (ret)
181 static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
183 register volatile gint32 *dest asm("g1") = _dest;
184 register gint32 tmp asm("o4");
185 register gint32 ret asm("o5");
187 __asm__ __volatile__(
188 "1: ld [%%g1], %%o4\n\t"
190 /* cas [%%g1], %%o4, %%o5 */
191 " .word 0xdbe0500c\n\t"
192 " cmp %%o4, %%o5\n\t"
195 : "=&r" (tmp), "=&r" (ret)
196 : "r" (dest), "r" (exch)
203 static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
205 register volatile gpointer *dest asm("g1") = _dest;
206 register gpointer tmp asm("o4");
207 register gpointer ret asm("o5");
209 __asm__ __volatile__(
211 "1: ldx [%%g1], %%o4\n\t"
213 "1: ld [%%g1], %%o4\n\t"
217 /* casx [%%g1], %%o4, %%o5 */
218 " .word 0xdbf0500c\n\t"
220 /* cas [%%g1], %%o4, %%o5 */
221 " .word 0xdbe0500c\n\t"
223 " cmp %%o4, %%o5\n\t"
226 : "=&r" (tmp), "=&r" (ret)
227 : "r" (dest), "r" (exch)
234 static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
236 register volatile gint32 *dest asm("g1") = _dest;
237 register gint32 tmp asm("o4");
238 register gint32 ret asm("o5");
240 __asm__ __volatile__(
241 "1: ld [%%g1], %%o4\n\t"
242 " add %%o4, %3, %%o5\n\t"
243 /* cas [%%g1], %%o4, %%o5 */
244 " .word 0xdbe0500c\n\t"
245 " cmp %%o4, %%o5\n\t"
247 " add %%o5, %3, %%o5"
248 : "=&r" (tmp), "=&r" (ret)
249 : "r" (dest), "r" (add)
258 InterlockedCompareExchange(volatile gint32 *dest,
259 gint32 exch, gint32 comp)
263 __asm__ __volatile__ ("\tLA\t1,%0\n"
266 : "+m" (*dest), "=&r" (old)
267 : "r" (exch), "r" (comp)
272 static inline gpointer
273 InterlockedCompareExchangePointer(volatile gpointer *dest,
279 __asm__ __volatile__ ("\tLA\t1,%0\n"
281 "\tCSG\t%1,%2,0(1)\n"
282 : "+m" (*dest), "=&r" (old)
283 : "r" (exch), "r" (comp)
290 InterlockedIncrement(volatile gint32 *val)
294 __asm__ __volatile__ ("\tLA\t2,%1\n"
301 : "=r" (tmp), "+m" (*val)
308 InterlockedDecrement(volatile gint32 *val)
312 __asm__ __volatile__ ("\tLA\t2,%1\n"
319 : "=r" (tmp), "+m" (*val)
326 InterlockedExchange(volatile gint32 *val, gint32 new_val)
330 __asm__ __volatile__ ("\tLA\t1,%0\n"
334 : "+m" (*val), "=&r" (ret)
341 static inline gpointer
342 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
346 __asm__ __volatile__ ("\tLA\t1,%0\n"
348 "\tCSG\t%1,%2,0(1)\n"
350 : "+m" (*val), "=&r" (ret)
358 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
362 __asm__ __volatile__ ("\tLA\t2,%1\n"
368 : "=&r" (ret), "+m" (*val)
375 #elif defined(__ia64__)
377 #ifdef __INTEL_COMPILER
378 #include <ia64intrin.h>
381 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
382 gint32 exch, gint32 comp)
387 #ifdef __INTEL_COMPILER
388 old = _InterlockedCompareExchange (dest, exch, comp);
390 /* cmpxchg4 zero extends the value read from memory */
391 real_comp = (guint64)(guint32)comp;
392 asm volatile ("mov ar.ccv = %2 ;;\n\t"
393 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
394 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
400 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
401 gpointer exch, gpointer comp)
405 #ifdef __INTEL_COMPILER
406 old = _InterlockedCompareExchangePointer (dest, exch, comp);
408 asm volatile ("mov ar.ccv = %2 ;;\n\t"
409 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
410 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
416 static inline gint32 InterlockedIncrement(gint32 volatile *val)
418 #ifdef __INTEL_COMPILER
419 return _InterlockedIncrement (val);
425 } while (InterlockedCompareExchange (val, old + 1, old) != old);
431 static inline gint32 InterlockedDecrement(gint32 volatile *val)
433 #ifdef __INTEL_COMPILER
434 return _InterlockedDecrement (val);
440 } while (InterlockedCompareExchange (val, old - 1, old) != old);
446 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
448 #ifdef __INTEL_COMPILER
449 return _InterlockedExchange (dest, new_val);
455 } while (InterlockedCompareExchange (dest, new_val, res) != res);
461 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
463 #ifdef __INTEL_COMPILER
464 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
470 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
476 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
480 #ifdef __INTEL_COMPILER
481 old = _InterlockedExchangeAdd (val, add);
485 } while (InterlockedCompareExchange (val, old + add, old) != old);
493 #define WAPI_NO_ATOMIC_ASM
495 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
496 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
497 extern gint32 InterlockedIncrement(volatile gint32 *dest);
498 extern gint32 InterlockedDecrement(volatile gint32 *dest);
499 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
500 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
501 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
505 #if defined (WAPI_NO_ATOMIC_ASM) || defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
507 extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp);
511 #endif /* _WAPI_ATOMIC_H_ */