annotate DEPENDENCIES/generic/include/boost/interprocess/detail/atomic.hpp @ 133:4acb5d8d80b6 tip

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