Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // (C) Copyright Ion Gaztanaga 2006-2012 Chris@16: // (C) Copyright Markus Schoepflin 2007 Chris@16: // (C) Copyright Bryce Lelbach 2010 Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // See http://www.boost.org/libs/interprocess for documentation. Chris@16: // Chris@16: ////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP Chris@16: #define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP Chris@16: Chris@101: #ifndef BOOST_CONFIG_HPP Chris@101: # include Chris@101: #endif Chris@101: # Chris@101: #if defined(BOOST_HAS_PRAGMA_ONCE) Chris@101: # pragma once Chris@101: #endif Chris@101: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically increment an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem); Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem); Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val); Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with": what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp); Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@101: #if defined (BOOST_INTERPROCESS_WINDOWS) Chris@16: Chris@16: #include Chris@16: Chris@101: #if defined( _MSC_VER ) Chris@101: extern "C" void _ReadWriteBarrier(void); Chris@101: #pragma intrinsic(_ReadWriteBarrier) Chris@101: #define BOOST_INTERPROCESS_READ_WRITE_BARRIER _ReadWriteBarrier() Chris@101: #elif defined(__GNUC__) Chris@101: #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 Chris@101: #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize() Chris@101: #else Chris@101: #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __asm__ __volatile__("" : : : "memory") Chris@101: #endif Chris@101: #endif Chris@101: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return winapi::interlocked_decrement(reinterpret_cast(mem)) + 1; } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return winapi::interlocked_increment(reinterpret_cast(mem))-1; } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@101: { Chris@101: const boost::uint32_t val = *mem; Chris@101: BOOST_INTERPROCESS_READ_WRITE_BARRIER; Chris@101: return val; Chris@101: } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { winapi::interlocked_exchange(reinterpret_cast(mem), val); } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with": what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { return winapi::interlocked_compare_exchange(reinterpret_cast(mem), with, cmp); } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@101: #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(_CRAYC) Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { Chris@16: boost::uint32_t prev = cmp; Chris@16: // This version by Mans Rullgard of Pathscale Chris@16: __asm__ __volatile__ ( "lock\n\t" Chris@16: "cmpxchg %2,%0" Chris@16: : "+m"(*mem), "+a"(prev) Chris@16: : "r"(with) Chris@16: : "cc"); Chris@16: Chris@16: return prev; Chris@16: } Chris@16: Chris@16: //! Atomically add 'val' to an boost::uint32_t Chris@16: //! "mem": pointer to the object Chris@16: //! "val": amount to add Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_add32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { Chris@16: // int r = *pw; Chris@16: // *mem += val; Chris@16: // return r; Chris@16: int r; Chris@16: Chris@16: asm volatile Chris@16: ( Chris@16: "lock\n\t" Chris@16: "xadd %1, %0": Chris@16: "+m"( *mem ), "=r"( r ): // outputs (%0, %1) Chris@16: "1"( val ): // inputs (%2 == %1) Chris@16: "memory", "cc" // clobbers Chris@16: ); Chris@16: Chris@16: return r; Chris@16: } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, 1); } Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, (boost::uint32_t)-1); } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@101: { Chris@101: const boost::uint32_t val = *mem; Chris@101: __asm__ __volatile__ ( "" ::: "memory" ); Chris@101: return val; Chris@101: } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@101: { Chris@101: __asm__ __volatile__ Chris@101: ( Chris@101: "xchgl %0, %1" Chris@101: : "+r" (val), "+m" (*mem) Chris@101: :: "memory" Chris@101: ); Chris@101: } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@16: #elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__)) Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically add 'val' to an boost::uint32_t Chris@16: //! "mem": pointer to the object Chris@16: //! "val": amount to add Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { Chris@16: boost::uint32_t prev, temp; Chris@16: Chris@16: asm volatile ("1:\n\t" Chris@16: "lwarx %0,0,%2\n\t" Chris@16: "add %1,%0,%3\n\t" Chris@16: "stwcx. %1,0,%2\n\t" Chris@16: "bne- 1b" Chris@16: : "=&r" (prev), "=&r" (temp) Chris@16: : "b" (mem), "r" (val) Chris@16: : "cc", "memory"); Chris@16: return prev; Chris@16: } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { Chris@16: boost::uint32_t prev; Chris@16: Chris@16: asm volatile ("1:\n\t" Chris@16: "lwarx %0,0,%1\n\t" Chris@16: "cmpw %0,%3\n\t" Chris@16: "bne- 2f\n\t" Chris@16: "stwcx. %2,0,%1\n\t" Chris@16: "bne- 1b\n\t" Chris@16: "2:" Chris@16: : "=&r"(prev) Chris@16: : "b" (mem), "r" (with), "r" (cmp) Chris@16: : "cc", "memory"); Chris@16: return prev; Chris@16: } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, 1); } Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, boost::uint32_t(-1u)); } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@101: { Chris@101: const boost::uint32_t val = *mem; Chris@101: __asm__ __volatile__ ( "" ::: "memory" ); Chris@101: return val; Chris@101: } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { *mem = val; } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@16: #elif (defined(sun) || defined(__sun)) Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically add 'val' to an boost::uint32_t Chris@16: //! "mem": pointer to the object Chris@16: //! "val": amount to add Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { return atomic_add_32_nv(reinterpret_cast(mem), (int32_t)val) - val; } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { return atomic_cas_32(reinterpret_cast(mem), cmp, with); } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add_32_nv(reinterpret_cast(mem), 1) - 1; } Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add_32_nv(reinterpret_cast(mem), (boost::uint32_t)-1) + 1; } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@16: { return *mem; } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { *mem = val; } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@16: #elif defined(__osf__) && defined(__DECCXX) Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically decrement a uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: //! Acquire, memory barrier after decrement. Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; } Chris@16: Chris@16: //! Atomically increment a uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: //! Release, memory barrier before increment. Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { __MB(); return __ATOMIC_INCREMENT_LONG(mem); } Chris@16: Chris@16: // Rational for the implementation of the atomic read and write functions. Chris@16: // Chris@16: // 1. The Alpha Architecture Handbook requires that access to a byte, Chris@16: // an aligned word, an aligned longword, or an aligned quadword is Chris@16: // atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.) Chris@16: // Chris@16: // 2. The CXX User's Guide states that volatile quantities are accessed Chris@16: // with single assembler instructions, and that a compilation error Chris@16: // occurs when declaring a quantity as volatile which is not properly Chris@16: // aligned. Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: //! Acquire, memory barrier after load. Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@16: { boost::uint32_t old_val = *mem; __MB(); return old_val; } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: //! Release, memory barrier before store. Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { __MB(); *mem = val; } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: //! Memory barrier between load and store. Chris@16: inline boost::uint32_t atomic_cas32( Chris@16: volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { Chris@16: // Note: Chris@16: // Chris@16: // Branch prediction prefers backward branches, and the Alpha Architecture Chris@16: // Handbook explicitely states that the loop should not be implemented like Chris@16: // it is below. (See chapter 4.2.5.) Therefore the code should probably look Chris@16: // like this: Chris@16: // Chris@16: // return asm( Chris@16: // "10: ldl_l %v0,(%a0) ;" Chris@16: // " cmpeq %v0,%a2,%t0 ;" Chris@16: // " beq %t0,20f ;" Chris@16: // " mb ;" Chris@16: // " mov %a1,%t0 ;" Chris@16: // " stl_c %t0,(%a0) ;" Chris@16: // " beq %t0,30f ;" Chris@16: // "20: ret ;" Chris@16: // "30: br 10b;", Chris@16: // mem, with, cmp); Chris@16: // Chris@16: // But as the compiler always transforms this into the form where a backward Chris@16: // branch is taken on failure, we can as well implement it in the straight Chris@16: // forward form, as this is what it will end up in anyway. Chris@16: Chris@16: return asm( Chris@16: "10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem Chris@16: " cmpeq %v0,%a2,%t0 ;" // compare with given value Chris@16: " beq %t0,20f ;" // if not equal, we're done Chris@16: " mb ;" // memory barrier Chris@16: " mov %a1,%t0 ;" // load new value into scratch register Chris@16: " stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch) Chris@16: " beq %t0,10b ;" // store failed because lock has been stolen, retry Chris@16: "20: ", Chris@16: mem, with, cmp); Chris@16: } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@16: #elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX) Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting Chris@16: //all the functions with casts Chris@16: Chris@16: //! From XLC documenation : Chris@16: //! This function can be used with a subsequent stwcxu call to implement a Chris@16: //! read-modify-write on a specified memory location. The two functions work Chris@16: //! together to ensure that if the store is successfully performed, no other Chris@16: //! processor or mechanism can modify the target doubleword between the time Chris@16: //! lwarxu function is executed and the time the stwcxu functio ncompletes. Chris@16: //! "mem" : pointer to the object Chris@16: //! Returns the value at pointed to by mem Chris@16: inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem) Chris@16: { Chris@16: return static_cast(__lwarx(reinterpret_cast(mem))); Chris@16: } Chris@16: Chris@16: //! "mem" : pointer to the object Chris@16: //! "val" : the value to store Chris@16: //! Returns true if the update of mem is successful and false if it is Chris@16: //!unsuccessful Chris@16: inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val) Chris@16: { Chris@16: return (__stwcx(reinterpret_cast(mem), static_cast(val)) != 0); Chris@16: } Chris@16: Chris@16: //! "mem": pointer to the object Chris@16: //! "val": amount to add Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_add32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { Chris@16: boost::uint32_t oldValue; Chris@16: do Chris@16: { Chris@16: oldValue = lwarxu(mem); Chris@16: }while (!stwcxu(mem, oldValue+val)); Chris@16: return oldValue; Chris@16: } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, 1); } Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, (boost::uint32_t)-1); } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@16: { return *mem; } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { Chris@16: boost::uint32_t oldValue; Chris@16: boost::uint32_t valueToStore; Chris@16: do Chris@16: { Chris@16: oldValue = lwarxu(mem); Chris@16: } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue)); Chris@16: Chris@16: return oldValue; Chris@16: } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { *mem = val; } Chris@16: Chris@16: } //namespace ipcdetail Chris@16: } //namespace interprocess Chris@16: } //namespace boost Chris@16: Chris@16: #elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) Chris@16: Chris@16: namespace boost { Chris@16: namespace interprocess { Chris@16: namespace ipcdetail{ Chris@16: Chris@16: //! Atomically add 'val' to an boost::uint32_t Chris@16: //! "mem": pointer to the object Chris@16: //! "val": amount to add Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_add32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t val) Chris@16: { return __sync_fetch_and_add(const_cast(mem), val); } Chris@16: Chris@16: //! Atomically increment an apr_uint32_t by 1 Chris@16: //! "mem": pointer to the object Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, 1); } Chris@16: Chris@16: //! Atomically decrement an boost::uint32_t by 1 Chris@16: //! "mem": pointer to the atomic value Chris@16: //! Returns the old value pointed to by mem Chris@16: inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem) Chris@16: { return atomic_add32(mem, (boost::uint32_t)-1); } Chris@16: Chris@16: //! Atomically read an boost::uint32_t from memory Chris@16: inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem) Chris@101: { boost::uint32_t old_val = *mem; __sync_synchronize(); return old_val; } Chris@16: Chris@16: //! Compare an boost::uint32_t's value with "cmp". Chris@16: //! If they are the same swap the value with "with" Chris@16: //! "mem": pointer to the value Chris@16: //! "with" what to swap it with Chris@16: //! "cmp": the value to compare it to Chris@16: //! Returns the old value of *mem Chris@16: inline boost::uint32_t atomic_cas32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp) Chris@16: { return __sync_val_compare_and_swap(const_cast(mem), cmp, with); } Chris@16: Chris@16: //! Atomically set an boost::uint32_t in memory Chris@16: //! "mem": pointer to the object Chris@16: //! "param": val value that the object will assume Chris@16: inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val) Chris@101: { __sync_synchronize(); *mem = val; } Chris@16: Chris@16: } //namespace ipcdetail{ Chris@16: } //namespace interprocess{ Chris@16: } //namespace boost{ Chris@16: Chris@16: #else Chris@16: Chris@16: #error No atomic operations implemented for this platform, sorry! Chris@16: Chris@16: #endif Chris@16: Chris@16: namespace boost{ Chris@16: namespace interprocess{ Chris@16: namespace ipcdetail{ Chris@16: Chris@16: inline bool atomic_add_unless32 Chris@16: (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this) Chris@16: { Chris@16: boost::uint32_t old, c(atomic_read32(mem)); Chris@16: while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){ Chris@16: c = old; Chris@16: } Chris@16: return c != unless_this; Chris@16: } Chris@16: Chris@16: } //namespace ipcdetail Chris@16: } //namespace interprocess Chris@16: } //namespace boost Chris@16: Chris@16: Chris@16: #include Chris@16: Chris@16: #endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP