[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