$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: markus.schoepflin_at_[hidden]
Date: 2007-11-09 09:25:45
Author: schoepflin
Date: 2007-11-09 09:25:44 EST (Fri, 09 Nov 2007)
New Revision: 40967
URL: http://svn.boost.org/trac/boost/changeset/40967
Log:
Added memory barriers to Tru64 atomic ops.
Text files modified: 
   trunk/boost/interprocess/detail/atomic.hpp |    86 +++++++++++++++++++++++++-------------- 
   1 files changed, 54 insertions(+), 32 deletions(-)
Modified: trunk/boost/interprocess/detail/atomic.hpp
==============================================================================
--- trunk/boost/interprocess/detail/atomic.hpp	(original)
+++ trunk/boost/interprocess/detail/atomic.hpp	2007-11-09 09:25:44 EST (Fri, 09 Nov 2007)
@@ -1,8 +1,11 @@
 //////////////////////////////////////////////////////////////////////////////
 //
-// (C) Copyright Ion Gaztanaga 2006-2007. Distributed under the Boost
-// Software License, Version 1.0. (See accompanying file
-// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+// (C) Copyright Ion Gaztanaga 2006-2007
+// (C) Copyright Markus Schoepflin 2007
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
 //
 // See http://www.boost.org/libs/interprocess for documentation.
 //
@@ -372,17 +375,19 @@
 namespace interprocess{
 namespace detail{
 
-//! Atomically increment an apr_uint32_t by 1
+//! Atomically decrement a uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+//! Acquire, memory barrier after decrement.
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{  boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; }
+
+//! Atomically increment a uint32_t by 1
 //! "mem": pointer to the object
 //! Returns the old value pointed to by mem
+//! Release, memory barrier before increment.
 inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
-{  return __ATOMIC_INCREMENT_LONG(mem); }
-
-//! Atomically decrement an boost::uint32_t by 1
-//! "mem": pointer to the atomic value
-//! Returns false if the value becomes zero on decrement, otherwise true
-inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
-{  return __ATOMIC_DECREMENT_LONG(mem); }
+{  __MB(); return __ATOMIC_INCREMENT_LONG(mem); }
 
 // Rational for the implementation of the atomic read and write functions.
 //
@@ -396,14 +401,16 @@
 // aligned.
 
 //! Atomically read an boost::uint32_t from memory
+//! Acquire, memory barrier after load.
 inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
-{  return *mem;   }
+{  boost::uint32_t old_val = *mem; __MB(); return old_val;  }
 
 //! Atomically set an boost::uint32_t in memory
 //! "mem": pointer to the object
 //! "param": val value that the object will assume
+//! Release, memory barrier before store.
 inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
-{  *mem = val; }
+{  __MB(); *mem = val; }
 
 //! Compare an boost::uint32_t's value with "cmp".
 //! If they are the same swap the value with "with"
@@ -411,28 +418,43 @@
 //! "with" what to swap it with
 //! "cmp": the value to compare it to
 //! Returns the old value of *mem
-inline boost::uint32_t atomic_cas32
-   (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
+//! Memory barrier between load and store.
+inline boost::uint32_t atomic_cas32(
+  volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
 {
-  // Notes:
+  // Note:
+  //
+  // Branch prediction prefers backward branches, and the Alpha Architecture
+  // Handbook explicitely states that the loop should not be implemented like
+  // it is below. (See chapter 4.2.5.) Therefore the code should probably look
+  // like this:
   //
-  // 1. Branch prediction prefers branches, as we assume that the lock
-  // is not stolen usually, we branch forward conditionally on success
-  // of the store, and not conditionally backwards on failure.
+  // return asm(
+  //   "10: ldl_l %v0,(%a0) ;"
+  //   "    cmpeq %v0,%a2,%t0 ;"
+  //   "    beq %t0,20f ;"
+  //   "    mb ;"
+  //   "    mov %a1,%t0 ;"
+  //   "    stl_c %t0,(%a0) ;"
+  //   "    beq %t0,30f ;"
+  //   "20: ret ;"
+  //   "30: br 10b;",
+  //   mem, with, cmp);
   //
-  // 2. The memory lock is invalidated when a branch is taken between
-  // load and store. Therefore we can only branch if we don't need a
-  // store.
-
-  return asm("10: ldl_l %v0,(%a0) ;"    // load prev value from mem and lock mem
-	     "    cmpeq %v0,%a2,%t0 ;"  // compare with given value
-	     "    beq %t0,20f ;"        // if not equal, we're done
-	     "    mov %a1,%t0 ;"        // load new value into scratch register
-	     "    stl_c %t0,(%a0) ;"    // store new value to locked mem (overwriting scratch)
-	     "    bne %t0,20f ;"        // store succeeded, we're done
-	     "    br 10b ;"             // lock has been stolen, retry
-	     "20: ",
-	     mem, with, cmp);
+  // But as the compiler always transforms this into the form where a backward
+  // branch is taken on failure, we can as well implement it in the straight
+  // forward form, as this is what it will end up in anyway.
+
+  return asm(
+    "10: ldl_l %v0,(%a0) ;"    // load prev value from mem and lock mem
+    "    cmpeq %v0,%a2,%t0 ;"  // compare with given value
+    "    beq %t0,20f ;"        // if not equal, we're done
+    "    mb ;"                 // memory barrier
+    "    mov %a1,%t0 ;"        // load new value into scratch register
+    "    stl_c %t0,(%a0) ;"    // store new value to locked mem (overwriting scratch)
+    "    beq %t0,10b ;"        // store failed because lock has been stolen, retry
+    "20: ",
+    mem, with, cmp);
 }
 
 }  //namespace detail{