blocxx
AtomicOps.hpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Vintela, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
39 #ifndef BLOCXX_ATOMIC_OPS_HPP_
40 #define BLOCXX_ATOMIC_OPS_HPP_
41 #include "blocxx/BLOCXX_config.h"
42 
43 #if defined(BLOCXX_AIX)
44 extern "C"
45 {
46 #include <sys/atomic_op.h>
47 }
48 #elif defined(__HP_aCC) && defined(BLOCXX_ARCH_IA64)
49 #include <machine/sys/inline.h>
50 #endif
51 
52 
53 // TODO: PA-RISC and itanium. IA64 is supported for aCC, but not for gcc.
54 // See http://h21007.www2.hp.com/dspp/files/unprotected/Itanium/spinlocks.pdf
55 // http://www.hpl.hp.com/research/linux/atomic_ops/
56 
57 // The classes and functions defined in this file are not meant for general
58 // use, they are internal implementation details. They may change at any time.
59 
60 // x86 and x86-64 asm is identical
61 #if (defined(BLOCXX_ARCH_X86) || defined(__i386__) || defined(BLOCXX_ARCH_X86_64) || defined(__x86_64__)) && defined(__GNUC__)
62 
63 namespace BLOCXX_NAMESPACE
64 {
65 
66 // use fast inline assembly versions
67 struct Atomic_t
68 {
69  Atomic_t() : val(0) {}
70  Atomic_t(int i) : val(i) {}
71  volatile int val;
72 };
73 inline void AtomicInc(Atomic_t &v)
74 {
75  __asm__ __volatile__(
76  "lock ; " "incl %0"
77  :"=m" (v.val)
78  :"m" (v.val));
79 }
80 inline bool AtomicDecAndTest(Atomic_t &v)
81 {
82  unsigned char c;
83  __asm__ __volatile__(
84  "lock ; " "decl %0; sete %1"
85  :"=m" (v.val), "=qm" (c)
86  :"m" (v.val) : "memory");
87  return c != 0;
88 }
89 inline int AtomicGet(Atomic_t const &v)
90 {
91  return v.val;
92 }
93 inline void AtomicDec(Atomic_t &v)
94 {
95  __asm__ __volatile__(
96  "lock ; " "decl %0"
97  :"=m" (v.val)
98  :"m" (v.val));
99 }
100 
101 } // end namespace BLOCXX_NAMESPACE
102 #elif defined(__HP_aCC) && defined(BLOCXX_ARCH_IA64)
103 namespace BLOCXX_NAMESPACE
104 {
105 struct Atomic_t
106 {
107  Atomic_t() : val(0) {}
108  Atomic_t(int i) : val(i) {}
109  volatile int val;
110 };
111 inline void AtomicInc(Atomic_t &v)
112 {
113  _Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, 1, _LDHINT_NONE);
114 }
115 inline bool AtomicDecAndTest(Atomic_t &v)
116 {
117  int c = int(_Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, int(-1), _LDHINT_NONE));
118  --c;
119  return c == 0;
120 }
121 inline int AtomicGet(Atomic_t const &v)
122 {
123  return int(v.val);
124 }
125 inline void AtomicDec(Atomic_t &v)
126 {
127  _Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, -1, _LDHINT_NONE);
128 }
129 }
130 
131 #elif defined(BLOCXX_AIX)
132 namespace BLOCXX_NAMESPACE
133 {
134 // This comment was stolen from the libstdc++ implementation of atomicity.h
135 // (and modified).
136 // We cannot use the inline assembly for powerpc, since definitions for
137 // these operations since they depend on operations that are not available on
138 // the original POWER architecture. AIX still runs on the POWER architecture,
139 // so it would be incorrect to assume the existence of these instructions.
140 //
141 // The definition of Atomic_t.val must match the type pointed to by atomic_p in
142 // <sys/atomic_op.h>.
143 struct Atomic_t
144 {
145  Atomic_t() : val(0) {}
146  Atomic_t(int i) : val(i) {}
147  volatile int val;
148 };
149 
150 inline void AtomicInc(Atomic_t &v)
151 {
152  ::fetch_and_add(const_cast<atomic_p>(&v.val), 1);
153 }
154 inline bool AtomicDecAndTest(Atomic_t &v)
155 {
156  // fetch_and_add returns the original value before the add operation. Thus,
157  // we must subtract one from the returned value before comparing.
158  int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), -1);
159  --c;
160  return c == 0;
161 }
162 inline int AtomicGet(Atomic_t const &v)
163 {
164  int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), 0);
165  return c;
166 }
167 inline void AtomicDec(Atomic_t &v)
168 {
169  ::fetch_and_add(const_cast<atomic_p>(&v.val), -1);
170 }
171 
172 } // end namespace BLOCXX_NAMESPACE
173 
174 #elif (defined(BLOCXX_ARCH_PPC) || defined(__ppc__)) && defined(__GNUC__)
175 
176 namespace BLOCXX_NAMESPACE
177 {
178 
179 // use fast inline assembly versions
180 struct Atomic_t
181 {
182  Atomic_t() : val(0) {}
183  Atomic_t(int i) : val(i) {}
184  volatile int val;
185 };
186 
187 inline void AtomicInc(Atomic_t &v)
188 {
189  int t;
190  __asm__ __volatile__(
191  "1: lwarx %0,0,%2\n"
192  " addic %0,%0,1\n"
193  " stwcx. %0,0,%2\n"
194  " bne- 1b"
195  : "=&r" (t), "=m" (v.val)
196  : "r" (&v.val), "m" (v.val)
197  : "cc");
198 }
199 inline bool AtomicDecAndTest(Atomic_t &v)
200 {
201  int c;
202  __asm__ __volatile__(
203  "1: lwarx %0,0,%1\n"
204  " addic %0,%0,-1\n"
205  " stwcx. %0,0,%1\n"
206  " bne- 1b\n"
207  " isync"
208  : "=&r" (c)
209  : "r" (&v.val)
210  : "cc", "memory");
211  return c == 0;
212 }
213 inline int AtomicGet(Atomic_t const &v)
214 {
215  return v.val;
216 }
217 inline void AtomicDec(Atomic_t &v)
218 {
219  int c;
220  __asm__ __volatile__(
221  "1: lwarx %0,0,%2\n"
222  " addic %0,%0,-1\n"
223  " stwcx. %0,0,%2\n"
224  " bne- 1b"
225  : "=&r" (c), "=m" (v.val)
226  : "r" (&v.val), "m" (v.val)
227  : "cc");
228 }
229 
230 } // end namespace BLOCXX_NAMESPACE
231 
232 #elif defined(BLOCXX_WIN32)
233 
234 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
235 #include <wtypes.h>
236 
237 namespace BLOCXX_NAMESPACE
238 {
239 
240 // use fast inline assembly versions
241 struct BLOCXX_COMMON_API Atomic_t
242 {
243  Atomic_t() : val(0) {}
244  Atomic_t(int i) : val(i) {}
245  volatile long val;
246 };
247 inline void AtomicInc(Atomic_t &v)
248 {
249  InterlockedIncrement(&v.val);
250 }
251 inline bool AtomicDecAndTest(Atomic_t &v)
252 {
253  return InterlockedDecrement(&v.val) == 0;
254 }
255 inline int AtomicGet(Atomic_t const &v)
256 {
257  return v.val;
258 }
259 inline void AtomicDec(Atomic_t &v)
260 {
261  InterlockedDecrement(&v.val);
262 }
263 
264 } // end namespace BLOCXX_NAMESPACE
265 
266 #elif defined(BLOCXX_HAVE_PTHREAD_SPIN_LOCK)
267 #include <pthread.h>
268 
269 #define BLOCXX_USE_PTHREAD_SPIN_LOCK_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp
270 
271 namespace BLOCXX_NAMESPACE
272 {
276 struct Atomic_t
277 {
282  Atomic_t();
283 
289  Atomic_t(int i);
290 
292  int val;
293 
294  pthread_spinlock_t spinlock;
295 };
296 
301 void AtomicInc(Atomic_t &v);
302 
308 bool AtomicDecAndTest(Atomic_t &v);
314 int AtomicGet(Atomic_t const &v);
315 
320 void AtomicDec(Atomic_t &v);
321 
322 } // end namespace BLOCXX_NAMESPACE
323 
324 #else
325 // use slow mutex protected versions
326 #define BLOCXX_USE_BLOCXX_DEFAULT_ATOMIC_OPS // used in BLOCXX_AtomicOps.cpp
327 
328 namespace BLOCXX_NAMESPACE
329 {
330 
331 struct Atomic_t
332 {
333  Atomic_t() : val(0) {}
334  Atomic_t(int i) : val(i) {}
335  volatile int val;
336 };
337 void AtomicInc(Atomic_t &v);
338 bool AtomicDecAndTest(Atomic_t &v);
339 int AtomicGet(Atomic_t const &v);
340 void AtomicDec(Atomic_t &v);
341 
342 } // end namespace BLOCXX_NAMESPACE
343 
344 #endif
345 #endif