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)
32 /* Prefer GCC atomic ops if the target supports it (see configure.in). */
33 #elif defined(USE_GCC_ATOMIC_OPS)
35 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
36 gint32 exch, gint32 comp)
38 return __sync_val_compare_and_swap (dest, comp, exch);
41 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
43 return __sync_val_compare_and_swap (dest, comp, exch);
46 static inline gint32 InterlockedIncrement(volatile gint32 *val)
48 return __sync_add_and_fetch (val, 1);
51 static inline gint32 InterlockedDecrement(volatile gint32 *val)
53 return __sync_add_and_fetch (val, -1);
56 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
61 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
65 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
71 } while (__sync_val_compare_and_swap (val, old_val, new_val) != old_val);
75 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
77 return __sync_fetch_and_add (val, add);
80 #elif defined(__NetBSD__) && defined(HAVE_ATOMIC_OPS)
82 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
83 gint32 exch, gint32 comp)
85 return atomic_cas_32((uint32_t*)dest, comp, exch);
88 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
90 return atomic_cas_ptr(dest, comp, exch);
93 static inline gint32 InterlockedIncrement(volatile gint32 *val)
95 return atomic_inc_32_nv((uint32_t*)val);
98 static inline gint32 InterlockedDecrement(volatile gint32 *val)
100 return atomic_dec_32_nv((uint32_t*)val);
103 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
105 return atomic_swap_32((uint32_t*)val, new_val);
108 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
111 return atomic_swap_ptr(val, new_val);
114 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
116 return atomic_add_32_nv((uint32_t*)val, add) - add;
119 #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
122 static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
124 register volatile gint32 *dest asm("g1") = _dest;
125 register gint32 comp asm("o4") = _comp;
126 register gint32 exch asm("o5") = _exch;
128 __asm__ __volatile__(
129 /* cas [%%g1], %%o4, %%o5 */
132 : "0" (exch), "r" (dest), "r" (comp)
139 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
141 register volatile gpointer *dest asm("g1") = _dest;
142 register gpointer comp asm("o4") = _comp;
143 register gpointer exch asm("o5") = _exch;
145 __asm__ __volatile__(
147 /* casx [%%g1], %%o4, %%o5 */
150 /* cas [%%g1], %%o4, %%o5 */
154 : "0" (exch), "r" (dest), "r" (comp)
161 static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
163 register volatile gint32 *dest asm("g1") = _dest;
164 register gint32 tmp asm("o4");
165 register gint32 ret asm("o5");
167 __asm__ __volatile__(
168 "1: ld [%%g1], %%o4\n\t"
169 " add %%o4, 1, %%o5\n\t"
170 /* cas [%%g1], %%o4, %%o5 */
171 " .word 0xdbe0500c\n\t"
172 " cmp %%o4, %%o5\n\t"
175 : "=&r" (tmp), "=&r" (ret)
183 static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
185 register volatile gint32 *dest asm("g1") = _dest;
186 register gint32 tmp asm("o4");
187 register gint32 ret asm("o5");
189 __asm__ __volatile__(
190 "1: ld [%%g1], %%o4\n\t"
191 " sub %%o4, 1, %%o5\n\t"
192 /* cas [%%g1], %%o4, %%o5 */
193 " .word 0xdbe0500c\n\t"
194 " cmp %%o4, %%o5\n\t"
197 : "=&r" (tmp), "=&r" (ret)
205 static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
207 register volatile gint32 *dest asm("g1") = _dest;
208 register gint32 tmp asm("o4");
209 register gint32 ret asm("o5");
211 __asm__ __volatile__(
212 "1: ld [%%g1], %%o4\n\t"
214 /* cas [%%g1], %%o4, %%o5 */
215 " .word 0xdbe0500c\n\t"
216 " cmp %%o4, %%o5\n\t"
219 : "=&r" (tmp), "=&r" (ret)
220 : "r" (dest), "r" (exch)
227 static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
229 register volatile gpointer *dest asm("g1") = _dest;
230 register gpointer tmp asm("o4");
231 register gpointer ret asm("o5");
233 __asm__ __volatile__(
235 "1: ldx [%%g1], %%o4\n\t"
237 "1: ld [%%g1], %%o4\n\t"
241 /* casx [%%g1], %%o4, %%o5 */
242 " .word 0xdbf0500c\n\t"
244 /* cas [%%g1], %%o4, %%o5 */
245 " .word 0xdbe0500c\n\t"
247 " cmp %%o4, %%o5\n\t"
250 : "=&r" (tmp), "=&r" (ret)
251 : "r" (dest), "r" (exch)
258 static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
260 register volatile gint32 *dest asm("g1") = _dest;
261 register gint32 tmp asm("o4");
262 register gint32 ret asm("o5");
264 __asm__ __volatile__(
265 "1: ld [%%g1], %%o4\n\t"
266 " add %%o4, %3, %%o5\n\t"
267 /* cas [%%g1], %%o4, %%o5 */
268 " .word 0xdbe0500c\n\t"
269 " cmp %%o4, %%o5\n\t"
271 " add %%o5, %3, %%o5"
272 : "=&r" (tmp), "=&r" (ret)
273 : "r" (dest), "r" (add)
282 InterlockedCompareExchange(volatile gint32 *dest,
283 gint32 exch, gint32 comp)
287 __asm__ __volatile__ ("\tLA\t1,%0\n"
290 : "+m" (*dest), "=&r" (old)
291 : "r" (exch), "r" (comp)
296 static inline gpointer
297 InterlockedCompareExchangePointer(volatile gpointer *dest,
303 __asm__ __volatile__ ("\tLA\t1,%0\n"
305 "\tCSG\t%1,%2,0(1)\n"
306 : "+m" (*dest), "=&r" (old)
307 : "r" (exch), "r" (comp)
314 InterlockedIncrement(volatile gint32 *val)
318 __asm__ __volatile__ ("\tLA\t2,%1\n"
325 : "=r" (tmp), "+m" (*val)
332 InterlockedDecrement(volatile gint32 *val)
336 __asm__ __volatile__ ("\tLA\t2,%1\n"
343 : "=r" (tmp), "+m" (*val)
350 InterlockedExchange(volatile gint32 *val, gint32 new_val)
354 __asm__ __volatile__ ("\tLA\t1,%0\n"
358 : "+m" (*val), "=&r" (ret)
365 static inline gpointer
366 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
370 __asm__ __volatile__ ("\tLA\t1,%0\n"
372 "\tCSG\t%1,%2,0(1)\n"
374 : "+m" (*val), "=&r" (ret)
382 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
386 __asm__ __volatile__ ("\tLA\t2,%1\n"
392 : "=&r" (ret), "+m" (*val)
399 #elif defined(__ia64__)
401 #ifdef __INTEL_COMPILER
402 #include <ia64intrin.h>
405 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
406 gint32 exch, gint32 comp)
411 #ifdef __INTEL_COMPILER
412 old = _InterlockedCompareExchange (dest, exch, comp);
414 /* cmpxchg4 zero extends the value read from memory */
415 real_comp = (guint64)(guint32)comp;
416 asm volatile ("mov ar.ccv = %2 ;;\n\t"
417 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
418 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
424 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
425 gpointer exch, gpointer comp)
429 #ifdef __INTEL_COMPILER
430 old = _InterlockedCompareExchangePointer (dest, exch, comp);
432 asm volatile ("mov ar.ccv = %2 ;;\n\t"
433 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
434 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
440 static inline gint32 InterlockedIncrement(gint32 volatile *val)
442 #ifdef __INTEL_COMPILER
443 return _InterlockedIncrement (val);
449 } while (InterlockedCompareExchange (val, old + 1, old) != old);
455 static inline gint32 InterlockedDecrement(gint32 volatile *val)
457 #ifdef __INTEL_COMPILER
458 return _InterlockedDecrement (val);
464 } while (InterlockedCompareExchange (val, old - 1, old) != old);
470 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
472 #ifdef __INTEL_COMPILER
473 return _InterlockedExchange (dest, new_val);
479 } while (InterlockedCompareExchange (dest, new_val, res) != res);
485 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
487 #ifdef __INTEL_COMPILER
488 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
494 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
500 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
504 #ifdef __INTEL_COMPILER
505 old = _InterlockedExchangeAdd (val, add);
509 } while (InterlockedCompareExchange (val, old + add, old) != old);
517 #define WAPI_NO_ATOMIC_ASM
519 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
520 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
521 extern gint32 InterlockedIncrement(volatile gint32 *dest);
522 extern gint32 InterlockedDecrement(volatile gint32 *dest);
523 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
524 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
525 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
529 #endif /* _WAPI_ATOMIC_H_ */