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)
255 #elif defined(__ia64__)
257 #ifdef __INTEL_COMPILER
258 #include <ia64intrin.h>
261 static inline gint32 InterlockedCompareExchange(gint32 volatile *dest,
262 gint32 exch, gint32 comp)
267 #ifdef __INTEL_COMPILER
268 old = _InterlockedCompareExchange (dest, exch, comp);
270 /* cmpxchg4 zero extends the value read from memory */
271 real_comp = (guint64)(guint32)comp;
272 asm volatile ("mov ar.ccv = %2 ;;\n\t"
273 "cmpxchg4.acq %0 = [%1], %3, ar.ccv\n\t"
274 : "=r" (old) : "r" (dest), "r" (real_comp), "r" (exch));
280 static inline gpointer InterlockedCompareExchangePointer(gpointer volatile *dest,
281 gpointer exch, gpointer comp)
285 #ifdef __INTEL_COMPILER
286 old = _InterlockedCompareExchangePointer (dest, exch, comp);
288 asm volatile ("mov ar.ccv = %2 ;;\n\t"
289 "cmpxchg8.acq %0 = [%1], %3, ar.ccv\n\t"
290 : "=r" (old) : "r" (dest), "r" (comp), "r" (exch));
296 static inline gint32 InterlockedIncrement(gint32 volatile *val)
298 #ifdef __INTEL_COMPILER
299 return _InterlockedIncrement (val);
305 } while (InterlockedCompareExchange (val, old + 1, old) != old);
311 static inline gint32 InterlockedDecrement(gint32 volatile *val)
313 #ifdef __INTEL_COMPILER
314 return _InterlockedDecrement (val);
320 } while (InterlockedCompareExchange (val, old - 1, old) != old);
326 static inline gint32 InterlockedExchange(gint32 volatile *dest, gint32 new_val)
328 #ifdef __INTEL_COMPILER
329 return _InterlockedExchange (dest, new_val);
335 } while (InterlockedCompareExchange (dest, new_val, res) != res);
341 static inline gpointer InterlockedExchangePointer(gpointer volatile *dest, gpointer new_val)
343 #ifdef __INTEL_COMPILER
344 return (gpointer)_InterlockedExchange64 ((gint64*)dest, (gint64)new_val);
350 } while (InterlockedCompareExchangePointer (dest, new_val, res) != res);
356 static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add)
360 #ifdef __INTEL_COMPILER
361 old = _InterlockedExchangeAdd (val, add);
365 } while (InterlockedCompareExchange (val, old + add, old) != old);
373 #define WAPI_NO_ATOMIC_ASM
375 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
376 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
377 extern gint32 InterlockedIncrement(volatile gint32 *dest);
378 extern gint32 InterlockedDecrement(volatile gint32 *dest);
379 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
380 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
381 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
385 #if defined (WAPI_NO_ATOMIC_ASM) || defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
387 extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp);
391 #endif /* _WAPI_ATOMIC_H_ */