2 * atomic.h: Atomic operations
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
10 #ifndef _WAPI_ATOMIC_H_
11 #define _WAPI_ATOMIC_H_
15 #include "mono/io-layer/wapi.h"
18 #define WAPI_ATOMIC_ASM
21 * NB: The *Pointer() functions here assume that
22 * sizeof(pointer)==sizeof(gint32)
24 * NB2: These asm functions assume 486+ (some of the opcodes dont
25 * exist on 386). If this becomes an issue, we can get configure to
26 * fall back to the non-atomic C versions of these calls.
29 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
30 gint32 exch, gint32 comp)
34 __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
35 : "=m" (*dest), "=a" (old)
36 : "r" (exch), "m" (*dest), "a" (comp));
40 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
44 __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
45 : "=m" (*dest), "=a" (old)
46 : "r" (exch), "m" (*dest), "a" (comp));
50 static inline gint32 InterlockedIncrement(volatile gint32 *val)
54 __asm__ __volatile__ ("lock; xaddl %0, %1"
55 : "=r" (tmp), "=m" (*val)
56 : "0" (1), "m" (*val));
61 static inline gint32 InterlockedDecrement(volatile gint32 *val)
65 __asm__ __volatile__ ("lock; xaddl %0, %1"
66 : "=r" (tmp), "=m" (*val)
67 : "0" (-1), "m" (*val));
74 * http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
75 * for the reasons for using cmpxchg and a loop here.
77 * That url is no longer valid, but it's still in the google cache at the
78 * moment: http://www.google.com/search?q=cache:http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
80 * For the time being, http://msdn.microsoft.com/msdnmag/issues/0700/Win32/
81 * might work. Bet it will change soon enough though.
83 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
87 __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
88 : "=m" (*val), "=a" (ret)
89 : "r" (new_val), "m" (*val), "a" (*val));
94 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
99 __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
100 : "=m" (*val), "=a" (ret)
101 : "r" (new_val), "m" (*val), "a" (*val));
106 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
110 __asm__ __volatile__ ("lock; xaddl %0, %1"
111 : "=r" (ret), "=m" (*val)
112 : "0" (add), "m" (*val));
117 #elif defined(sparc) || defined (__sparc__)
118 #define WAPI_ATOMIC_ASM
120 #define BEGIN_SPIN(tmp,lock) \
121 __asm__ __volatile__("1: ldstub [%1],%0\n\t" \
129 #define END_SPIN(lock) \
130 __asm__ __volatile__("stb %%g0, [%0]" \
136 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
138 static unsigned char lock;
154 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
156 static unsigned char lock;
172 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
174 static unsigned char lock;
188 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
190 static unsigned char lock;
204 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
206 static unsigned char lock;
220 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
222 static unsigned char lock;
236 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
238 static unsigned char lock;
254 #define WAPI_ATOMIC_ASM
257 InterlockedCompareExchange(volatile gint32 *dest,
258 gint32 exch, gint32 comp)
262 __asm__ __volatile__ ("\tL\t%1,%0\n"
264 : "=m" (*dest), "=r" (old)
265 : "r" (exch), "r" (comp)
270 #define InterlockedCompareExchangePointer InterlockedCompareExchange
273 InterlockedIncrement(volatile gint32 *val)
277 __asm__ __volatile__ ("0:\tL\t%0,%1\n"
282 : "=r" (tmp), "+m" (*val)
289 InterlockedDecrement(volatile gint32 *val)
293 __asm__ __volatile__ ("0:\tL\t%0,%1\n"
298 : "=r" (tmp), "+m" (*val)
306 InterlockedExchange(volatile gint32 *val, gint32 new_val)
310 __asm__ __volatile__ ("0:\tL\t%1,%0\n"
313 : "+m" (*val), "=r" (ret)
320 #define InterlockedExchangePointer InterlockedExchange
323 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
327 __asm__ __volatile__ ("0:\tL\t%0,%1\n"
332 : "=r" (ret), "+m" (*val)
340 #define WAPI_ATOMIC_ASM
342 static inline gint32 InterlockedIncrement(volatile gint32 *val)
346 __asm__ __volatile__ ("\nL_ii_loop:\n\t"
347 "lwarx %0, 0, %2\n\t"
349 "stwcx. %0, 0, %2\n\t"
351 : "=r" (tmp) : "0" (tmp), "r" (val));
355 static inline gint32 InterlockedDecrement(volatile gint32 *val)
359 __asm__ __volatile__ ("\nL_id_loop:\n\t"
360 "lwarx %0, 0, %2\n\t"
361 "addi %0, %0, -1\n\t"
362 "stwcx. %0, 0, %2\n\t"
364 : "=r" (tmp) : "0" (tmp), "r" (val));
368 #define InterlockedCompareExchangePointer InterlockedCompareExchange
370 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
371 gint32 exch, gint32 comp) {
374 __asm__ __volatile__ ("\nL_ice_loop:\n\t"
375 "lwarx %0, 0, %1\n\t"
377 "bne- L_ice_diff\n\t"
378 "stwcx. %4, 0, %1\n\t"
382 : "r" (dest), "0" (tmp) ,"r" (comp), "r" (exch));
386 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
390 __asm__ __volatile__ ("\nL_ie_loop:\n\t"
391 "lwarx %0, 0, %1\n\t"
392 "stwcx. %2, 0, %1\n\t"
394 : "=r" (tmp) : "r" (dest), "r" (exch));
397 #define InterlockedExchangePointer InterlockedExchange
399 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
403 __asm__ __volatile__ ("\nL_iea_loop:\n\t"
404 "lwarx %0, 0, %2\n\t"
406 "stwcx. %1, 0, %2\n\t"
408 : "=r" (tmp), "=r" (add)
409 : "r" (dest), "0" (tmp), "1" (add));
413 #elif defined(__arm__)
414 #define WAPI_ATOMIC_ASM
416 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
420 __asm__ __volatile__ ( "0:\n\t"
424 "swp %0, %3, [%2]\n\t"
426 "swpne %3, %0, [%2]\n\t"
429 : "=&r" (a), "=&r" (b)
430 : "r" (dest), "r" (exch), "r" (comp)
436 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
440 __asm__ __volatile__ ( "0:\n\t"
444 "swpeq %0, %3, [%2]\n\t"
446 "swpne %3, %0, [%2]\n\t"
449 : "=&r" (a), "=&r" (b)
450 : "r" (dest), "r" (exch), "r" (comp)
456 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
460 __asm__ __volatile__ ( "0:\n\t"
463 "swp %2, %1, [%3]\n\t"
465 "swpne %1, %2, [%3]\n\t"
467 : "=&r" (a), "=&r" (b), "=&r" (c)
468 : "r" (dest), "r" (1)
474 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
478 __asm__ __volatile__ ( "0:\n\t"
481 "swp %2, %1, [%3]\n\t"
483 "swpne %1, %2, [%3]\n\t"
485 : "=&r" (a), "=&r" (b), "=&r" (c)
486 : "r" (dest), "r" (-1)
492 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
496 __asm__ __volatile__ ( "swp %0, %2, [%1]"
498 : "r" (dest), "r" (exch));
503 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
507 __asm__ __volatile__ ( "swp %0, %2, [%1]"
509 : "r" (dest), "r" (exch));
514 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
518 __asm__ __volatile__ ( "0:\n\t"
521 "swp %2, %1, [%3]\n\t"
523 "swpne %1, %2, [%3]\n\t"
525 : "=&r" (a), "=&r" (b), "=&r" (c)
526 : "r" (dest), "r" (add)
534 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
535 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
536 extern gint32 InterlockedIncrement(volatile gint32 *dest);
537 extern gint32 InterlockedDecrement(volatile gint32 *dest);
538 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
539 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
540 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
543 #endif /* _WAPI_ATOMIC_H_ */