Imported Upstream version 1.51.0
[platform/upstream/boost.git] / boost / interprocess / detail / atomic.hpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2006-2011
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"(cmp), "r" (with)
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