Lunchbox
1.4.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 #endif 00030 00031 namespace lunchbox 00032 { 00033 00035 inline void memoryBarrier() 00036 { 00037 #ifdef LB_GCC_4_1_OR_LATER 00038 __sync_synchronize(); 00039 #elif defined(_MSC_VER) 00040 _ReadWriteBarrier(); 00041 #else 00042 # error "no memory barrier implemented for this platform" 00043 #endif 00044 } 00045 00055 template< class T > class Atomic 00056 { 00057 public: 00059 LUNCHBOX_API static T getAndAdd( T& value, const T increment ); 00060 00062 LUNCHBOX_API static T getAndSub( T& value, const T increment ); 00063 00065 static T addAndGet( T& value, const T increment ); 00066 00068 static T subAndGet( T& value, const T increment ); 00069 00071 LUNCHBOX_API static T incAndGet( T& value ); 00072 00074 LUNCHBOX_API static T decAndGet( T& value ); 00075 00077 LUNCHBOX_API static bool compareAndSwap( T* value, const T expected, 00078 const T newValue ); 00079 00081 explicit Atomic( const T v = 0 ); 00082 00084 Atomic( const Atomic< T >& v ); 00085 00087 operator T(void) const; 00088 00090 void operator = ( const T v ); 00091 00093 void operator = ( const Atomic< T >& v); 00094 00096 T operator +=(T v); 00097 00099 T operator -=(T v); 00100 00102 T operator ++(void); 00103 00105 T operator --(void); 00106 00108 T operator ++(int); 00109 00111 T operator --(int); 00112 00114 bool operator == ( const Atomic< T >& rhs ) const; 00115 00117 bool operator != ( const Atomic< T >& rhs ) const; 00118 00127 bool compareAndSwap( const T expected, const T newValue ); 00128 00129 private: 00130 mutable T _value; 00131 }; 00132 00133 // Implementation 00134 #ifdef LB_GCC_4_1_OR_LATER 00135 template< class T > T Atomic< T >::getAndAdd( T& value, const T increment ) 00136 { 00137 return __sync_fetch_and_add( &value, increment ); 00138 } 00139 00140 template< class T > T Atomic< T >::getAndSub( T& value, const T increment ) 00141 { 00142 return __sync_fetch_and_sub( &value, increment ); 00143 } 00144 00145 template< class T > T Atomic< T >::addAndGet( T& value, const T increment ) 00146 { 00147 return __sync_add_and_fetch( &value, increment ); 00148 } 00149 00150 template< class T > T Atomic< T >::subAndGet( T& value, const T increment ) 00151 { 00152 return __sync_sub_and_fetch( &value, increment ); 00153 } 00154 00155 template< class T > T Atomic< T >::incAndGet( T& value ) 00156 { 00157 return addAndGet( value, 1 ); 00158 } 00159 00160 template< class T > T Atomic< T >::decAndGet( T& value ) 00161 { 00162 return subAndGet( value, 1 ); 00163 } 00164 00165 template< class T > 00166 bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue ) 00167 { 00168 return __sync_bool_compare_and_swap( value, expected, newValue ); 00169 } 00170 00171 #elif defined (_MSC_VER) 00172 00173 // see also atomic.cpp 00174 template< class T > T Atomic< T >::addAndGet( T& value, const T increment ) 00175 { 00176 return getAndAdd( value, increment ) + increment; 00177 } 00178 00179 template< class T > T Atomic< T >::subAndGet( T& value, const T increment ) 00180 { 00181 return getAndSub( value, increment ) - increment; 00182 } 00183 00184 #else 00185 # error No Atomic Support - consider compareAndSwap-based implementation? 00186 #endif 00187 00188 template< class T > Atomic< T >::Atomic ( const T v ) : _value(v) {} 00189 00190 template <class T> 00191 Atomic< T >::Atomic( const Atomic< T >& v ) : _value( v._value ) {} 00192 00193 template <class T> 00194 Atomic< T >::operator T(void) const 00195 { 00196 return getAndAdd( _value, 0 ); 00197 } 00198 00199 template< class T > void Atomic< T >::operator = ( const T v ) 00200 { 00201 _value = v; 00202 memoryBarrier(); 00203 } 00204 00205 template< class T > void Atomic< T >::operator = ( const Atomic< T >& v) 00206 { 00207 _value = v._value; 00208 memoryBarrier(); 00209 } 00210 00211 template< class T > T Atomic< T >::operator += (T v) 00212 { 00213 return addAndGet( _value, v ); 00214 } 00215 00216 template< class T > T Atomic< T >::operator -=(T v) 00217 { 00218 return subAndGet( _value, v ); 00219 } 00220 00221 template< class T > T Atomic< T >::operator ++(void) 00222 { 00223 return incAndGet( _value ); 00224 } 00225 00226 template< class T > T Atomic< T >::operator --(void) 00227 { 00228 return decAndGet( _value ); 00229 } 00230 00231 template< class T > T Atomic< T >::operator ++(int) 00232 { 00233 return getAndAdd( _value, 1 ); 00234 } 00235 00236 template< class T > T Atomic< T >::operator --(int) 00237 { 00238 return getAndSub( _value, 1 ); 00239 } 00240 00241 template< class T > bool Atomic< T >::operator == ( const Atomic<T>& rhs ) const 00242 { 00243 memoryBarrier(); 00244 return _value == rhs._value; 00245 } 00246 00247 template< class T > bool Atomic< T >::operator != ( const Atomic<T>& rhs ) const 00248 { 00249 memoryBarrier(); 00250 return _value != rhs._value; 00251 } 00252 00253 template< class T > 00254 bool Atomic< T >::compareAndSwap( const T expected, const T newValue ) 00255 { 00256 return compareAndSwap( &_value, expected, newValue ); 00257 } 00258 00259 } 00260 #endif // LUNCHBOX_ATOMIC_H