[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