atomic.hpp 22 KB

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