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
|