Boost logo

Boost-Commit :

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{


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk