Lunchbox  1.4.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 #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