Lunchbox  1.6.0
atomic.h
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