[Mono-dev] _wapi_sparc_lock
Zoltan Varga
vargaz at gmail.com
Tue Mar 28 05:46:09 EST 2006
Hi,
One thing I'm worried about with this change is that is falls back to the
pthread_ set of functions when using a compiler other than GCC. This is most
likely not a problem on sparc/linux, but can be a problem on sparc/solaris.
The pthread_ functions are slower, and even less async safe than the existing
spin functionality. So I think it would be better to keep the spin stuff.
Zoltan
On 3/28/06, David S. Miller <davem at davemloft.net> wrote:
> 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