Lunchbox  1.8.0
atomic.h
1 
2 // Copyright (C) 2007, 2008 Tim Blechmann & Thomas Grill
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
8 // Disclaimer: Not a Boost library.
9 
10 /* Copyright (c) 2008-2012, Stefan Eilemann <eile@equalizergraphics.com>
11  Modifications to use within lunchbox namespace and naming conventions.
12  Original at http://tim.klingt.org/git?p=boost_lockfree.git;a=tree
13 */
14 
15 #ifndef LUNCHBOX_ATOMIC_H
16 #define LUNCHBOX_ATOMIC_H
17 
18 #include <lunchbox/api.h>
19 #include <lunchbox/compiler.h> // GCC version
20 #include <lunchbox/types.h>
21 
22 #ifdef _MSC_VER
23 # pragma warning (push)
24 # pragma warning (disable: 4985) // inconsistent decl of ceil
25 # include <math.h> // include math.h early to avoid warning later
26 # include <intrin.h>
27 # pragma warning (pop)
28 # pragma intrinsic(_ReadWriteBarrier)
29 #elif defined(__xlC__)
30 # include <builtins.h>
31 # include <iostream>
32 #endif
33 
34 namespace lunchbox
35 {
36 
38 inline void memoryBarrier()
39 {
40 #ifdef LB_GCC_4_1_OR_LATER
41  __sync_synchronize();
42 #elif defined(_MSC_VER)
43  _ReadWriteBarrier();
44 #elif defined(__xlC__)
45  __fence();
46  __eieio();
47  __fence();
48 #else
49 # error "no memory barrier implemented for this platform"
50 #endif
51 }
52 
54 inline void memoryBarrierAcquire()
55 {
56 #ifdef __xlC__
57  __fence();
58  __eieio();
59 #else
60  memoryBarrier();
61 #endif
62 }
63 
65 inline void memoryBarrierRelease()
66 {
67 #ifdef __xlC__
68  __isync();
69  __fence();
70 #else
71  memoryBarrier();
72 #endif
73 }
74 
84 template< class T > class Atomic
85 {
86 public:
88  LUNCHBOX_API static T getAndAdd( T& value, const T increment );
89 
91  LUNCHBOX_API static T getAndSub( T& value, const T increment );
92 
94  static T addAndGet( T& value, const T increment );
95 
97  static T subAndGet( T& value, const T increment );
98 
100  LUNCHBOX_API static T incAndGet( T& value );
101 
103  LUNCHBOX_API static T decAndGet( T& value );
104 
106  LUNCHBOX_API static bool compareAndSwap( T* value, const T expected,
107  const T newValue );
108 
110  explicit Atomic( const T v = 0 );
111 
113  Atomic( const Atomic< T >& v );
114 
116  operator T(void) const;
117 
119  void operator = ( const T v );
120 
122  void operator = ( const Atomic< T >& v);
123 
125  T operator +=(T v);
126 
128  T operator -=(T v);
129 
131  T operator ++(void);
132 
134  T operator --(void);
135 
137  T operator ++(int);
138 
140  T operator --(int);
141 
143  bool operator == ( const Atomic< T >& rhs ) const;
144 
146  bool operator != ( const Atomic< T >& rhs ) const;
147 
156  bool compareAndSwap( const T expected, const T newValue );
157 
158 private:
159  // https://github.com/Eyescale/Lunchbox/issues/8
160 #if _MSC_VER < 1700
161  mutable T _value;
162 #else
163  LB_ALIGN8( mutable T _value );
164 #endif
165 };
166 
167 // Implementation
168 #ifdef LB_GCC_4_1_OR_LATER
169 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment )
170 {
171  return __sync_fetch_and_add( &value, increment );
172 }
173 
174 template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
175 {
176  return __sync_fetch_and_sub( &value, increment );
177 }
178 
179 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
180 {
181  return __sync_add_and_fetch( &value, increment );
182 }
183 
184 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
185 {
186  return __sync_sub_and_fetch( &value, increment );
187 }
188 
189 template< class T > T Atomic< T >::incAndGet( T& value )
190 {
191  return addAndGet( value, 1 );
192 }
193 
194 template< class T > T Atomic< T >::decAndGet( T& value )
195 {
196  return subAndGet( value, 1 );
197 }
198 
199 template< class T >
200 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
201 {
202  return __sync_bool_compare_and_swap( value, expected, newValue );
203 }
204 
205 #elif defined (_MSC_VER)
206 
207 // see also atomic.cpp
208 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
209 {
210  return getAndAdd( value, increment ) + increment;
211 }
212 
213 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
214 {
215  return getAndSub( value, increment ) - increment;
216 }
217 
218 #else
219 # ifdef __xlC__
220 template< class T >
221 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
222 {
223  return __compare_and_swap( value, const_cast< T* >( &expected ), newValue );
224 }
225 # ifdef __64BIT__
226 template<> inline
227 bool Atomic< int64_t >::compareAndSwap( int64_t* value, const int64_t expected,
228  const int64_t newValue )
229 {
230  return __compare_and_swaplp( value, const_cast< int64_t* >( &expected ),
231  newValue );
232 }
233 # endif
234 # else
235 # error No compare-and-swap implementated for this platform
236 # endif
237 
238 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment )
239 {
240  for(;;)
241  {
243  const T oldv = value;
244  const T newv = oldv + increment;
245  if( !compareAndSwap( &value, oldv, newv ))
246  continue;
247 
249  return oldv;
250  }
251 }
252 
253 template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
254 {
255  for(;;)
256  {
258  const T oldv = value;
259  const T newv = oldv - increment;
260  if( !compareAndSwap( &value, oldv, newv ))
261  continue;
262 
264  return oldv;
265  }
266 }
267 
268 template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
269 {
270  for(;;)
271  {
273  const T oldv = value;
274  const T newv = oldv + increment;
275  if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
276  continue;
277 
279  return newv;
280  }
281 }
282 
283 template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
284 {
285  for(;;)
286  {
288  const T oldv = value;
289  const T newv = oldv - increment;
290  if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
291  continue;
292 
294  return newv;
295  }
296 }
297 
298 template< class T > T Atomic< T >::incAndGet( T& value )
299 {
300  return addAndGet( value, 1 );
301 }
302 
303 template< class T > T Atomic< T >::decAndGet( T& value )
304 {
305  return subAndGet( value, 1 );
306 }
307 #endif
308 
309 template< class T > Atomic< T >::Atomic ( const T v ) : _value(v) {}
310 
311 template <class T>
312 Atomic< T >::Atomic( const Atomic< T >& v ) : _value( v._value ) {}
313 
314 template <class T>
316 {
318  return _value;
319 }
320 
321 template< class T > void Atomic< T >::operator = ( const T v )
322 {
323  _value = v;
324  memoryBarrier();
325 }
326 
327 template< class T > void Atomic< T >::operator = ( const Atomic< T >& v)
328 {
329  _value = v._value;
330  memoryBarrier();
331 }
332 
333 template< class T > T Atomic< T >::operator += (T v)
334 {
335  return addAndGet( _value, v );
336 }
337 
338 template< class T > T Atomic< T >::operator -=(T v)
339 {
340  return subAndGet( _value, v );
341 }
342 
343 template< class T > T Atomic< T >::operator ++(void)
344 {
345  return incAndGet( _value );
346 }
347 
348 template< class T > T Atomic< T >::operator --(void)
349 {
350  return decAndGet( _value );
351 }
352 
353 template< class T > T Atomic< T >::operator ++(int)
354 {
355  return getAndAdd( _value, 1 );
356 }
357 
358 template< class T > T Atomic< T >::operator --(int)
359 {
360  return getAndSub( _value, 1 );
361 }
362 
363 template< class T > bool Atomic< T >::operator == ( const Atomic<T>& rhs ) const
364 {
365  memoryBarrier();
366  return _value == rhs._value;
367 }
368 
369 template< class T > bool Atomic< T >::operator != ( const Atomic<T>& rhs ) const
370 {
371  memoryBarrier();
372  return _value != rhs._value;
373 }
374 
375 template< class T >
376 bool Atomic< T >::compareAndSwap( const T expected, const T newValue )
377 {
378  return compareAndSwap( &_value, expected, newValue );
379 }
380 
381 }
382 #endif // LUNCHBOX_ATOMIC_H