
Hello, attached patch introduces support for the atomic ops needed by interprocess on Tru64/CXX/Alpha. It currently misses support for atomic add and sub, but those are not used right now. There are a few issues I would like to raise regarding the atomic operations: 1) Currently it is not specified whether an atomic operation implies a memory barrier or not. This should be explicitly stated. 2) atomic_sub32 does not return the old value, but atomic_add32 does. This seems inconsistent to me. 3) Has the use of the low level atomic ops API as proposed in WG21/N2047 (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2047.html) been considered. If yes, why has it been rejected? If no, would it makes sense to use this API? 4) Is there a need for an atomic ops boost library? I seem to remember that other libraries need atomic ops as well. Regards, Markus Index: atomic.hpp =================================================================== --- atomic.hpp (revision 40078) +++ atomic.hpp (working copy) @@ -436,6 +436,82 @@ } //namespace interprocess{ } //namespace boost{ +#elif defined(__osf__) + +#include <machine/builtins.h> +#include <c_asm.h> + +namespace boost{ +namespace interprocess{ +namespace detail{ + +//! Atomically increment an apr_uint32_t by 1 +//! "mem": pointer to the object +//! Returns the old value pointed to by mem +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 bool atomic_dec32(volatile boost::uint32_t *mem) +{ return __ATOMIC_DECREMENT_LONG(mem); } + +// Rational for the implementation of the atomic read and write functions. +// +// 1. The Alpha Architecture Handbook requires that access to a byte, +// an aligned word, an aligned longword, or an aligned quadword is +// atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.) +// +// 2. The CXX User's Guide states that volatile quantities are accessed +// with single assembler instructions, and that a compilation error +// occurs when declaring a quantity as volatile which is not properly +// aligned. + +//! Atomically read an boost::uint32_t from memory +inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) +{ return *mem; } + +//! Atomically set an boost::uint32_t in memory +//! "mem": pointer to the object +//! "param": val value that the object will assume +inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) +{ *mem = val; } + +//! Compare an boost::uint32_t's value with "cmp". +//! If they are the same swap the value with "with" +//! "mem": pointer to the value +//! "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) +{ + // Notes: + // + // 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. + // + // 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); +} + +} //namespace detail{ +} //namespace interprocess{ +} //namespace boost{ + #else #error No atomic operations implemented for this platform, sorry!