atomic.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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. #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
  68. #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __sync_synchronize()
  69. #else
  70. #define BOOST_INTERPROCESS_READ_WRITE_BARRIER __asm__ __volatile__("" : : : "memory")
  71. #endif
  72. #endif
  73. namespace boost{
  74. namespace interprocess{
  75. namespace ipcdetail{
  76. //! Atomically decrement an boost::uint32_t by 1
  77. //! "mem": pointer to the atomic value
  78. //! Returns the old value pointed to by mem
  79. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  80. { return (boost::uint32_t)winapi::interlocked_decrement(reinterpret_cast<volatile long*>(mem)) + 1; }
  81. //! Atomically increment an apr_uint32_t by 1
  82. //! "mem": pointer to the object
  83. //! Returns the old value pointed to by mem
  84. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  85. { return (boost::uint32_t)winapi::interlocked_increment(reinterpret_cast<volatile long*>(mem))-1; }
  86. //! Atomically read an boost::uint32_t from memory
  87. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  88. {
  89. const boost::uint32_t val = *mem;
  90. BOOST_INTERPROCESS_READ_WRITE_BARRIER;
  91. return val;
  92. }
  93. //! Atomically set an boost::uint32_t in memory
  94. //! "mem": pointer to the object
  95. //! "param": val value that the object will assume
  96. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  97. { winapi::interlocked_exchange(reinterpret_cast<volatile long*>(mem), (long)val); }
  98. //! Compare an boost::uint32_t's value with "cmp".
  99. //! If they are the same swap the value with "with"
  100. //! "mem": pointer to the value
  101. //! "with": what to swap it with
  102. //! "cmp": the value to compare it to
  103. //! Returns the old value of *mem
  104. inline boost::uint32_t atomic_cas32
  105. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  106. { return (boost::uint32_t)winapi::interlocked_compare_exchange(reinterpret_cast<volatile long*>(mem), (long)with, (long)cmp); }
  107. } //namespace ipcdetail{
  108. } //namespace interprocess{
  109. } //namespace boost{
  110. #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(_CRAYC)
  111. namespace boost {
  112. namespace interprocess {
  113. namespace ipcdetail{
  114. //! Compare an boost::uint32_t's value with "cmp".
  115. //! If they are the same swap the value with "with"
  116. //! "mem": pointer to the value
  117. //! "with" what to swap it with
  118. //! "cmp": the value to compare it to
  119. //! Returns the old value of *mem
  120. inline boost::uint32_t atomic_cas32
  121. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  122. {
  123. boost::uint32_t prev = cmp;
  124. // This version by Mans Rullgard of Pathscale
  125. __asm__ __volatile__ ( "lock\n\t"
  126. "cmpxchg %2,%0"
  127. : "+m"(*mem), "+a"(prev)
  128. : "r"(with)
  129. : "cc");
  130. return prev;
  131. }
  132. //! Atomically add 'val' to an boost::uint32_t
  133. //! "mem": pointer to the object
  134. //! "val": amount to add
  135. //! Returns the old value pointed to by mem
  136. inline boost::uint32_t atomic_add32
  137. (volatile boost::uint32_t *mem, boost::uint32_t val)
  138. {
  139. // int r = *pw;
  140. // *mem += val;
  141. // return r;
  142. boost::uint32_t r;
  143. asm volatile
  144. (
  145. "lock\n\t"
  146. "xadd %1, %0":
  147. "+m"( *mem ), "=r"( r ): // outputs (%0, %1)
  148. "1"( val ): // inputs (%2 == %1)
  149. "memory", "cc" // clobbers
  150. );
  151. return r;
  152. }
  153. //! Atomically increment an apr_uint32_t by 1
  154. //! "mem": pointer to the object
  155. //! Returns the old value pointed to by mem
  156. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  157. { return atomic_add32(mem, 1); }
  158. //! Atomically decrement an boost::uint32_t by 1
  159. //! "mem": pointer to the atomic value
  160. //! Returns the old value pointed to by mem
  161. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  162. { return atomic_add32(mem, (boost::uint32_t)-1); }
  163. //! Atomically read an boost::uint32_t from memory
  164. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  165. {
  166. const boost::uint32_t val = *mem;
  167. __asm__ __volatile__ ( "" ::: "memory" );
  168. return val;
  169. }
  170. //! Atomically set an boost::uint32_t in memory
  171. //! "mem": pointer to the object
  172. //! "param": val value that the object will assume
  173. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  174. {
  175. __asm__ __volatile__
  176. (
  177. "xchgl %0, %1"
  178. : "+r" (val), "+m" (*mem)
  179. :: "memory"
  180. );
  181. }
  182. } //namespace ipcdetail{
  183. } //namespace interprocess{
  184. } //namespace boost{
  185. #elif defined(__GNUC__) && (defined(__PPC__) || defined(__ppc__))
  186. namespace boost {
  187. namespace interprocess {
  188. namespace ipcdetail{
  189. //! Atomically add 'val' to an boost::uint32_t
  190. //! "mem": pointer to the object
  191. //! "val": amount to add
  192. //! Returns the old value pointed to by mem
  193. inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
  194. {
  195. boost::uint32_t prev, temp;
  196. asm volatile
  197. (
  198. BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("1")
  199. "lwarx %0,0,%2\n\t"
  200. "add %1,%0,%3\n\t"
  201. "stwcx. %1,0,%2\n\t"
  202. BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "1b", "-12")
  203. : "=&r" (prev), "=&r" (temp)
  204. : "b" (mem), "r" (val)
  205. : "cc", "memory"
  206. );
  207. return prev;
  208. }
  209. //! Compare an boost::uint32_t's value with "cmp".
  210. //! If they are the same swap the value with "with"
  211. //! "mem": pointer to the value
  212. //! "with" what to swap it with
  213. //! "cmp": the value to compare it to
  214. //! Returns the old value of *mem
  215. inline boost::uint32_t atomic_cas32
  216. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  217. {
  218. boost::uint32_t prev;
  219. asm volatile
  220. (
  221. BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("1")
  222. "lwarx %0,0,%1\n\t"
  223. "cmpw %0,%3\n\t"
  224. BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "2f", "+12")
  225. "stwcx. %2,0,%1\n\t"
  226. BOOST_INTERPROCESS_DETAIL_PPC_ASM_JUMP("bne-", "1b", "-16")
  227. BOOST_INTERPROCESS_DETAIL_PPC_ASM_LABEL("2")
  228. : "=&r"(prev)
  229. : "b" (mem), "r" (with), "r" (cmp)
  230. : "cc", "memory"
  231. );
  232. return prev;
  233. }
  234. //! Atomically increment an apr_uint32_t by 1
  235. //! "mem": pointer to the object
  236. //! Returns the old value pointed to by mem
  237. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  238. { return atomic_add32(mem, 1); }
  239. //! Atomically decrement an boost::uint32_t by 1
  240. //! "mem": pointer to the atomic value
  241. //! Returns the old value pointed to by mem
  242. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  243. { return atomic_add32(mem, boost::uint32_t(-1u)); }
  244. //! Atomically read an boost::uint32_t from memory
  245. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  246. {
  247. const boost::uint32_t val = *mem;
  248. __asm__ __volatile__ ( "" ::: "memory" );
  249. return val;
  250. }
  251. //! Atomically set an boost::uint32_t in memory
  252. //! "mem": pointer to the object
  253. //! "param": val value that the object will assume
  254. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  255. { *mem = val; }
  256. } //namespace ipcdetail{
  257. } //namespace interprocess{
  258. } //namespace boost{
  259. #elif (defined(sun) || defined(__sun))
  260. #include <atomic.h>
  261. namespace boost{
  262. namespace interprocess{
  263. namespace ipcdetail{
  264. //! Atomically add 'val' to an boost::uint32_t
  265. //! "mem": pointer to the object
  266. //! "val": amount to add
  267. //! Returns the old value pointed to by mem
  268. inline boost::uint32_t atomic_add32(volatile boost::uint32_t *mem, boost::uint32_t val)
  269. { return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (int32_t)val) - val; }
  270. //! Compare an boost::uint32_t's value with "cmp".
  271. //! If they are the same swap the value with "with"
  272. //! "mem": pointer to the value
  273. //! "with" what to swap it with
  274. //! "cmp": the value to compare it to
  275. //! Returns the old value of *mem
  276. inline boost::uint32_t atomic_cas32
  277. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  278. { return atomic_cas_32(reinterpret_cast<volatile ::uint32_t*>(mem), cmp, with); }
  279. //! Atomically increment an apr_uint32_t by 1
  280. //! "mem": pointer to the object
  281. //! Returns the old value pointed to by mem
  282. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  283. { return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), 1) - 1; }
  284. //! Atomically decrement an boost::uint32_t by 1
  285. //! "mem": pointer to the atomic value
  286. //! Returns the old value pointed to by mem
  287. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  288. { return atomic_add_32_nv(reinterpret_cast<volatile ::uint32_t*>(mem), (boost::uint32_t)-1) + 1; }
  289. //! Atomically read an boost::uint32_t from memory
  290. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  291. { return *mem; }
  292. //! Atomically set an boost::uint32_t in memory
  293. //! "mem": pointer to the object
  294. //! "param": val value that the object will assume
  295. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  296. { *mem = val; }
  297. } //namespace ipcdetail{
  298. } //namespace interprocess{
  299. } //namespace boost{
  300. #elif defined(__osf__) && defined(__DECCXX)
  301. #include <machine/builtins.h>
  302. #include <c_asm.h>
  303. namespace boost{
  304. namespace interprocess{
  305. namespace ipcdetail{
  306. //! Atomically decrement a uint32_t by 1
  307. //! "mem": pointer to the atomic value
  308. //! Returns the old value pointed to by mem
  309. //! Acquire, memory barrier after decrement.
  310. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  311. { boost::uint32_t old_val = __ATOMIC_DECREMENT_LONG(mem); __MB(); return old_val; }
  312. //! Atomically increment a uint32_t by 1
  313. //! "mem": pointer to the object
  314. //! Returns the old value pointed to by mem
  315. //! Release, memory barrier before increment.
  316. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  317. { __MB(); return __ATOMIC_INCREMENT_LONG(mem); }
  318. // Rational for the implementation of the atomic read and write functions.
  319. //
  320. // 1. The Alpha Architecture Handbook requires that access to a byte,
  321. // an aligned word, an aligned longword, or an aligned quadword is
  322. // atomic. (See 'Alpha Architecture Handbook', version 4, chapter 5.2.2.)
  323. //
  324. // 2. The CXX User's Guide states that volatile quantities are accessed
  325. // with single assembler instructions, and that a compilation error
  326. // occurs when declaring a quantity as volatile which is not properly
  327. // aligned.
  328. //! Atomically read an boost::uint32_t from memory
  329. //! Acquire, memory barrier after load.
  330. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  331. { boost::uint32_t old_val = *mem; __MB(); return old_val; }
  332. //! Atomically set an boost::uint32_t in memory
  333. //! "mem": pointer to the object
  334. //! "param": val value that the object will assume
  335. //! Release, memory barrier before store.
  336. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  337. { __MB(); *mem = val; }
  338. //! Compare an boost::uint32_t's value with "cmp".
  339. //! If they are the same swap the value with "with"
  340. //! "mem": pointer to the value
  341. //! "with" what to swap it with
  342. //! "cmp": the value to compare it to
  343. //! Returns the old value of *mem
  344. //! Memory barrier between load and store.
  345. inline boost::uint32_t atomic_cas32(
  346. volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  347. {
  348. // Note:
  349. //
  350. // Branch prediction prefers backward branches, and the Alpha Architecture
  351. // Handbook explicitely states that the loop should not be implemented like
  352. // it is below. (See chapter 4.2.5.) Therefore the code should probably look
  353. // like this:
  354. //
  355. // return asm(
  356. // "10: ldl_l %v0,(%a0) ;"
  357. // " cmpeq %v0,%a2,%t0 ;"
  358. // " beq %t0,20f ;"
  359. // " mb ;"
  360. // " mov %a1,%t0 ;"
  361. // " stl_c %t0,(%a0) ;"
  362. // " beq %t0,30f ;"
  363. // "20: ret ;"
  364. // "30: br 10b;",
  365. // mem, with, cmp);
  366. //
  367. // But as the compiler always transforms this into the form where a backward
  368. // branch is taken on failure, we can as well implement it in the straight
  369. // forward form, as this is what it will end up in anyway.
  370. return asm(
  371. "10: ldl_l %v0,(%a0) ;" // load prev value from mem and lock mem
  372. " cmpeq %v0,%a2,%t0 ;" // compare with given value
  373. " beq %t0,20f ;" // if not equal, we're done
  374. " mb ;" // memory barrier
  375. " mov %a1,%t0 ;" // load new value into scratch register
  376. " stl_c %t0,(%a0) ;" // store new value to locked mem (overwriting scratch)
  377. " beq %t0,10b ;" // store failed because lock has been stolen, retry
  378. "20: ",
  379. mem, with, cmp);
  380. }
  381. } //namespace ipcdetail{
  382. } //namespace interprocess{
  383. } //namespace boost{
  384. #elif defined(__IBMCPP__) && (__IBMCPP__ >= 800) && defined(_AIX)
  385. #include <builtins.h>
  386. namespace boost {
  387. namespace interprocess {
  388. namespace ipcdetail{
  389. //first define boost::uint32_t versions of __lwarx and __stwcx to avoid poluting
  390. //all the functions with casts
  391. //! From XLC documenation :
  392. //! This function can be used with a subsequent stwcxu call to implement a
  393. //! read-modify-write on a specified memory location. The two functions work
  394. //! together to ensure that if the store is successfully performed, no other
  395. //! processor or mechanism can modify the target doubleword between the time
  396. //! lwarxu function is executed and the time the stwcxu functio ncompletes.
  397. //! "mem" : pointer to the object
  398. //! Returns the value at pointed to by mem
  399. inline boost::uint32_t lwarxu(volatile boost::uint32_t *mem)
  400. {
  401. return static_cast<boost::uint32_t>(__lwarx(reinterpret_cast<volatile int*>(mem)));
  402. }
  403. //! "mem" : pointer to the object
  404. //! "val" : the value to store
  405. //! Returns true if the update of mem is successful and false if it is
  406. //!unsuccessful
  407. inline bool stwcxu(volatile boost::uint32_t* mem, boost::uint32_t val)
  408. {
  409. return (__stwcx(reinterpret_cast<volatile int*>(mem), static_cast<int>(val)) != 0);
  410. }
  411. //! "mem": pointer to the object
  412. //! "val": amount to add
  413. //! Returns the old value pointed to by mem
  414. inline boost::uint32_t atomic_add32
  415. (volatile boost::uint32_t *mem, boost::uint32_t val)
  416. {
  417. boost::uint32_t oldValue;
  418. do
  419. {
  420. oldValue = lwarxu(mem);
  421. }while (!stwcxu(mem, oldValue+val));
  422. return oldValue;
  423. }
  424. //! Atomically increment an apr_uint32_t by 1
  425. //! "mem": pointer to the object
  426. //! Returns the old value pointed to by mem
  427. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  428. { return atomic_add32(mem, 1); }
  429. //! Atomically decrement an boost::uint32_t by 1
  430. //! "mem": pointer to the atomic value
  431. //! Returns the old value pointed to by mem
  432. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  433. { return atomic_add32(mem, (boost::uint32_t)-1); }
  434. //! Atomically read an boost::uint32_t from memory
  435. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  436. { return *mem; }
  437. //! Compare an boost::uint32_t's value with "cmp".
  438. //! If they are the same swap the value with "with"
  439. //! "mem": pointer to the value
  440. //! "with" what to swap it with
  441. //! "cmp": the value to compare it to
  442. //! Returns the old value of *mem
  443. inline boost::uint32_t atomic_cas32
  444. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  445. {
  446. boost::uint32_t oldValue;
  447. boost::uint32_t valueToStore;
  448. do
  449. {
  450. oldValue = lwarxu(mem);
  451. } while (!stwcxu(mem, (oldValue == with) ? cmp : oldValue));
  452. return oldValue;
  453. }
  454. //! Atomically set an boost::uint32_t in memory
  455. //! "mem": pointer to the object
  456. //! "param": val value that the object will assume
  457. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  458. { *mem = val; }
  459. } //namespace ipcdetail
  460. } //namespace interprocess
  461. } //namespace boost
  462. #elif defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 )
  463. namespace boost {
  464. namespace interprocess {
  465. namespace ipcdetail{
  466. //! Atomically add 'val' to an boost::uint32_t
  467. //! "mem": pointer to the object
  468. //! "val": amount to add
  469. //! Returns the old value pointed to by mem
  470. inline boost::uint32_t atomic_add32
  471. (volatile boost::uint32_t *mem, boost::uint32_t val)
  472. { return __sync_fetch_and_add(const_cast<boost::uint32_t *>(mem), val); }
  473. //! Atomically increment an apr_uint32_t by 1
  474. //! "mem": pointer to the object
  475. //! Returns the old value pointed to by mem
  476. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  477. { return atomic_add32(mem, 1); }
  478. //! Atomically decrement an boost::uint32_t by 1
  479. //! "mem": pointer to the atomic value
  480. //! Returns the old value pointed to by mem
  481. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  482. { return atomic_add32(mem, (boost::uint32_t)-1); }
  483. //! Atomically read an boost::uint32_t from memory
  484. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  485. { boost::uint32_t old_val = *mem; __sync_synchronize(); return old_val; }
  486. //! Compare an boost::uint32_t's value with "cmp".
  487. //! If they are the same swap the value with "with"
  488. //! "mem": pointer to the value
  489. //! "with" what to swap it with
  490. //! "cmp": the value to compare it to
  491. //! Returns the old value of *mem
  492. inline boost::uint32_t atomic_cas32
  493. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  494. { return __sync_val_compare_and_swap(const_cast<boost::uint32_t *>(mem), cmp, with); }
  495. //! Atomically set an boost::uint32_t in memory
  496. //! "mem": pointer to the object
  497. //! "param": val value that the object will assume
  498. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  499. { __sync_synchronize(); *mem = val; }
  500. } //namespace ipcdetail{
  501. } //namespace interprocess{
  502. } //namespace boost{
  503. #elif defined(__VXWORKS__)
  504. #include <vxAtomicLib.h>
  505. // VxWorks atomic32_t is not volatile, for some unknown reason
  506. #define vx_atomic_cast(_i) (reinterpret_cast< ::atomic32_t *>( const_cast<boost::uint32_t *>(_i)))
  507. namespace boost {
  508. namespace interprocess {
  509. namespace ipcdetail{
  510. //! Atomically add 'val' to an boost::uint32_t
  511. //! "mem": pointer to the object
  512. //! "val": amount to add
  513. //! Returns the old value pointed to by mem
  514. inline boost::uint32_t atomic_add32
  515. (volatile boost::uint32_t *mem, boost::uint32_t val)
  516. { return ::vxAtomic32Add( vx_atomic_cast(mem), val); }
  517. //! Atomically increment an apr_uint32_t by 1
  518. //! "mem": pointer to the object
  519. //! Returns the old value pointed to by mem
  520. inline boost::uint32_t atomic_inc32(volatile boost::uint32_t *mem)
  521. { return ::vxAtomic32Inc( vx_atomic_cast(mem) ); }
  522. //! Atomically decrement an boost::uint32_t by 1
  523. //! "mem": pointer to the atomic value
  524. //! Returns the old value pointed to by mem
  525. inline boost::uint32_t atomic_dec32(volatile boost::uint32_t *mem)
  526. { return ::vxAtomic32Dec( vx_atomic_cast(mem) ); }
  527. //! Atomically read an boost::uint32_t from memory
  528. inline boost::uint32_t atomic_read32(volatile boost::uint32_t *mem)
  529. { return ::vxAtomic32Get( vx_atomic_cast(mem) ); }
  530. //! Compare an boost::uint32_t's value with "cmp".
  531. //! If they are the same swap the value with "with"
  532. //! "mem": pointer to the value
  533. //! "with" what to swap it with
  534. //! "cmp": the value to compare it to
  535. //! Returns the old value of *mem
  536. inline boost::uint32_t atomic_cas32
  537. (volatile boost::uint32_t *mem, boost::uint32_t with, boost::uint32_t cmp)
  538. { return ::vxAtomic32Cas( vx_atomic_cast(mem), cmp, with); }
  539. //! Atomically set an boost::uint32_t in memory
  540. //! "mem": pointer to the object
  541. //! "param": val value that the object will assume
  542. inline void atomic_write32(volatile boost::uint32_t *mem, boost::uint32_t val)
  543. { ::vxAtomic32Set( vx_atomic_cast(mem), val); }
  544. } //namespace ipcdetail{
  545. } //namespace interprocess{
  546. } //namespace boost{
  547. #else
  548. #error No atomic operations implemented for this platform, sorry!
  549. #endif
  550. namespace boost{
  551. namespace interprocess{
  552. namespace ipcdetail{
  553. inline bool atomic_add_unless32
  554. (volatile boost::uint32_t *mem, boost::uint32_t value, boost::uint32_t unless_this)
  555. {
  556. boost::uint32_t old, c(atomic_read32(mem));
  557. while(c != unless_this && (old = atomic_cas32(mem, c + value, c)) != c){
  558. c = old;
  559. }
  560. return c != unless_this;
  561. }
  562. } //namespace ipcdetail
  563. } //namespace interprocess
  564. } //namespace boost
  565. #include <boost/interprocess/detail/config_end.hpp>
  566. #endif //BOOST_INTERPROCESS_DETAIL_ATOMIC_HPP