Fw: [patch] Make std::tr1::shared_ptr thread-safe.

Peter Dimov pdimov@mmltd.net
Fri Apr 1 15:27:00 GMT 2005


Paolo Carlini wrote:
> Alexander Terekhov wrote:
>
>> It is about msync semantics of exchange_and_add(). If you rely on
>> msync semantics which it doesn't provide, your code is broken. If it
>> is guaranteed to provide "fully-fenced" semantics (mimicking Intel's
>> __sync_fetch_and_add()), then (apart from unneeded overhead) you're
>> fine.
>>
>>
> Ok. Therefore, can well be the case that the port maintainers that
> provided (inline assembly ) implementations of exchange_and_add for
> the various archs chose to provide "fully-fenced" semantics, right?

This is possible, but unlikely. Unless there is documentation stating that 
__exchange_and_add needs to be fully fenced (which is a stronger requirement 
than necessary), the port maintainers are free to not implement a 
fully-fenced __exchange_and_add.

> Maybe you can volunteer to check a few of those implementations? Maybe
> ia64? For your convenience, reads, simply (exploiting built-ins in
> such case):
>
> namespace __gnu_cxx
> {
>  _Atomic_word
>  __attribute__ ((__unused__))
>  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
>  { return __sync_fetch_and_add(__mem, __val); }
>
>  void
>  __attribute__ ((__unused__))
>  __atomic_add(volatile _Atomic_word* __mem, int __val)
>  { __sync_fetch_and_add(__mem, __val); }
> }

The __sync_* IA64 intrinsics are fully-fenced, as far as I know.

> You can find all of them under config/cpu/*/atomicity.h.

Some of the interesting ones are:

*** Alpha ***:

http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc%2b%2b-v3/config/cpu/alpha/atomicity.h?rev=1.6&content-type=text/x-cvsweb-markup

namespace __gnu_cxx
{
  _Atomic_word
  __attribute__ ((__unused__))
  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
  {
    register int __result, __tmp;

    __asm__ __volatile__ (
      "\n$Lxadd_%=:\n\t"
      "ldl_l  %0,%3\n\t"
      "addl   %0,%4,%1\n\t"
      "stl_c  %1,%2\n\t"
      "beq    %1,$Lxadd_%=\n\t"
      "mb"
      : "=&r"(__result), "=&r"(__tmp), "=m"(*__mem)
      : "m" (*__mem), "r"(__val));

    return __result;
  }

  void
  __attribute__ ((__unused__))
  __atomic_add(volatile _Atomic_word* __mem, int __val)
  {
    register _Atomic_word __result;

    __asm__ __volatile__ (
      "\n$Ladd_%=:\n\t"
      "ldl_l  %0,%2\n\t"
      "addl   %0,%3,%0\n\t"
      "stl_c  %0,%1\n\t"
      "beq    %0,$Ladd_%=\n\t"
      "mb"
      : "=&r"(__result), "=m"(*__mem)
      : "m" (*__mem), "r"(__val));
  }
} // namespace __gnu_cxx

*** PowerPC ***:

http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc%2b%2b-v3/config/cpu/powerpc/atomicity.h?rev=1.9&content-type=text/x-cvsweb-markup

#ifdef __PPC405__
#define _STWCX "sync \n\tstwcx. "
#else
#define _STWCX "stwcx. "
#endif

namespace __gnu_cxx
{
  _Atomic_word
  __attribute__ ((__unused__))
  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __tmp, __res;
    __asm__ __volatile__ (
                          "/* Inline exchange & add */\n"
                          "0:\t"
                          "lwarx    %0,0,%3 \n\t"
                          "add%I4   %1,%0,%4 \n\t"
                          _STWCX "  %1,0,%3 \n\t"
                          "bne-     0b \n\t"
                          "/* End exchange & add */"
                          : "=&b"(__res), "=&r"(__tmp), "=m" (*__mem)
                          : "r" (__mem), "Ir"(__val), "m" (*__mem)
                          : "cr0");
    return __res;
  }

  void
  __attribute__ ((__unused__))
  __atomic_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __tmp;
    __asm__ __volatile__ (
                          "/* Inline atomic add */\n"
                          "0:\t"
                          "lwarx    %0,0,%2 \n\t"
                          "add%I3   %0,%0,%3 \n\t"
                          _STWCX "  %0,0,%2 \n\t"
                          "bne-     0b \n\t"
                          "/* End atomic add */"
                          : "=&b"(__tmp), "=m" (*__mem)
                          : "r" (__mem), "Ir"(__val), "m" (*__mem)
                          : "cr0");
  }
} // namespace __gnu_cxx

*** Sparc ***:

http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc%2b%2b-v3/config/cpu/sparc/atomicity.h?rev=1.7&content-type=text/x-cvsweb-markup

