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
121 #define BEGIN_SPIN(tmp,lock) \
122 __asm__ __volatile__("1: ldstub [%1],%0\n\t" \
130 #define END_SPIN(lock) \
131 __asm__ __volatile__("stb %%g0, [%0]" \
136 static inline void begin_spin(volatile unsigned char *lock)
138 asm("1: ldstub [%i0], %l0");
143 #define BEGIN_SPIN(tmp,lock) begin_spin(&lock);
144 #define END_SPIN(lock) ((lock) = 0);
147 extern volatile unsigned char _wapi_sparc_lock;
149 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
154 BEGIN_SPIN(tmp,_wapi_sparc_lock)
161 END_SPIN(_wapi_sparc_lock)
166 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
171 BEGIN_SPIN(tmp,_wapi_sparc_lock)
178 END_SPIN(_wapi_sparc_lock)
183 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
188 BEGIN_SPIN(tmp,_wapi_sparc_lock)
193 END_SPIN(_wapi_sparc_lock)
198 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
203 BEGIN_SPIN(tmp,_wapi_sparc_lock)
208 END_SPIN(_wapi_sparc_lock)
213 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
218 BEGIN_SPIN(tmp,_wapi_sparc_lock)
223 END_SPIN(_wapi_sparc_lock)
228 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
233 BEGIN_SPIN(tmp,_wapi_sparc_lock)
238 END_SPIN(_wapi_sparc_lock)
243 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
248 BEGIN_SPIN(tmp,_wapi_sparc_lock)
253 END_SPIN(_wapi_sparc_lock)
260 #define WAPI_ATOMIC_ASM
263 InterlockedCompareExchange(volatile gint32 *dest,
264 gint32 exch, gint32 comp)
268 __asm__ __volatile__ ("\tL\t%1,%0\n"
271 : "=m" (*dest), "=r" (old)
272 : "r" (exch), "r" (comp)
277 #define InterlockedCompareExchangePointer InterlockedCompareExchange
280 InterlockedIncrement(volatile gint32 *val)
284 __asm__ __volatile__ ("\tLA\t2,%1\n"
288 "0:\tCS\t%0,1,0(2)\n"
290 : "=r" (tmp), "+m" (*val)
297 InterlockedDecrement(volatile gint32 *val)
301 __asm__ __volatile__ ("\tLA\t2,%1\n"
305 "0:\tCS\t%0,1,0(2)\n"
307 : "=r" (tmp), "+m" (*val)
315 InterlockedExchange(volatile gint32 *val, gint32 new_val)
319 __asm__ __volatile__ ("\tLA\t1,%1\n"
323 : "+m" (*val), "=r" (ret)
330 #define InterlockedExchangePointer InterlockedExchange
333 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
337 __asm__ __volatile__ ("\tL\t%0,%1\n"
341 "0:\tCS\t%0,1,0(2)\n"
343 : "=r" (ret), "+m" (*val)
350 #elif defined(__ppc__) || defined (__powerpc__)
351 #define WAPI_ATOMIC_ASM
353 static inline gint32 InterlockedIncrement(volatile gint32 *val)
357 __asm__ __volatile__ ("\n1:\n\t"
358 "lwarx %0, 0, %2\n\t"
360 "stwcx. %1, 0, %2\n\t"
362 : "=&b" (tmp): "r" (tmp), "r" (val): "cc", "memory");
366 static inline gint32 InterlockedDecrement(volatile gint32 *val)
370 __asm__ __volatile__ ("\n1:\n\t"
371 "lwarx %0, 0, %2\n\t"
372 "addi %1, %0, -1\n\t"
373 "stwcx. %1, 0, %2\n\t"
375 : "=&b" (tmp) : "r" (tmp), "r" (val): "cc", "memory");
379 #define InterlockedCompareExchangePointer InterlockedCompareExchange
381 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
382 gint32 exch, gint32 comp) {
385 __asm__ __volatile__ ("\n1:\n\t"
386 "lwarx %0, 0, %1\n\t"
389 "stwcx. %4, 0, %1\n\t"
393 : "r" (dest), "0" (tmp) ,"r" (comp), "r" (exch): "cc", "memory");
397 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
401 __asm__ __volatile__ ("\n1:\n\t"
402 "lwarx %0, 0, %1\n\t"
403 "stwcx. %2, 0, %1\n\t"
405 : "=r" (tmp) : "r" (dest), "r" (exch): "cc", "memory");
408 #define InterlockedExchangePointer InterlockedExchange
410 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
414 __asm__ __volatile__ ("\n1:\n\t"
415 "lwarx %0, 0, %2\n\t"
417 "stwcx. %1, 0, %2\n\t"
419 : "=r" (tmp), "=r" (add)
420 : "r" (dest), "0" (tmp), "1" (add) : "cc", "memory");
424 #elif defined(__arm__)
425 #define WAPI_ATOMIC_ASM
427 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
431 __asm__ __volatile__ ( "0:\n\t"
435 "swp %0, %3, [%2]\n\t"
437 "swpne %3, %0, [%2]\n\t"
440 : "=&r" (a), "=&r" (b)
441 : "r" (dest), "r" (exch), "r" (comp)
447 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
451 __asm__ __volatile__ ( "0:\n\t"
455 "swpeq %0, %3, [%2]\n\t"
457 "swpne %3, %0, [%2]\n\t"
460 : "=&r" (a), "=&r" (b)
461 : "r" (dest), "r" (exch), "r" (comp)
467 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
471 __asm__ __volatile__ ( "0:\n\t"
474 "swp %2, %1, [%3]\n\t"
476 "swpne %1, %2, [%3]\n\t"
478 : "=&r" (a), "=&r" (b), "=&r" (c)
479 : "r" (dest), "r" (1)
485 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
489 __asm__ __volatile__ ( "0:\n\t"
492 "swp %2, %1, [%3]\n\t"
494 "swpne %1, %2, [%3]\n\t"
496 : "=&r" (a), "=&r" (b), "=&r" (c)
497 : "r" (dest), "r" (-1)
503 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
507 __asm__ __volatile__ ( "swp %0, %2, [%1]"
509 : "r" (dest), "r" (exch));
514 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
518 __asm__ __volatile__ ( "swp %0, %2, [%1]"
520 : "r" (dest), "r" (exch));
525 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
529 __asm__ __volatile__ ( "0:\n\t"
532 "swp %2, %1, [%3]\n\t"
534 "swpne %1, %2, [%3]\n\t"
536 : "=&r" (a), "=&r" (b), "=&r" (c)
537 : "r" (dest), "r" (add)
545 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
546 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
547 extern gint32 InterlockedIncrement(volatile gint32 *dest);
548 extern gint32 InterlockedDecrement(volatile gint32 *dest);
549 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
550 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
551 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
553 #if defined(__hpux) && !defined(__GNUC__)
554 #define WAPI_ATOMIC_ASM
559 #endif /* _WAPI_ATOMIC_H_ */