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_
14 #if defined(__NetBSD__)
15 #include <sys/param.h>
17 #if __NetBSD_Version__ > 499004000
18 #include <sys/atomic.h>
19 #define HAVE_ATOMIC_OPS
27 /* On Windows, we always use the functions provided by the Windows API. */
28 #if defined(__WIN32__) || defined(_WIN32)
31 #define HAS_64BITS_ATOMICS 1
33 /* Prefer GCC atomic ops if the target supports it (see configure.in). */
34 #elif defined(USE_GCC_ATOMIC_OPS)
36 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
37 gint32 exch, gint32 comp)
39 return __sync_val_compare_and_swap (dest, comp, exch);
42 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
44 return __sync_val_compare_and_swap (dest, comp, exch);
47 static inline gint32 InterlockedIncrement(volatile gint32 *val)
49 return __sync_add_and_fetch (val, 1);
52 static inline gint32 InterlockedDecrement(volatile gint32 *val)
54 return __sync_add_and_fetch (val, -1);
57 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
62 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
66 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
72 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
76 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
78 return __sync_fetch_and_add (val, add);
81 #if defined (TARGET_ARM) && defined (TARGET_MACH)
82 #define BROKEN_64BIT_ATOMICS_INTRINSIC 1
86 #if !defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
87 #define HAS_64BITS_ATOMICS 1
89 static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
91 return __sync_val_compare_and_swap (dest, comp, exch);
97 #elif defined(__NetBSD__) && defined(HAVE_ATOMIC_OPS)
99 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
100 gint32 exch, gint32 comp)
102 return atomic_cas_32((uint32_t*)dest, comp, exch);
105 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
107 return atomic_cas_ptr(dest, comp, exch);
110 static inline gint32 InterlockedIncrement(volatile gint32 *val)
112 return atomic_inc_32_nv((uint32_t*)val);
115 static inline gint32 InterlockedDecrement(volatile gint32 *val)
117 return atomic_dec_32_nv((uint32_t*)val);
120 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
122 return atomic_swap_32((uint32_t*)val, new_val);
125 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
128 return atomic_swap_ptr(val, new_val);
131 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
133 return atomic_add_32_nv((uint32_t*)val, add) - add;
136 #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
139 static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
141 register volatile gint32 *dest asm("g1") = _dest;
142 register gint32 comp asm("o4") = _comp;
143 register gint32 exch asm("o5") = _exch;
145 __asm__ __volatile__(
146 /* cas [%%g1], %%o4, %%o5 */
149 : "0" (exch), "r" (dest), "r" (comp)
156 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
158 register volatile gpointer *dest asm("g1") = _dest;
159 register gpointer comp asm("o4") = _comp;
160 register gpointer exch asm("o5") = _exch;
162 __asm__ __volatile__(
164 /* casx [%%g1], %%o4, %%o5 */
167 /* cas [%%g1], %%o4, %%o5 */
171 : "0" (exch), "r" (dest), "r" (comp)
178 static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
180 register volatile gint32 *dest asm("g1") = _dest;
181 register gint32 tmp asm("o4");
182 register gint32 ret asm("o5");
184 __asm__ __volatile__(
185 "1: ld [%%g1], %%o4\n\t"
186 " add %%o4, 1, %%o5\n\t"
187 /* cas [%%g1], %%o4, %%o5 */
188 " .word 0xdbe0500c\n\t"
189 " cmp %%o4, %%o5\n\t"
192 : "=&r" (tmp), "=&r" (ret)
200 static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
202 register volatile gint32 *dest asm("g1") = _dest;
203 register gint32 tmp asm("o4");
204 register gint32 ret asm("o5");
206 __asm__ __volatile__(
207 "1: ld [%%g1], %%o4\n\t"
208 " sub %%o4, 1, %%o5\n\t"
209 /* cas [%%g1], %%o4, %%o5 */
210 " .word 0xdbe0500c\n\t"
211 " cmp %%o4, %%o5\n\t"
214 : "=&r" (tmp), "=&r" (ret)
222 static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
224 register volatile gint32 *dest asm("g1") = _dest;
225 register gint32 tmp asm("o4");
226 register gint32 ret asm("o5");
228 __asm__ __volatile__(
229 "1: ld [%%g1], %%o4\n\t"
231 /* cas [%%g1], %%o4, %%o5 */
232 " .word 0xdbe0500c\n\t"
233 " cmp %%o4, %%o5\n\t"
236 : "=&r" (tmp), "=&r" (ret)
237 : "r" (dest), "r" (exch)
244 static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
246 register volatile gpointer *dest asm("g1") = _dest;
247 register gpointer tmp asm("o4");
248 register gpointer ret asm("o5");
250 __asm__ __volatile__(
252 "1: ldx [%%g1], %%o4\n\t"
254 "1: ld [%%g1], %%o4\n\t"
258 /* casx [%%g1], %%o4, %%o5 */
259 " .word 0xdbf0500c\n\t"
261 /* cas [%%g1], %%o4, %%o5 */
262 " .word 0xdbe0500c\n\t"
264 " cmp %%o4, %%o5\n\t"
267 : "=&r" (tmp), "=&r" (ret)
268 : "r" (dest), "r" (exch)
275 static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
277 register volatile gint32 *dest asm("g1") = _dest;
278 register gint32 tmp asm("o4");
279 register gint32 ret asm("o5");
281 __asm__ __volatile__(
282 "1: ld [%%g1], %%o4\n\t"
283 " add %%o4, %3, %%o5\n\t"
284 /* cas [%%g1], %%o4, %%o5 */
285 " .word 0xdbe0500c\n\t"
286 " cmp %%o4, %%o5\n\t"
288 " add %%o5, %3, %%o5"
289 : "=&r" (tmp), "=&r" (ret)
290 : "r" (dest), "r" (add)
299 InterlockedCompareExchange(volatile gint32 *dest,
300 gint32 exch, gint32 comp)
304 __asm__ __volatile__ ("\tLA\t1,%0\n"
307 : "+m" (*dest), "=&r" (old)
308 : "r" (exch), "r" (comp)
313 static inline gpointer
314 InterlockedCompareExchangePointer(volatile gpointer *dest,
320 __asm__ __volatile__ ("\tLA\t1,%0\n"
322 "\tCSG\t%1,%2,0(1)\n"
323 : "+m" (*dest), "=&r" (old)
324 : "r" (exch), "r" (comp)
331 InterlockedIncrement(volatile gint32 *val)
335 __asm__ __volatile__ ("\tLA\t2,%1\n"
342 : "=r" (tmp), "+m" (*val)
349 InterlockedDecrement(volatile gint32 *val)
353 __asm__ __volatile__ ("\tLA\t2,%1\n"
360 : "=r" (tmp), "+m" (*val)
367 InterlockedExchange(volatile gint32 *val, gint32 new_val)
371 __asm__ __volatile__ ("\tLA\t1,%0\n"
375 : "+m" (*val), "=&r" (ret)
382 static inline gpointer
383 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
387 __asm__ __volatile__ ("\tLA\t1,%0\n"
389 "\tCSG\t%1,%2,0(1)\n"
391 : "+m" (*val), "=&r" (ret)
399 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
403 __asm__ __volatile__ ("\tLA\t2,%1\n"
409 : "=&r" (ret), "+m" (*val)
416 #elif defined(__ia64__)
418 #ifdef __INTEL_COMPILER
419 #include <ia64intrin.h>
422 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
423 gint32 exch, gint32 comp)
428 #ifdef __INTEL_COMPILER
429 old = _InterlockedCompareExchange (dest, exch, comp);
431 /* cmpxchg4 zero extends the value read from memory */
432 real_comp = (guint64)(guint32)comp;
433 asm volatile ("mov ar.ccv = %2 ;;\n\t"
434 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
435 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
441 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
442 gpointer exch, gpointer comp)
446 #ifdef __INTEL_COMPILER
447 old = _InterlockedCompareExchangePointer (dest, exch, comp);
449 asm volatile ("mov ar.ccv = %2 ;;\n\t"
450 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
451 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
457 static inline gint32 InterlockedIncrement(gint32 volatile *val)
459 #ifdef __INTEL_COMPILER
460 return _InterlockedIncrement (val);
466 } while (InterlockedCompareExchange (val, old + 1, old) != old);
472 static inline gint32 InterlockedDecrement(gint32 volatile *val)
474 #ifdef __INTEL_COMPILER
475 return _InterlockedDecrement (val);
481 } while (InterlockedCompareExchange (val, old - 1, old) != old);
487 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
489 #ifdef __INTEL_COMPILER
490 return _InterlockedExchange (dest, new_val);
496 } while (InterlockedCompareExchange (dest, new_val, res) != res);
502 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
504 #ifdef __INTEL_COMPILER
505 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
511 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
517 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
521 #ifdef __INTEL_COMPILER
522 old = _InterlockedExchangeAdd (val, add);
526 } while (InterlockedCompareExchange (val, old + add, old) != old);
534 #define WAPI_NO_ATOMIC_ASM
536 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
537 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
538 extern gint32 InterlockedIncrement(volatile gint32 *dest);
539 extern gint32 InterlockedDecrement(volatile gint32 *dest);
540 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
541 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
542 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
546 #ifndef HAS_64BITS_ATOMICS
547 extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp);
550 #endif /* _WAPI_ATOMIC_H_ */