Lunchbox
1.6.0
|
00001 00002 // Copyright (C) 2007, 2008 Tim Blechmann & Thomas Grill 00003 // 00004 // Distributed under the Boost Software License, Version 1.0. (See 00005 // accompanying file LICENSE_1_0.txt or copy at 00006 // http://www.boost.org/LICENSE_1_0.txt) 00007 00008 // Disclaimer: Not a Boost library. 00009 00010 /* Copyright (c) 2008-2012, Stefan Eilemann <eile@equalizergraphics.com> 00011 Modifications to use within lunchbox namespace and naming conventions. 00012 Original at http://tim.klingt.org/git?p=boost_lockfree.git;a=tree 00013 */ 00014 00015 #ifndef LUNCHBOX_ATOMIC_H 00016 #define LUNCHBOX_ATOMIC_H 00017 00018 #include <lunchbox/api.h> 00019 #include <lunchbox/compiler.h> // GCC version 00020 #include <lunchbox/types.h> 00021 00022 #ifdef _MSC_VER 00023 # pragma warning (push) 00024 # pragma warning (disable: 4985) // inconsistent decl of ceil 00025 # include <math.h> // include math.h early to avoid warning later 00026 # include <intrin.h> 00027 # pragma warning (pop) 00028 # pragma intrinsic(_ReadWriteBarrier) 00029 #elif defined(__xlC__) 00030 # include <builtins.h> 00031 # include <iostream> 00032 #endif 00033 00034 namespace lunchbox 00035 { 00036 00038 inline void memoryBarrier() 00039 { 00040 #ifdef LB_GCC_4_1_OR_LATER 00041 __sync_synchronize(); 00042 #elif defined(_MSC_VER) 00043 _ReadWriteBarrier(); 00044 #elif defined(__xlC__) 00045 __fence(); 00046 __eieio(); 00047 __fence(); 00048 #else 00049 # error "no memory barrier implemented for this platform" 00050 #endif 00051 } 00052 00054 inline void memoryBarrierAcquire() 00055 { 00056 #ifdef __xlC__ 00057 __fence(); 00058 __eieio(); 00059 #else 00060 memoryBarrier(); 00061 #endif 00062 } 00063 00065 inline void memoryBarrierRelease() 00066 { 00067 #ifdef __xlC__ 00068 __isync(); 00069 __fence(); 00070 #else 00071 memoryBarrier(); 00072 #endif 00073 } 00074 00084 template< class T > class Atomic 00085 { 00086 public: 00088 LUNCHBOX_API static T getAndAdd( T& value, const T increment ); 00089 00091 LUNCHBOX_API static T getAndSub( T& value, const T increment ); 00092 00094 static T addAndGet( T& value, const T increment ); 00095 00097 static T subAndGet( T& value, const T increment ); 00098 00100 LUNCHBOX_API static T incAndGet( T& value ); 00101 00103 LUNCHBOX_API static T decAndGet( T& value ); 00104 00106 LUNCHBOX_API static bool compareAndSwap( T* value, const T expected, 00107 const T newValue ); 00108 00110 explicit Atomic( const T v = 0 ); 00111 00113 Atomic( const Atomic< T >& v ); 00114 00116 operator T(void) const; 00117 00119 void operator = ( const T v ); 00120 00122 void operator = ( const Atomic< T >& v); 00123 00125 T operator +=(T v); 00126 00128 T operator -=(T v); 00129 00131 T operator ++(void); 00132 00134 T operator --(void); 00135 00137 T operator ++(int); 00138 00140 T operator --(int); 00141 00143 bool operator == ( const Atomic< T >& rhs ) const; 00144 00146 bool operator != ( const Atomic< T >& rhs ) const; 00147 00156 bool compareAndSwap( const T expected, const T newValue ); 00157 00158 private: 00159 // https://github.com/Eyescale/Lunchbox/issues/8 00160 #if _MSC_VER < 1700 00161 mutable T _value; 00162 #else 00163 LB_ALIGN8( mutable T _value ); 00164 #endif 00165 }; 00166 00167 // Implementation 00168 #ifdef LB_GCC_4_1_OR_LATER 00169 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment ) 00170 { 00171 return __sync_fetch_and_add( &value, increment ); 00172 } 00173 00174 template< class T > T Atomic< T >::getAndSub( T& value, const T increment ) 00175 { 00176 return __sync_fetch_and_sub( &value, increment ); 00177 } 00178 00179 template< class T > T Atomic< T >::addAndGet( T& value, const T increment ) 00180 { 00181 return __sync_add_and_fetch( &value, increment ); 00182 } 00183 00184 template< class T > T Atomic< T >::subAndGet( T& value, const T increment ) 00185 { 00186 return __sync_sub_and_fetch( &value, increment ); 00187 } 00188 00189 template< class T > T Atomic< T >::incAndGet( T& value ) 00190 { 00191 return addAndGet( value, 1 ); 00192 } 00193 00194 template< class T > T Atomic< T >::decAndGet( T& value ) 00195 { 00196 return subAndGet( value, 1 ); 00197 } 00198 00199 template< class T > 00200 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue ) 00201 { 00202 return __sync_bool_compare_and_swap( value, expected, newValue ); 00203 } 00204 00205 #elif defined (_MSC_VER) 00206 00207 // see also atomic.cpp 00208 template< class T > T Atomic< T >::addAndGet( T& value, const T increment ) 00209 { 00210 return getAndAdd( value, increment ) + increment; 00211 } 00212 00213 template< class T > T Atomic< T >::subAndGet( T& value, const T increment ) 00214 { 00215 return getAndSub( value, increment ) - increment; 00216 } 00217 00218 #else 00219 # ifdef __xlC__ 00220 template< class T > 00221 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue ) 00222 { 00223 return __compare_and_swap( value, const_cast< T* >( &expected ), newValue ); 00224 } 00225 # ifdef __64BIT__ 00226 template<> inline 00227 bool Atomic< int64_t >::compareAndSwap( int64_t* value, const int64_t expected, 00228 const int64_t newValue ) 00229 { 00230 return __compare_and_swaplp( value, const_cast< int64_t* >( &expected ), 00231 newValue ); 00232 } 00233 # endif 00234 # else 00235 # error No compare-and-swap implementated for this platform 00236 # endif 00237 00238 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment ) 00239 { 00240 for(;;) 00241 { 00242 memoryBarrierAcquire(); 00243 const T oldv = value; 00244 const T newv = oldv + increment; 00245 if( !compareAndSwap( &value, oldv, newv )) 00246 continue; 00247 00248 memoryBarrierRelease(); 00249 return oldv; 00250 } 00251 } 00252 00253 template< class T > T Atomic< T >::getAndSub( T& value, const T increment ) 00254 { 00255 for(;;) 00256 { 00257 memoryBarrierAcquire(); 00258 const T oldv = value; 00259 const T newv = oldv - increment; 00260 if( !compareAndSwap( &value, oldv, newv )) 00261 continue; 00262 00263 memoryBarrierRelease(); 00264 return oldv; 00265 } 00266 } 00267 00268 template< class T > T Atomic< T >::addAndGet( T& value, const T increment ) 00269 { 00270 for(;;) 00271 { 00272 memoryBarrierAcquire(); 00273 const T oldv = value; 00274 const T newv = oldv + increment; 00275 if( !Atomic< T >::compareAndSwap( &value, oldv, newv )) 00276 continue; 00277 00278 memoryBarrierRelease(); 00279 return newv; 00280 } 00281 } 00282 00283 template< class T > T Atomic< T >::subAndGet( T& value, const T increment ) 00284 { 00285 for(;;) 00286 { 00287 memoryBarrierAcquire(); 00288 const T oldv = value; 00289 const T newv = oldv - increment; 00290 if( !Atomic< T >::compareAndSwap( &value, oldv, newv )) 00291 continue; 00292 00293 memoryBarrierRelease(); 00294 return newv; 00295 } 00296 } 00297 00298 template< class T > T Atomic< T >::incAndGet( T& value ) 00299 { 00300 return addAndGet( value, 1 ); 00301 } 00302 00303 template< class T > T Atomic< T >::decAndGet( T& value ) 00304 { 00305 return subAndGet( value, 1 ); 00306 } 00307 #endif 00308 00309 template< class T > Atomic< T >::Atomic ( const T v ) : _value(v) {} 00310 00311 template <class T> 00312 Atomic< T >::Atomic( const Atomic< T >& v ) : _value( v._value ) {} 00313 00314 template <class T> 00315 Atomic< T >::operator T(void) const 00316 { 00317 memoryBarrierAcquire(); 00318 return _value; 00319 } 00320 00321 template< class T > void Atomic< T >::operator = ( const T v ) 00322 { 00323 _value = v; 00324 memoryBarrier(); 00325 } 00326 00327 template< class T > void Atomic< T >::operator = ( const Atomic< T >& v) 00328 { 00329 _value = v._value; 00330 memoryBarrier(); 00331 } 00332 00333 template< class T > T Atomic< T >::operator += (T v) 00334 { 00335 return addAndGet( _value, v ); 00336 } 00337 00338 template< class T > T Atomic< T >::operator -=(T v) 00339 { 00340 return subAndGet( _value, v ); 00341 } 00342 00343 template< class T > T Atomic< T >::operator ++(void) 00344 { 00345 return incAndGet( _value ); 00346 } 00347 00348 template< class T > T Atomic< T >::operator --(void) 00349 { 00350 return decAndGet( _value ); 00351 } 00352 00353 template< class T > T Atomic< T >::operator ++(int) 00354 { 00355 return getAndAdd( _value, 1 ); 00356 } 00357 00358 template< class T > T Atomic< T >::operator --(int) 00359 { 00360 return getAndSub( _value, 1 ); 00361 } 00362 00363 template< class T > bool Atomic< T >::operator == ( const Atomic<T>& rhs ) const 00364 { 00365 memoryBarrier(); 00366 return _value == rhs._value; 00367 } 00368 00369 template< class T > bool Atomic< T >::operator != ( const Atomic<T>& rhs ) const 00370 { 00371 memoryBarrier(); 00372 return _value != rhs._value; 00373 } 00374 00375 template< class T > 00376 bool Atomic< T >::compareAndSwap( const T expected, const T newValue ) 00377 { 00378 return compareAndSwap( &_value, expected, newValue ); 00379 } 00380 00381 } 00382 #endif // LUNCHBOX_ATOMIC_H