atomic.hpp 19 KB

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