namespace __gnu_cxx
{
#ifdef __arch64__
  _Atomic_word
  __attribute__ ((__unused__))
  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __tmp1, __tmp2;
    _Atomic_word __val_extended = __val;

    __asm__ __volatile__("1:    ldx        [%3], %0\n\t"
                         "        add        %0, %4, %1\n\t"
                         "        casx        [%3], %0, %1\n\t"
                         "        sub        %0, %1, %0\n\t"
                         "        brnz,pn        %0, 1b\n\t"
                         "         nop"
                         : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__mem)
                         : "r" (__mem), "r" (__val_extended), "m" (*__mem));
    return __tmp2;
  }

  void
  __attribute__ ((__unused__))
  __atomic_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __tmp1, __tmp2;
    _Atomic_word __val_extended = __val;

    __asm__ __volatile__("1:    ldx        [%3], %0\n\t"
                         "        add        %0, %4, %1\n\t"
                         "        casx        [%3], %0, %1\n\t"
                         "        sub        %0, %1, %0\n\t"
                         "        brnz,pn        %0, 1b\n\t"
                         "         nop"
                         : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__mem)
                         : "r" (__mem), "r" (__val_extended), "m" (*__mem));
  }

#else /* __arch32__ */

  template<int __inst>
    struct _Atomicity_lock
    {
      static unsigned char _S_atomicity_lock;
    };

  template<int __inst>
  unsigned char _Atomicity_lock<__inst>::_S_atomicity_lock = 0;

  template unsigned char _Atomicity_lock<0>::_S_atomicity_lock;

  _Atomic_word
  __attribute__ ((__unused__))
  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __result, __tmp;

    __asm__ __volatile__("1:    ldstub        [%1], %0\n\t"
                         "        cmp        %0, 0\n\t"
                         "        bne        1b\n\t"
                         "         nop"
                         : "=&r" (__tmp)
                         : "r" (&_Atomicity_lock<0>::_S_atomicity_lock)
                         : "memory");
    __result = *__mem;
    *__mem += __val;
    __asm__ __volatile__("stb   %%g0, [%0]"
                         : /* no outputs */
                         : "r" (&_Atomicity_lock<0>::_S_atomicity_lock)
                         : "memory");
    return __result;
  }

  void
  __attribute__ ((__unused__))
  __atomic_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __tmp;

    __asm__ __volatile__("1:    ldstub        [%1], %0\n\t"
                         "        cmp        %0, 0\n\t"
                         "        bne        1b\n\t"
                         "         nop"
                         : "=&r" (__tmp)
                         : "r" (&_Atomicity_lock<0>::_S_atomicity_lock)
                         : "memory");
    *__mem += __val;
    __asm__ __volatile__("stb   %%g0, [%0]"
                         : /* no outputs */
                         : "r" (&_Atomicity_lock<0>::_S_atomicity_lock)
                         : "memory");
  }
#endif /* __arch32__ */
} // namespace __gnu_cxx

*** MIPS ***:

http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc%2b%2b-v3/config/cpu/mips/atomicity.h?rev=1.10&content-type=text/x-cvsweb-markup

namespace __gnu_cxx
{
  _Atomic_word
  __attribute__ ((__unused__))
  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __result, __tmp;

    __asm__ __volatile__
      ("/* Inline exchange & add */\n\t"
       "1:\n\t"
       ".set    push\n\t"
#if _MIPS_SIM == _ABIO32
       ".set    mips2\n\t"
#endif
       "ll      %0,0(%2)\n\t"
       "addu    %1,%3,%0\n\t"
       "sc      %1,0(%2)\n\t"
       ".set    pop\n\t"
       "beqz    %1,1b\n\t"
       "/* End exchange & add */"
       : "=&r"(__result), "=&r"(__tmp)
       : "r"(__mem), "r"(__val)
       :  "memory" );

    return __result;
  }

  void
  __attribute__ ((__unused__))
  __atomic_add(volatile _Atomic_word* __mem, int __val)
  {
    _Atomic_word __result;

    __asm__ __volatile__
      ("/* Inline atomic add */\n\t"
       "1:\n\t"
       ".set    push\n\t"
#if _MIPS_SIM == _ABIO32
       ".set    mips2\n\t"
#endif
       "ll      %0,0(%1)\n\t"
       "addu    %0,%2,%0\n\t"
       "sc      %0,0(%1)\n\t"
       ".set    pop\n\t"
       "beqz    %0,1b\n\t"
       "/* End atomic add */"
       : "=&r"(__result)
       : "r"(__mem), "r"(__val)
       : "memory" );
  }
} // namespace __gnu_cxx



More information about the Libstdc++ mailing list