atomic.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2006-2012
  4. // (C) Copyright Markus Schoepflin 2007
  5. // (C) Copyright Bryce Lelbach 2010
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See
  8. // accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // See http://www.boost.org/libs/interprocess for documentation.
  12. //
  13. //////////////////////////////////////////////////////////////////////////////
  14. #ifndef BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
  15. #define BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP
  16. #ifndef BOOST_CONFIG_HPP
  17. # include <boost/config.hpp>
  18. #endif
  19. #
  20. #if defined(BOOST_HAS_PRAGMA_ONCE)
  21. # pragma once
  22. #endif
  23. #include <boost/interprocess/detail/config_begin.hpp>
  24. #include <boost/interprocess/detail/workaround.hpp>
  25. #include <boost/cstdint.hpp>
  26. #if !defined(_AIX)
  27. #define BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL(label) label ":\n\t"
  28. #define BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP(insn, label, offset) insn " " label "\n\t"
  29. #else
  30. #define BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL(label)
  31. #define BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP(insn, label, offset) insn " $" offset "\n\t"
  32. #endif
  33. namespace boost{
  34. namespace interprocess{
  35. namespace ipcdetail{
  36. //! Atomically increment an boost::uint32_t by 1
  37. //! "mem": pointer to the object
  38. //! Returns the old value pointed to by mem
  39. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem);
  40. //! Atomically read an boost::uint32_t from memory
  41. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem);
  42. //! Atomically set an boost::uint32_t in memory
  43. //! "mem": pointer to the object
  44. //! "param": val value that the object will assume
  45. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val);
  46. //! Compare an boost::uint32_t's value with "cmp".
  47. //! If they are the same swap the value with "with"
  48. //! "mem": pointer to the value
  49. //! "with": what to swap it with
  50. //! "cmp": the value to compare it to
  51. //! Returns the old value of *mem
  52. inline boost::uint32_t atomic_cas32
  53. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp);
  54. } //namespace ipcdetail{
  55. } //namespace interprocess{
  56. } //namespace boost{
  57. #if defined (BOOST_INTERPROCESS_WINDOWS)
  58. #include <boost/interprocess/detail/win32_api.hpp>
  59. #if defined( _MSC_VER )
  60. extern "C" void _ReadWriteBarrier(void);
  61. #pragma intrinsic(_ReadWriteBarrier)
  62. #define BOOST_INTERPROCESS_READ_WRITE_BARRIER \
  63. BOOST_INTERPROCESS_DISABLE_DEPRECATED_WARNING \
  64. _ReadWriteBarrier() \
  65. BOOST_INTERPROCESS_RESTORE_WARNING
  66. #elif defined(__GNUC__)
  67. # define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize()
  68. #else
  69. # error "Unsupported Compiler for Window"
  70. #endif
  71. namespace boost{
  72. namespace interprocess{
  73. namespace ipcdetail{
  74. //! Atomically decrement an boost::uint32_t by 1
  75. //! "mem": pointer to the atomic value
  76. //! Returns the old value pointed to by mem
  77. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  78. { return (boost::uint32_t)winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; }
  79. //! Atomically increment an apr_uint32_t by 1
  80. //! "mem": pointer to the object
  81. //! Returns the old value pointed to by mem
  82. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  83. { return (boost::uint32_t)winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
  84. //! Atomically read an boost::uint32_t from memory
  85. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  86. {
  87. const boost::uint32_t val = *mem;
  88. BOOST_INTERPROCESS_READ_WRITE_BARRIER;
  89. return val;
  90. }
  91. //! Atomically set an boost::uint32_t in memory
  92. //! "mem": pointer to the object
  93. //! "param": val value that the object will assume
  94. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  95. { winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), (long)val); }
  96. //! Compare an boost::uint32_t's value with "cmp".
  97. //! If they are the same swap the value with "with"
  98. //! "mem": pointer to the value
  99. //! "with": what to swap it with
  100. //! "cmp": the value to compare it to
  101. //! Returns the old value of *mem
  102. inline boost::uint32_t atomic_cas32
  103. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  104. { return (boost::uint32_t)winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), (long)with, (long)cmp); }
  105. } //namespace ipcdetail{
  106. } //namespace interprocess{
  107. } //namespace boost{
  108. #elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
  109. namespace boost {
  110. namespace interprocess {
  111. namespace ipcdetail{
  112. //! Atomically add 'val' to an boost::uint32_t
  113. //! "mem": pointer to the object
  114. //! "val": amount to add
  115. //! Returns the old value pointed to by mem
  116. inline boost::uint32_t atomic_add32
  117. (volatile boost::uint32_t *mem, boost::uint32_t val)
  118. { return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
  119. //! Atomically increment an apr_uint32_t by 1
  120. //! "mem": pointer to the object
  121. //! Returns the old value pointed to by mem
  122. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  123. { return atomic_add32(mem, 1); }
  124. //! Atomically decrement an boost::uint32_t by 1
  125. //! "mem": pointer to the atomic value
  126. //! Returns the old value pointed to by mem
  127. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  128. { return atomic_add32(mem, (boost::uint32_t)-1); }
  129. //! Atomically read an boost::uint32_t from memory
  130. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  131. { boost::uint32_t old_val = *mem; __sync_synchronize(); return old_val; }
  132. //! Compare an boost::uint32_t's value with "cmp".
  133. //! If they are the same swap the value with "with"
  134. //! "mem": pointer to the value
  135. //! "with" what to swap it with
  136. //! "cmp": the value to compare it to
  137. //! Returns the old value of *mem
  138. inline boost::uint32_t atomic_cas32
  139. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  140. { return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); }
  141. //! Atomically set an boost::uint32_t in memory
  142. //! "mem": pointer to the object
  143. //! "param": val value that the object will assume
  144. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  145. { __sync_synchronize(); *mem = val; }
  146. } //namespace ipcdetail{
  147. } //namespace interprocess{
  148. } //namespace boost{
  149. #else
  150. #error No atomic operations implemented for this platform, sorry!
  151. #endif
  152. namespace boost{
  153. namespace interprocess{
  154. namespace ipcdetail{
  155. inline bool atomic_add_unless32
  156. (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this)
  157. {
  158. boost::uint32_t old, c(atomic_read32(mem));
  159. while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){
  160. c = old;
  161. }
  162. return c != unless_this;
  163. }
  164. } //namespace ipcdetail
  165. } //namespace interprocess
  166. } //namespace boost
  167. #include <boost/interprocess/detail/config_end.hpp>
  168. #endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP