123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- //////////////////////////////////////////////////////////////////////////////
- //
- // (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__))
- 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"(cmp), "r" (with)
- : "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
|