[Mono-dev] _wapi_sparc_lock
David S. Miller
davem at davemloft.net
Tue Mar 28 05:36:52 EST 2006
From: "Zoltan Varga" <vargaz at gmail.com>
Date: Sat, 25 Mar 2006 12:30:23 +0100
> This looks ok to me. I will try to test it on sparc/solaris, then
> check it in, if it works.
There were two bugs in my change, a fixed version is included
below.
The two bugs were:
1) Missing "cc" condition code clobber in the assembler
sequences that use compare+branch.
2) InterlockedCompareExchange and InterlockedCompareExchangePointer
were losing the return value because we weren't specifying the
input/output locations for "exch" correctly. We were using
exch as the input, a new local variable "old" for the output,
gcc could put them into different locations and when it did
our return value was corrupt.
I'm pretty confident in this change now :-)
Thanks.
2006-03-24 David S. Miller <davem at sunset.davemloft.net>
* atomic.c (__wapi_sparc_lock): Delete
* atomic.h sparc: Reimplement Interlocked* primitives using CAS/CASx
when __GNUC__, else we will fall back to the generic pthread version.
--- mono/io-layer/atomic.c.~1~ 2006-03-27 22:56:34.000000000 -0800
+++ mono/io-layer/atomic.c 2006-03-27 22:56:44.000000000 -0800
@@ -14,11 +14,7 @@
#include "mono/io-layer/wapi.h"
-#ifdef WAPI_ATOMIC_ASM
-#if defined(sparc) || defined (__sparc__)
-volatile unsigned char _wapi_sparc_lock;
-#endif
-#else
+#ifndef WAPI_ATOMIC_ASM
static pthread_mutex_t spin = PTHREAD_MUTEX_INITIALIZER;
static mono_once_t spin_once=MONO_ONCE_INIT;
--- mono/io-layer/atomic.h.~1~ 2006-03-27 22:56:39.000000000 -0800
+++ mono/io-layer/atomic.h 2006-03-27 22:56:54.000000000 -0800
@@ -127,152 +127,165 @@ static inline gint32 InterlockedExchange
return(ret);
}
-#elif defined(sparc) || defined (__sparc__)
+#elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__)
#define WAPI_ATOMIC_ASM
-#ifdef __GNUC__
-#define BEGIN_SPIN(tmp,lock) \
-__asm__ __volatile__("1: ldstub [%1],%0\n\t" \
- " cmp %0, 0\n\t" \
- " bne 1b\n\t" \
- " nop" \
- : "=&r" (tmp) \
- : "r" (&lock) \
- : "memory");
-
-#define END_SPIN(lock) \
-__asm__ __volatile__("stb %%g0, [%0]" \
- : /* no outputs */ \
- : "r" (&lock)\
- : "memory");
-#else
-static inline void begin_spin(volatile unsigned char *lock)
-{
- asm("1: ldstub [%i0], %l0");
- asm("cmp %l0,0");
- asm("bne 1b");
- asm("nop");
-}
-#define BEGIN_SPIN(tmp,lock) begin_spin(&lock);
-#define END_SPIN(lock) ((lock) = 0);
-#endif
-
-extern volatile unsigned char _wapi_sparc_lock;
-
G_GNUC_UNUSED
-static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
+static inline gint32 InterlockedCompareExchange(volatile gint32 *_dest, gint32 _exch, gint32 _comp)
{
- int tmp;
- gint32 old;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- old = *dest;
- if (old==comp) {
- *dest=exch;
- }
+ register volatile gint32 *dest asm("g1") = _dest;
+ register gint32 comp asm("o4") = _comp;
+ register gint32 exch asm("o5") = _exch;
+
+ __asm__ __volatile__(
+ /* cas [%%g1], %%o4, %%o5 */
+ ".word 0xdbe0500c"
+ : "=r" (exch)
+ : "0" (exch), "r" (dest), "r" (comp)
+ : "memory");
- END_SPIN(_wapi_sparc_lock)
-
- return(old);
+ return exch;
}
G_GNUC_UNUSED
-static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
+static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *_dest, gpointer _exch, gpointer _comp)
{
- int tmp;
- gpointer old;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- old = *dest;
- if (old==comp) {
- *dest=exch;
- }
-
- END_SPIN(_wapi_sparc_lock)
+ register volatile gpointer *dest asm("g1") = _dest;
+ register gpointer comp asm("o4") = _comp;
+ register gpointer exch asm("o5") = _exch;
+
+ __asm__ __volatile__(
+#ifdef SPARCV9
+ /* casx [%%g1], %%o4, %%o5 */
+ ".word 0xdbf0500c"
+#else
+ /* cas [%%g1], %%o4, %%o5 */
+ ".word 0xdbe0500c"
+#endif
+ : "=r" (exch)
+ : "0" (exch), "r" (dest), "r" (comp)
+ : "memory");
- return(old);
+ return exch;
}
G_GNUC_UNUSED
-static inline gint32 InterlockedIncrement(volatile gint32 *dest)
+static inline gint32 InterlockedIncrement(volatile gint32 *_dest)
{
- int tmp;
- gint32 ret;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- (*dest)++;
- ret = *dest;
-
- END_SPIN(_wapi_sparc_lock)
+ register volatile gint32 *dest asm("g1") = _dest;
+ register gint32 tmp asm("o4");
+ register gint32 ret asm("o5");
+
+ __asm__ __volatile__(
+ "1: ld [%%g1], %%o4\n\t"
+ " add %%o4, 1, %%o5\n\t"
+ /* cas [%%g1], %%o4, %%o5 */
+ " .word 0xdbe0500c\n\t"
+ " cmp %%o4, %%o5\n\t"
+ " bne 1b\n\t"
+ " add %%o5, 1, %%o5"
+ : "=&r" (tmp), "=&r" (ret)
+ : "r" (dest)
+ : "memory", "cc");
- return(ret);
+ return ret;
}
G_GNUC_UNUSED
-static inline gint32 InterlockedDecrement(volatile gint32 *dest)
+static inline gint32 InterlockedDecrement(volatile gint32 *_dest)
{
- int tmp;
- gint32 ret;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- (*dest)--;
- ret = *dest;
+ register volatile gint32 *dest asm("g1") = _dest;
+ register gint32 tmp asm("o4");
+ register gint32 ret asm("o5");
+
+ __asm__ __volatile__(
+ "1: ld [%%g1], %%o4\n\t"
+ " sub %%o4, 1, %%o5\n\t"
+ /* cas [%%g1], %%o4, %%o5 */
+ " .word 0xdbe0500c\n\t"
+ " cmp %%o4, %%o5\n\t"
+ " bne 1b\n\t"
+ " sub %%o5, 1, %%o5"
+ : "=&r" (tmp), "=&r" (ret)
+ : "r" (dest)
+ : "memory", "cc");
- END_SPIN(_wapi_sparc_lock)
-
- return(ret);
+ return ret;
}
G_GNUC_UNUSED
-static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
+static inline gint32 InterlockedExchange(volatile gint32 *_dest, gint32 exch)
{
- int tmp;
- gint32 ret;
+ register volatile gint32 *dest asm("g1") = _dest;
+ register gint32 tmp asm("o4");
+ register gint32 ret asm("o5");
+
+ __asm__ __volatile__(
+ "1: ld [%%g1], %%o4\n\t"
+ " mov %3, %%o5\n\t"
+ /* cas [%%g1], %%o4, %%o5 */
+ " .word 0xdbe0500c\n\t"
+ " cmp %%o4, %%o5\n\t"
+ " bne 1b\n\t"
+ " nop"
+ : "=&r" (tmp), "=&r" (ret)
+ : "r" (dest), "r" (exch)
+ : "memory", "cc");
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- ret = *dest;
- *dest = exch;
-
- END_SPIN(_wapi_sparc_lock)
-
- return(ret);
+ return ret;
}
G_GNUC_UNUSED
-static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
+static inline gpointer InterlockedExchangePointer(volatile gpointer *_dest, gpointer exch)
{
- int tmp;
- gpointer ret;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- ret = *dest;
- *dest = exch;
-
- END_SPIN(_wapi_sparc_lock)
+ register volatile gpointer *dest asm("g1") = _dest;
+ register gpointer tmp asm("o4");
+ register gpointer ret asm("o5");
+
+ __asm__ __volatile__(
+#ifdef SPARCV9
+ "1: ldx [%%g1], %%o4\n\t"
+#else
+ "1: ld [%%g1], %%o4\n\t"
+#endif
+ " mov %3, %%o5\n\t"
+#ifdef SPARCV9
+ /* casx [%%g1], %%o4, %%o5 */
+ " .word 0xdbf0500c\n\t"
+#else
+ /* cas [%%g1], %%o4, %%o5 */
+ " .word 0xdbe0500c\n\t"
+#endif
+ " cmp %%o4, %%o5\n\t"
+ " bne 1b\n\t"
+ " nop"
+ : "=&r" (tmp), "=&r" (ret)
+ : "r" (dest), "r" (exch)
+ : "memory", "cc");
- return(ret);
+ return ret;
}
G_GNUC_UNUSED
-static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
+static inline gint32 InterlockedExchangeAdd(volatile gint32 *_dest, gint32 add)
{
- int tmp;
- gint32 ret;
-
- BEGIN_SPIN(tmp,_wapi_sparc_lock)
-
- ret = *dest;
- *dest += add;
-
- END_SPIN(_wapi_sparc_lock)
+ register volatile gint32 *dest asm("g1") = _dest;
+ register gint32 tmp asm("o4");
+ register gint32 ret asm("o5");
+
+ __asm__ __volatile__(
+ "1: ld [%%g1], %%o4\n\t"
+ " add %%o4, %3, %%o5\n\t"
+ /* cas [%%g1], %%o4, %%o5 */
+ " .word 0xdbe0500c\n\t"
+ " cmp %%o4, %%o5\n\t"
+ " bne 1b\n\t"
+ " add %%o5, %3, %%o5"
+ : "=&r" (tmp), "=&r" (ret)
+ : "r" (dest), "r" (add)
+ : "memory", "cc");
- return(ret);
+ return ret;
}
#elif __s390__
More information about the Mono-devel-list
mailing list