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
38
39#ifndef BLOCXX_ATOMIC_OPS_HPP_
40#define BLOCXX_ATOMIC_OPS_HPP_
41#include "blocxx/BLOCXX_config.h"
42
43#if defined(BLOCXX_AIX)
44extern "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
63namespace BLOCXX_NAMESPACE
64{
65
66// use fast inline assembly versions
67struct Atomic_t
68{
69 Atomic_t() : val(0) {}
70 Atomic_t(int i) : val(i) {}
71 volatile int val;
72};
73inline void AtomicInc(Atomic_t &v)
74{
75 __asm__ __volatile__(
76 "lock ; " "incl %0"
77 :"=m" (v.val)
78 :"m" (v.val));
79}
80inline 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}
89inline int AtomicGet(Atomic_t const &v)
90{
91 return v.val;
92}
93inline 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)
103namespace BLOCXX_NAMESPACE
104{
105struct Atomic_t
106{
107 Atomic_t() : val(0) {}
108 Atomic_t(int i) : val(i) {}
109 volatile int val;
110};
111inline void AtomicInc(Atomic_t &v)
112{
113 _Asm_fetchadd(_FASZ_W, _SEM_ACQ, &v.val, 1, _LDHINT_NONE);
114}
115inline 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}
121inline int AtomicGet(Atomic_t const &v)
122{
123 return int(v.val);
124}
125inline 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)
132namespace 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>.
143struct Atomic_t
144{
145 Atomic_t() : val(0) {}
146 Atomic_t(int i) : val(i) {}
147 volatile int val;
148};
149
150inline void AtomicInc(Atomic_t &v)
151{
152 ::fetch_and_add(const_cast<atomic_p>(&v.val), 1);
153}
154inline 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}
162inline int AtomicGet(Atomic_t const &v)
163{
164 int c = ::fetch_and_add(const_cast<atomic_p>(&v.val), 0);
165 return c;
166}
167inline 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
176namespace BLOCXX_NAMESPACE
177{
178
179// use fast inline assembly versions
180struct Atomic_t
181{
182 Atomic_t() : val(0) {}
183 Atomic_t(int i) : val(i) {}
184 volatile int val;
185};
186
187inline 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}
199inline 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}
213inline int AtomicGet(Atomic_t const &v)
214{
215 return v.val;
216}
217inline 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
237namespace BLOCXX_NAMESPACE
238{
239
240// use fast inline assembly versions
241struct BLOCXX_COMMON_API Atomic_t
242{
243 Atomic_t() : val(0) {}
244 Atomic_t(int i) : val(i) {}
245 volatile long val;
246};
247inline void AtomicInc(Atomic_t &v)
248{
249 InterlockedIncrement(&v.val);
250}
251inline bool AtomicDecAndTest(Atomic_t &v)
252{
253 return InterlockedDecrement(&v.val) == 0;
254}
255inline int AtomicGet(Atomic_t const &v)
256{
257 return v.val;
258}
259inline 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
271namespace BLOCXX_NAMESPACE
272{
276struct Atomic_t
277{
282 Atomic_t();
283
289 Atomic_t(int i);
290
292 int val;
293
294 pthread_spinlock_t spinlock;
295};
296
301void AtomicInc(Atomic_t &v);
302
314int AtomicGet(Atomic_t const &v);
315
320void 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
328namespace BLOCXX_NAMESPACE
329{
330
332{
333 Atomic_t() : val(0) {}
334 Atomic_t(int i) : val(i) {}
335 volatile int val;
336};
337void AtomicInc(Atomic_t &v);
339int AtomicGet(Atomic_t const &v);
340void AtomicDec(Atomic_t &v);
341
342} // end namespace BLOCXX_NAMESPACE
343
344#endif
345#endif
Taken from RFC 1321.
bool AtomicDecAndTest(Atomic_t &v)
Definition AtomicOps.cpp:62
void AtomicInc(Atomic_t &v)
Definition AtomicOps.cpp:56
void AtomicDec(Atomic_t &v)
Definition AtomicOps.cpp:74
int AtomicGet(Atomic_t const &v)
Definition AtomicOps.cpp:70