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"
17 #if defined(__i386__) || defined(__x86_64__)
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; "
51 : "=m" (*dest), "=a" (old)
52 : "r" (exch), "m" (*dest), "a" (comp));
57 static inline gint32 InterlockedIncrement(volatile gint32 *val)
61 __asm__ __volatile__ ("lock; xaddl %0, %1"
62 : "=r" (tmp), "=m" (*val)
63 : "0" (1), "m" (*val));
68 static inline gint32 InterlockedDecrement(volatile gint32 *val)
72 __asm__ __volatile__ ("lock; xaddl %0, %1"
73 : "=r" (tmp), "=m" (*val)
74 : "0" (-1), "m" (*val));
81 * http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
82 * for the reasons for using cmpxchg and a loop here.
84 * That url is no longer valid, but it's still in the google cache at the
85 * moment: http://www.google.com/search?q=cache:http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
87 * For the time being, http://msdn.microsoft.com/msdnmag/issues/0700/Win32/
88 * might work. Bet it will change soon enough though.
90 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new_val)
94 __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
95 : "=m" (*val), "=a" (ret)
96 : "r" (new_val), "m" (*val), "a" (*val));
101 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
106 __asm__ __volatile__ ("1:; lock; "
113 : "=m" (*val), "=a" (ret)
114 : "r" (new_val), "m" (*val), "a" (*val));
119 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
123 __asm__ __volatile__ ("lock; xaddl %0, %1"
124 : "=r" (ret), "=m" (*val)
125 : "0" (add), "m" (*val));
130 #elif defined(sparc) || defined (__sparc__)
131 #define WAPI_ATOMIC_ASM
134 #define BEGIN_SPIN(tmp,lock) \
135 __asm__ __volatile__("1: ldstub [%1],%0\n\t" \
143 #define END_SPIN(lock) \
144 __asm__ __volatile__("stb %%g0, [%0]" \
149 static inline void begin_spin(volatile unsigned char *lock)
151 asm("1: ldstub [%i0], %l0");
156 #define BEGIN_SPIN(tmp,lock) begin_spin(&lock);
157 #define END_SPIN(lock) ((lock) = 0);
160 extern volatile unsigned char _wapi_sparc_lock;
163 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
168 BEGIN_SPIN(tmp,_wapi_sparc_lock)
175 END_SPIN(_wapi_sparc_lock)
181 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
186 BEGIN_SPIN(tmp,_wapi_sparc_lock)
193 END_SPIN(_wapi_sparc_lock)
199 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
204 BEGIN_SPIN(tmp,_wapi_sparc_lock)
209 END_SPIN(_wapi_sparc_lock)
215 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
220 BEGIN_SPIN(tmp,_wapi_sparc_lock)
225 END_SPIN(_wapi_sparc_lock)
231 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
236 BEGIN_SPIN(tmp,_wapi_sparc_lock)
241 END_SPIN(_wapi_sparc_lock)
247 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
252 BEGIN_SPIN(tmp,_wapi_sparc_lock)
257 END_SPIN(_wapi_sparc_lock)
263 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
268 BEGIN_SPIN(tmp,_wapi_sparc_lock)
273 END_SPIN(_wapi_sparc_lock)
280 #define WAPI_ATOMIC_ASM
283 InterlockedCompareExchange(volatile gint32 *dest,
284 gint32 exch, gint32 comp)
288 __asm__ __volatile__ ("\tLA\t1,%0\n"
295 : "+m" (*dest), "+r" (old)
296 : "r" (exch), "r" (comp)
302 # define InterlockedCompareExchangePointer InterlockedCompareExchange
304 static inline gpointer
305 InterlockedCompareExchangePointer(volatile gpointer *dest,
311 __asm__ __volatile__ ("\tLA\t1,%0\n"
315 "\tCSG\t%1,%2,0(1)\n"
318 : "+m" (*dest), "+r" (old)
319 : "r" (exch), "r" (comp)
328 InterlockedIncrement(volatile gint32 *val)
332 __asm__ __volatile__ ("\tLA\t2,%1\n"
339 : "=r" (tmp), "+m" (*val)
346 InterlockedDecrement(volatile gint32 *val)
350 __asm__ __volatile__ ("\tLA\t2,%1\n"
357 : "=r" (tmp), "+m" (*val)
365 InterlockedExchange(volatile gint32 *val, gint32 new_val)
369 __asm__ __volatile__ ("\tLA\t1,%0\n"
373 : "+m" (*val), "+r" (ret)
381 # define InterlockedExchangePointer InterlockedExchange
383 static inline gpointer
384 InterlockedExchangePointer(volatile gpointer *val, gpointer new_val)
388 __asm__ __volatile__ ("\tLA\t1,%1\n"
390 "\tCSG\t%1,%2,0(1)\n"
392 : "+m" (*val), "+r" (ret)
401 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
405 __asm__ __volatile__ ("\tLA\t2,%1\n"
411 : "=r" (ret), "+m" (*val)
418 #elif defined(__ppc__) || defined (__powerpc__)
419 #define WAPI_ATOMIC_ASM
421 static inline gint32 InterlockedIncrement(volatile gint32 *val)
423 gint32 result = 0, tmp;
425 __asm__ __volatile__ ("\n1:\n\t"
426 "lwarx %0, 0, %2\n\t"
428 "stwcx. %1, 0, %2\n\t"
430 : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
434 static inline gint32 InterlockedDecrement(volatile gint32 *val)
436 gint32 result = 0, tmp;
438 __asm__ __volatile__ ("\n1:\n\t"
439 "lwarx %0, 0, %2\n\t"
440 "addi %1, %0, -1\n\t"
441 "stwcx. %1, 0, %2\n\t"
443 : "=&b" (result), "=&b" (tmp): "r" (val): "cc", "memory");
447 #define InterlockedCompareExchangePointer(dest,exch,comp) InterlockedCompareExchange((volatile gint32 *)(dest), (gint32)(exch), (gint32)(comp))
449 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
450 gint32 exch, gint32 comp) {
453 __asm__ __volatile__ ("\n1:\n\t"
454 "lwarx %0, 0, %1\n\t"
457 "stwcx. %3, 0, %1\n\t"
461 : "b" (dest), "r" (comp), "r" (exch): "cc", "memory");
465 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
469 __asm__ __volatile__ ("\n1:\n\t"
470 "lwarx %0, 0, %2\n\t"
471 "stwcx. %3, 0, %2\n\t"
473 : "=r" (tmp) : "0" (tmp), "b" (dest), "r" (exch): "cc", "memory");
476 #define InterlockedExchangePointer(dest,exch) InterlockedExchange((volatile gint32 *)(dest), (gint32)(exch))
478 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
481 __asm__ __volatile__ ("\n1:\n\t"
482 "lwarx %0, 0, %2\n\t"
484 "stwcx. %1, 0, %2\n\t"
486 : "=&r" (result), "=&r" (tmp)
487 : "r" (dest), "r" (add) : "cc", "memory");
491 #elif defined(__arm__)
492 #define WAPI_ATOMIC_ASM
494 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
498 __asm__ __volatile__ ( "0:\n\t"
502 "swp %0, %3, [%2]\n\t"
504 "swpne %3, %0, [%2]\n\t"
507 : "=&r" (a), "=&r" (b)
508 : "r" (dest), "r" (exch), "r" (comp)
514 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
518 __asm__ __volatile__ ( "0:\n\t"
522 "swpeq %0, %3, [%2]\n\t"
524 "swpne %3, %0, [%2]\n\t"
527 : "=&r" (a), "=&r" (b)
528 : "r" (dest), "r" (exch), "r" (comp)
534 static inline gint32 InterlockedIncrement(volatile gint32 *dest)
538 __asm__ __volatile__ ( "0:\n\t"
541 "swp %2, %1, [%3]\n\t"
543 "swpne %1, %2, [%3]\n\t"
545 : "=&r" (a), "=&r" (b), "=&r" (c)
546 : "r" (dest), "r" (1)
552 static inline gint32 InterlockedDecrement(volatile gint32 *dest)
556 __asm__ __volatile__ ( "0:\n\t"
559 "swp %2, %1, [%3]\n\t"
561 "swpne %1, %2, [%3]\n\t"
563 : "=&r" (a), "=&r" (b), "=&r" (c)
564 : "r" (dest), "r" (-1)
570 static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
574 __asm__ __volatile__ ( "swp %0, %2, [%1]"
576 : "r" (dest), "r" (exch));
581 static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
585 __asm__ __volatile__ ( "swp %0, %2, [%1]"
587 : "r" (dest), "r" (exch));
592 static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
596 __asm__ __volatile__ ( "0:\n\t"
599 "swp %2, %1, [%3]\n\t"
601 "swpne %1, %2, [%3]\n\t"
603 : "=&r" (a), "=&r" (b), "=&r" (c)
604 : "r" (dest), "r" (add)
612 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
613 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
614 extern gint32 InterlockedIncrement(volatile gint32 *dest);
615 extern gint32 InterlockedDecrement(volatile gint32 *dest);
616 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
617 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
618 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
620 #if defined(__hpux) && !defined(__GNUC__)
621 #define WAPI_ATOMIC_ASM
626 #endif /* _WAPI_ATOMIC_H_ */