summaryrefslogtreecommitdiff
path: root/src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp')
-rw-r--r--src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp562
1 files changed, 562 insertions, 0 deletions
diff --git a/src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp b/src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp
new file mode 100644
index 00000000000..11992d1d157
--- /dev/null
+++ b/src/third_party/boost-1.56.0/boost/interprocess/detail/atomic.hpp
@@ -0,0 +1,562 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2006-2012
+// (C) Copyright Markus Schoepflin 2007
+// (C) Copyright Bryce Lelbach 2010
+//
+// 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.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
+#define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
+
+#include <boost/interprocess/detail/config_begin.hpp>
+#include <boost/interprocess/detail/workaround.hpp>
+#include <boost/cstdint.hpp>
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+//! Atomically increment an boost::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);
+
+//! Atomically read an boost::uint32_t from memory
+inline boost::uint32_t atomic_read32(volatile boost::uint32_t *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);
+
+//! 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);
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#if defined (BOOST_INTERPROCESS_WINDOWS)
+
+#include <boost/interprocess/detail/win32_api.hpp>
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; }
+
+//! 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 winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
+
+//! 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)
+{ winapi::interlocked_exchange(reinterpret_cast<volatile long*>(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)
+{ return winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), with, cmp); }
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(_CRAYC)
+
+namespace boost {
+namespace interprocess {
+namespace ipcdetail{
+
+//! 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)
+{
+ boost::uint32_t prev = cmp;
+ // This version by Mans Rullgard of Pathscale
+ __asm__ __volatile__ ( "lock\n\t"
+ "cmpxchg %2,%0"
+ : "+m"(*mem), "+a"(prev)
+ : "r"(with)
+ : "cc");
+
+ return prev;
+}
+
+//! Atomically add 'val' to an boost::uint32_t
+//! "mem": pointer to the object
+//! "val": amount to add
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_add32
+ (volatile boost::uint32_t *mem, boost::uint32_t val)
+{
+ // int r = *pw;
+ // *mem += val;
+ // return r;
+ int r;
+
+ asm volatile
+ (
+ "lock\n\t"
+ "xadd %1, %0":
+ "+m"( *mem ), "=r"( r ): // outputs (%0, %1)
+ "1"( val ): // inputs (%2 == %1)
+ "memory", "cc" // clobbers
+ );
+
+ return r;
+}
+
+//! 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_add32(mem, 1); }
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return atomic_add32(mem, (boost::uint32_t)-1); }
+
+//! 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; }
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__))
+
+namespace boost {
+namespace interprocess {
+namespace ipcdetail{
+
+//! Atomically add 'val' to an boost::uint32_t
+//! "mem": pointer to the object
+//! "val": amount to add
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
+{
+ boost::uint32_t prev, temp;
+
+ asm volatile ("1:\n\t"
+ "lwarx %0,0,%2\n\t"
+ "add %1,%0,%3\n\t"
+ "stwcx. %1,0,%2\n\t"
+ "bne- 1b"
+ : "=&r" (prev), "=&r" (temp)
+ : "b" (mem), "r" (val)
+ : "cc", "memory");
+ return prev;
+}
+
+//! 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)
+{
+ boost::uint32_t prev;
+
+ asm volatile ("1:\n\t"
+ "lwarx %0,0,%1\n\t"
+ "cmpw %0,%3\n\t"
+ "bne- 2f\n\t"
+ "stwcx. %2,0,%1\n\t"
+ "bne- 1b\n\t"
+ "2:"
+ : "=&r"(prev)
+ : "b" (mem), "r" (with), "r" (cmp)
+ : "cc", "memory");
+ return prev;
+}
+
+//! 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_add32(mem, 1); }
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return atomic_add32(mem, boost::uint32_t(-1u)); }
+
+//! 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; }
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#elif (defined(sun) || defined(__sun))
+
+#include <atomic.h>
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+//! Atomically add 'val' to an boost::uint32_t
+//! "mem": pointer to the object
+//! "val": amount to add
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
+{ return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (int32_t)val) - 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)
+{ return atomic_cas_32(reinterpret_cast<volatile ::uint32_t*>(mem), cmp, with); }
+
+//! 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_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), 1) - 1; }
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (boost::uint32_t)-1) + 1; }
+
+//! 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; }
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#elif defined(__osf__) && defined(__DECCXX)
+
+#include <machine/builtins.h>
+#include <c_asm.h>
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+//! 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)
+{ __MB(); return __ATOMIC_INCREMENT_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
+//! Acquire, memory barrier after load.
+inline boost::uint32_t atomic_read32(volatile boost::uint32_t *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)
+{ __MB(); *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
+//! 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)
+{
+ // 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:
+ //
+ // 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);
+ //
+ // 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 ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX)
+
+#include <builtins.h>
+
+namespace boost {
+namespace interprocess {
+namespace ipcdetail{
+
+//first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting
+//all the functions with casts
+
+//! From XLC documenation :
+//! This function can be used with a subsequent stwcxu call to implement a
+//! read-modify-write on a specified memory location. The two functions work
+//! together to ensure that if the store is successfully performed, no other
+//! processor or mechanism can modify the target doubleword between the time
+//! lwarxu function is executed and the time the stwcxu functio ncompletes.
+//! "mem" : pointer to the object
+//! Returns the value at pointed to by mem
+inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem)
+{
+ return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem)));
+}
+
+//! "mem" : pointer to the object
+//! "val" : the value to store
+//! Returns true if the update of mem is successful and false if it is
+//!unsuccessful
+inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val)
+{
+ return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0);
+}
+
+//! "mem": pointer to the object
+//! "val": amount to add
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_add32
+ (volatile boost::uint32_t *mem, boost::uint32_t val)
+{
+ boost::uint32_t oldValue;
+ do
+ {
+ oldValue = lwarxu(mem);
+ }while (!stwcxu(mem, oldValue+val));
+ return oldValue;
+}
+
+//! 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_add32(mem, 1); }
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return atomic_add32(mem, (boost::uint32_t)-1); }
+
+//! Atomically read an boost::uint32_t from memory
+inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
+{ return *mem; }
+
+//! 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)
+{
+ boost::uint32_t oldValue;
+ boost::uint32_t valueToStore;
+ do
+ {
+ oldValue = lwarxu(mem);
+ } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue));
+
+ return oldValue;
+}
+
+//! 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; }
+
+} //namespace ipcdetail
+} //namespace interprocess
+} //namespace boost
+
+#elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
+
+namespace boost {
+namespace interprocess {
+namespace ipcdetail{
+
+//! Atomically add 'val' to an boost::uint32_t
+//! "mem": pointer to the object
+//! "val": amount to add
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_add32
+ (volatile boost::uint32_t *mem, boost::uint32_t val)
+{ return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
+
+//! 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_add32(mem, 1); }
+
+//! Atomically decrement an boost::uint32_t by 1
+//! "mem": pointer to the atomic value
+//! Returns the old value pointed to by mem
+inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
+{ return atomic_add32(mem, (boost::uint32_t)-1); }
+
+//! Atomically read an boost::uint32_t from memory
+inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
+{ return *mem; }
+
+//! 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)
+{ return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); }
+
+//! 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; }
+
+} //namespace ipcdetail{
+} //namespace interprocess{
+} //namespace boost{
+
+#else
+
+#error No atomic operations implemented for this platform, sorry!
+
+#endif
+
+namespace boost{
+namespace interprocess{
+namespace ipcdetail{
+
+inline bool atomic_add_unless32
+ (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this)
+{
+ boost::uint32_t old, c(atomic_read32(mem));
+ while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){
+ c = old;
+ }
+ return c != unless_this;
+}
+
+} //namespace ipcdetail
+} //namespace interprocess
+} //namespace boost
+
+
+#include <boost/interprocess/detail/config_end.hpp>
+
+#endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP