comparison DEPENDENCIES/generic/include/boost/interprocess/detail/atomic.hpp @ 16:2665513ce2d3

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