LCOV - code coverage report
Current view: top level - lunchbox - atomic.h (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 33 33 100.0 %
Date: 2014-10-01 Functions: 14 14 100.0 %

          Line data    Source code
       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             : 
      37             : /** Perform a full memory barrier. */
      38   251720363 : inline void memoryBarrier()
      39             : {
      40             : #ifdef LB_GCC_4_1_OR_LATER
      41   251720363 :     __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   251720363 : }
      52             : 
      53             : /** Perform a load-with-acquire memory barrier. */
      54   185324294 : inline void memoryBarrierAcquire()
      55             : {
      56             : #ifdef __xlC__
      57             :     __fence();
      58             :     __eieio();
      59             : #else
      60   185324294 :     memoryBarrier();
      61             : #endif
      62   220079979 : }
      63             : 
      64             : /** Perform a store-with-release memory barrier. */
      65             : inline void memoryBarrierRelease()
      66             : {
      67             : #ifdef __xlC__
      68             :     __isync();
      69             :     __fence();
      70             : #else
      71             :     memoryBarrier();
      72             : #endif
      73             : }
      74             : 
      75             : /**
      76             :  * A variable with atomic semantics and standalone atomic operations.
      77             :  *
      78             :  * Use the C++11 equivalent if you can.
      79             :  *
      80             :  * Atomic variables can be modified safely from multiple threads
      81             :  * concurrently. They are useful to implement lock-free algorithms.
      82             :  *
      83             :  * For implementation reasons, only signed atomic variables are supported, of
      84             :  * which int32_t and ssize_t are implemented and typedef'd as a_int32_t and
      85             :  * a_ssize_t.
      86             :  */
      87             : template< class T > class Atomic
      88             : {
      89             : public:
      90             :     /** @return the old value, then add the given increment. */
      91             :     LUNCHBOX_API static T getAndAdd( T& value, const T increment );
      92             : 
      93             :     /** @return the old value, then substract the increment. */
      94             :     LUNCHBOX_API static T getAndSub( T& value, const T increment );
      95             : 
      96             :     /** @return the new value after adding the given increment. */
      97             :     static T addAndGet( T& value, const T increment );
      98             : 
      99             :     /** @return the new value after substracting the increment. */
     100             :     static T subAndGet( T& value, const T increment );
     101             : 
     102             :     /** @return the new value after incrementing the value. */
     103             :     LUNCHBOX_API static T incAndGet( T& value );
     104             : 
     105             :     /** @return the new value after decrementing the value. */
     106             :     LUNCHBOX_API static T decAndGet( T& value );
     107             : 
     108             :     /** Perform a compare-and-swap atomic operation. */
     109             :     LUNCHBOX_API static bool compareAndSwap( T* value, const T expected,
     110             :                                              const T newValue );
     111             : 
     112             :     /** Construct a new atomic variable with an initial value. @version 1.0 */
     113             :     explicit Atomic( const T v = 0 );
     114             : 
     115             :     /** Construct a copy of an atomic variable. Not thread-safe! @version 1.0 */
     116             :     Atomic( const Atomic< T >& v );
     117             : 
     118             :     /** @return the current value @version 1.0 */
     119             :     operator T(void) const;
     120             : 
     121             :     /** Assign a new value @version 1.0 */
     122             :     void operator = ( const T v );
     123             : 
     124             :     /** Assign a new value. Not thread-safe! @version 1.0 */
     125             :     void operator = ( const Atomic< T >& v);
     126             : 
     127             :     /** Atomically add a value and return the new value. @version 1.0 */
     128             :     T operator +=(T v);
     129             : 
     130             :     /** Atomically substract a value and return the new value. @version 1.0 */
     131             :     T operator -=(T v);
     132             : 
     133             :     /** Atomically increment by one and return the new value. @version 1.0 */
     134             :     T operator ++(void);
     135             : 
     136             :     /** Atomically decrement by one and return the new value. @version 1.0 */
     137             :     T operator --(void);
     138             : 
     139             :     /** Atomically increment by one and return the old value. @version 1.0 */
     140             :     T operator ++(int);
     141             : 
     142             :     /** Atomically decrement by one and return the old value. @version 1.0 */
     143             :     T operator --(int);
     144             : 
     145             :     /** @return true if the variable has the given value. @version 1.1.2 */
     146             :     bool operator == ( const Atomic< T >& rhs ) const;
     147             : 
     148             :     /** @return true if the variable has not the given value. @version 1.1.2 */
     149             :     bool operator != ( const Atomic< T >& rhs ) const;
     150             : 
     151             :     /**
     152             :      * Perform a compare-and-swap atomic operation.
     153             :      *
     154             :      * Atomically replaces the value and return true if the value matched the
     155             :      * expected.
     156             :      * @return true if the new value was set, false otherwise
     157             :      * @version 1.1.2
     158             :      */
     159             :     bool compareAndSwap( const T expected, const T newValue );
     160             : 
     161             : private:
     162             :     // https://github.com/Eyescale/Lunchbox/issues/8
     163             : #if _MSC_VER < 1700
     164             :     mutable T _value;
     165             : #else
     166             :     LB_ALIGN8( mutable T _value );
     167             : #endif
     168             : };
     169             : 
     170             : // Implementation
     171             : #ifdef LB_GCC_4_1_OR_LATER
     172             : template< class T > T Atomic< T >::getAndAdd( T& value, const T increment )
     173             : {
     174             :     return __sync_fetch_and_add( &value, increment );
     175             : }
     176             : 
     177             : template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
     178             : {
     179             :     return __sync_fetch_and_sub( &value, increment );
     180             : }
     181             : 
     182    10495596 : template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
     183             : {
     184    10495596 :     return __sync_add_and_fetch( &value, increment );
     185             : }
     186             : 
     187    10669588 : template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
     188             : {
     189    10669588 :     return __sync_sub_and_fetch( &value, increment );
     190             : }
     191             : 
     192     7438008 : template< class T > T Atomic< T >::incAndGet( T& value )
     193             : {
     194     7438008 :     return addAndGet( value, 1 );
     195             : }
     196             : 
     197     7800294 : template< class T > T Atomic< T >::decAndGet( T& value )
     198             : {
     199     7800294 :     return subAndGet( value, 1 );
     200             : }
     201             : 
     202             : template< class T >
     203   203134326 : bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
     204             : {
     205   203134326 :     return __sync_bool_compare_and_swap( value, expected, newValue );
     206             : }
     207             : 
     208             : #elif defined (_MSC_VER)
     209             : 
     210             : // see also atomic.cpp
     211             : template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
     212             : {
     213             :     return getAndAdd( value, increment ) + increment;
     214             : }
     215             : 
     216             : template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
     217             : {
     218             :     return getAndSub( value, increment ) - increment;
     219             : }
     220             : 
     221             : #else
     222             : #  ifdef __xlC__
     223             : template< class T >
     224             : bool Atomic< T >::compareAndSwap( T* value, const T expected, const T newValue )
     225             : {
     226             :     return __compare_and_swap( value, const_cast< T* >( &expected ), newValue );
     227             : }
     228             : #    ifdef __64BIT__
     229             : template<> inline
     230             : bool Atomic< int64_t >::compareAndSwap( int64_t* value, const int64_t expected,
     231             :                                         const int64_t newValue )
     232             : {
     233             :     return __compare_and_swaplp( value, const_cast< int64_t* >( &expected ),
     234             :                                  newValue );
     235             : }
     236             : #    endif
     237             : #  else
     238             : #    error No compare-and-swap implementated for this platform
     239             : #  endif
     240             : 
     241             : template< class T > T Atomic< T >::getAndAdd( T& value, const T increment )
     242             : {
     243             :     for(;;)
     244             :     {
     245             :         memoryBarrierAcquire();
     246             :         const T oldv = value;
     247             :         const T newv = oldv + increment;
     248             :         if( !compareAndSwap( &value, oldv, newv ))
     249             :             continue;
     250             : 
     251             :         memoryBarrierRelease();
     252             :         return oldv;
     253             :     }
     254             : }
     255             : 
     256             : template< class T > T Atomic< T >::getAndSub( T& value, const T increment )
     257             : {
     258             :     for(;;)
     259             :     {
     260             :         memoryBarrierAcquire();
     261             :         const T oldv = value;
     262             :         const T newv = oldv - increment;
     263             :         if( !compareAndSwap( &value, oldv, newv ))
     264             :             continue;
     265             : 
     266             :         memoryBarrierRelease();
     267             :         return oldv;
     268             :     }
     269             : }
     270             : 
     271             : template< class T > T Atomic< T >::addAndGet( T& value, const T increment )
     272             : {
     273             :     for(;;)
     274             :     {
     275             :         memoryBarrierAcquire();
     276             :         const T oldv = value;
     277             :         const T newv = oldv + increment;
     278             :         if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
     279             :             continue;
     280             : 
     281             :         memoryBarrierRelease();
     282             :         return newv;
     283             :     }
     284             : }
     285             : 
     286             : template< class T > T Atomic< T >::subAndGet( T& value, const T increment )
     287             : {
     288             :     for(;;)
     289             :     {
     290             :         memoryBarrierAcquire();
     291             :         const T oldv = value;
     292             :         const T newv = oldv - increment;
     293             :         if( !Atomic< T >::compareAndSwap( &value, oldv, newv ))
     294             :             continue;
     295             : 
     296             :         memoryBarrierRelease();
     297             :         return newv;
     298             :     }
     299             : }
     300             : 
     301             : template< class T > T Atomic< T >::incAndGet( T& value )
     302             : {
     303             :     return addAndGet( value, 1 );
     304             : }
     305             : 
     306             : template< class T > T Atomic< T >::decAndGet( T& value )
     307             : {
     308             :     return subAndGet( value, 1 );
     309             : }
     310             : #endif
     311             : 
     312         500 : template< class T > Atomic< T >::Atomic ( const T v ) : _value(v) {}
     313             : 
     314             : template <class T>
     315             : Atomic< T >::Atomic( const Atomic< T >& v ) : _value( v._value ) {}
     316             : 
     317             : template <class T>
     318   188232817 : Atomic< T >::operator T(void) const
     319             : {
     320   188232817 :     memoryBarrierAcquire();
     321   200414578 :     return _value;
     322             : }
     323             : 
     324    39577824 : template< class T > void Atomic< T >::operator = ( const T v )
     325             : {
     326    39577824 :     _value = v;
     327    39577824 :     memoryBarrier();
     328    39577791 : }
     329             : 
     330             : template< class T > void Atomic< T >::operator = ( const Atomic< T >& v)
     331             : {
     332             :     _value = v._value;
     333             :     memoryBarrier();
     334             : }
     335             : 
     336             : template< class T >  T Atomic< T >::operator += (T v)
     337             : {
     338             :     return addAndGet( _value, v );
     339             : }
     340             : 
     341             : template< class T > T Atomic< T >::operator -=(T v)
     342             : {
     343             :     return subAndGet( _value, v );
     344             : }
     345             : 
     346     7262156 : template< class T > T Atomic< T >::operator ++(void)
     347             : {
     348     7262156 :     return incAndGet( _value );
     349             : }
     350             : 
     351     7640300 : template< class T > T Atomic< T >::operator --(void)
     352             : {
     353     7640300 :     return decAndGet( _value );
     354             : }
     355             : 
     356             : template< class T > T Atomic< T >::operator ++(int)
     357             : {
     358             :     return getAndAdd( _value, 1 );
     359             : }
     360             : 
     361             : template< class T > T Atomic< T >::operator --(int)
     362             : {
     363             :     return getAndSub( _value, 1 );
     364             : }
     365             : 
     366      773547 : template< class T > bool Atomic< T >::operator == ( const Atomic<T>& rhs ) const
     367             : {
     368      773547 :     memoryBarrier();
     369      773547 :     return _value == rhs._value;
     370             : }
     371             : 
     372             : template< class T > bool Atomic< T >::operator != ( const Atomic<T>& rhs ) const
     373             : {
     374             :     memoryBarrier();
     375             :     return _value != rhs._value;
     376             : }
     377             : 
     378             : template< class T >
     379   169352594 : bool Atomic< T >::compareAndSwap( const T expected, const T newValue )
     380             : {
     381   169352594 :     return compareAndSwap( &_value, expected, newValue );
     382             : }
     383             : 
     384             : }
     385             : #endif  // LUNCHBOX_ATOMIC_H

Generated by: LCOV version 1.10