atomic.hpp 22 KB

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