LCOV - code coverage report
Current view: top level - lunchbox - atomic.h (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 35 35 100.0 %
Date: 2018-10-03 05:33:11 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 <intrin.h>
      26             : #include <math.h> // include math.h early to avoid warning later
      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             : /** Perform a full memory barrier. */
      37    19539855 : inline void memoryBarrier()
      38             : {
      39             : #ifdef __GNUC__
      40    19539855 :     __sync_synchronize();
      41             : #elif defined(_MSC_VER)
      42             :     _ReadWriteBarrier();
      43             : #elif defined(__xlC__)
      44             :     __fence();
      45             :     __eieio();
      46             :     __fence();
      47             : #else
      48             : #error "no memory barrier implemented for this platform"
      49             : #endif
      50    19539855 : }
      51             : 
      52             : /** Perform a load-with-acquire memory barrier. */
      53    17353658 : inline void memoryBarrierAcquire()
      54             : {
      55             : #ifdef __xlC__
      56             :     __fence();
      57             :     __eieio();
      58             : #else
      59    17353658 :     memoryBarrier();
      60             : #endif
      61    21562421 : }
      62             : 
      63             : /** Perform a store-with-release memory barrier. */
      64             : inline void memoryBarrierRelease()
      65             : {
      66             : #ifdef __xlC__
      67             :     __isync();
      68             :     __fence();
      69             : #else
      70             :     memoryBarrier();
      71             : #endif
      72             : }
      73             : 
      74             : /**
      75             :  * A variable with atomic semantics and standalone atomic operations.
      76             :  *
      77             :  * Use the C++11 equivalent if you can.
      78             :  *
      79             :  * Atomic variables can be modified safely from multiple threads
      80             :  * concurrently. They are useful to implement lock-free algorithms.
      81             :  *
      82             :  * For implementation reasons, only signed atomic variables are supported, of
      83             :  * which int32_t and ssize_t are implemented and typedef'd as a_int32_t and
      84             :  * a_ssize_t.
      85             :  */
      86             : template <class T>
      87             : 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 __GNUC__
     172             : template <class T>
     173             : T Atomic<T>::getAndAdd(T& value, const T increment)
     174             : {
     175             :     return __sync_fetch_and_add(&value, increment);
     176             : }
     177             : 
     178             : template <class T>
     179             : T Atomic<T>::getAndSub(T& value, const T increment)
     180             : {
     181             :     return __sync_fetch_and_sub(&value, increment);
     182             : }
     183             : 
     184             : template <class T>
     185    16036953 : T Atomic<T>::addAndGet(T& value, const T increment)
     186             : {
     187    16036953 :     return __sync_add_and_fetch(&value, increment);
     188             : }
     189             : 
     190             : template <class T>
     191    16100762 : T Atomic<T>::subAndGet(T& value, const T increment)
     192             : {
     193    16100762 :     return __sync_sub_and_fetch(&value, increment);
     194             : }
     195             : 
     196             : template <class T>
     197    13365361 : T Atomic<T>::incAndGet(T& value)
     198             : {
     199    13365361 :     return addAndGet(value, 1);
     200             : }
     201             : 
     202             : template <class T>
     203    15610211 : T Atomic<T>::decAndGet(T& value)
     204             : {
     205    15610211 :     return subAndGet(value, 1);
     206             : }
     207             : 
     208             : template <class T>
     209        8642 : bool Atomic<T>::compareAndSwap(T* value, const T expected, const T newValue)
     210             : {
     211        8642 :     return __sync_bool_compare_and_swap(value, expected, newValue);
     212             : }
     213             : 
     214             : #elif defined(_MSC_VER)
     215             : 
     216             : // see also atomic.cpp
     217             : template <class T>
     218             : T Atomic<T>::addAndGet(T& value, const T increment)
     219             : {
     220             :     return getAndAdd(value, increment) + increment;
     221             : }
     222             : 
     223             : template <class T>
     224             : T Atomic<T>::subAndGet(T& value, const T increment)
     225             : {
     226             :     return getAndSub(value, increment) - increment;
     227             : }
     228             : 
     229             : #else
     230             : #ifdef __xlC__
     231             : template <class T>
     232             : bool Atomic<T>::compareAndSwap(T* value, const T expected, const T newValue)
     233             : {
     234             :     return __compare_and_swap(value, const_cast<T*>(&expected), newValue);
     235             : }
     236             : #ifdef __64BIT__
     237             : template <>
     238             : inline bool Atomic<int64_t>::compareAndSwap(int64_t* value,
     239             :                                             const int64_t expected,
     240             :                                             const int64_t newValue)
     241             : {
     242             :     return __compare_and_swaplp(value, const_cast<int64_t*>(&expected),
     243             :                                 newValue);
     244             : }
     245             : #endif
     246             : #else
     247             : #error No compare-and-swap implementated for this platform
     248             : #endif
     249             : 
     250             : template <class T>
     251             : T Atomic<T>::getAndAdd(T& value, const T increment)
     252             : {
     253             :     for (;;)
     254             :     {
     255             :         memoryBarrierAcquire();
     256             :         const T oldv = value;
     257             :         const T newv = oldv + increment;
     258             :         if (!compareAndSwap(&value, oldv, newv))
     259             :             continue;
     260             : 
     261             :         memoryBarrierRelease();
     262             :         return oldv;
     263             :     }
     264             : }
     265             : 
     266             : template <class T>
     267             : T Atomic<T>::getAndSub(T& value, const T increment)
     268             : {
     269             :     for (;;)
     270             :     {
     271             :         memoryBarrierAcquire();
     272             :         const T oldv = value;
     273             :         const T newv = oldv - increment;
     274             :         if (!compareAndSwap(&value, oldv, newv))
     275             :             continue;
     276             : 
     277             :         memoryBarrierRelease();
     278             :         return oldv;
     279             :     }
     280             : }
     281             : 
     282             : template <class T>
     283             : T Atomic<T>::addAndGet(T& value, const T increment)
     284             : {
     285             :     for (;;)
     286             :     {
     287             :         memoryBarrierAcquire();
     288             :         const T oldv = value;
     289             :         const T newv = oldv + increment;
     290             :         if (!Atomic<T>::compareAndSwap(&value, oldv, newv))
     291             :             continue;
     292             : 
     293             :         memoryBarrierRelease();
     294             :         return newv;
     295             :     }
     296             : }
     297             : 
     298             : template <class T>
     299             : T Atomic<T>::subAndGet(T& value, const T increment)
     300             : {
     301             :     for (;;)
     302             :     {
     303             :         memoryBarrierAcquire();
     304             :         const T oldv = value;
     305             :         const T newv = oldv - increment;
     306             :         if (!Atomic<T>::compareAndSwap(&value, oldv, newv))
     307             :             continue;
     308             : 
     309             :         memoryBarrierRelease();
     310             :         return newv;
     311             :     }
     312             : }
     313             : 
     314             : template <class T>
     315             : T Atomic<T>::incAndGet(T& value)
     316             : {
     317             :     return addAndGet(value, 1);
     318             : }
     319             : 
     320             : template <class T>
     321             : T Atomic<T>::decAndGet(T& value)
     322             : {
     323             :     return subAndGet(value, 1);
     324             : }
     325             : #endif
     326             : 
     327             : template <class T>
     328     2000112 : Atomic<T>::Atomic(const T v)
     329     2000112 :     : _value(v)
     330             : {
     331     2000112 : }
     332             : 
     333             : template <class T>
     334             : Atomic<T>::Atomic(const Atomic<T>& v)
     335             :     : _value(v._value)
     336             : {
     337             : }
     338             : 
     339             : template <class T>
     340    17746772 : Atomic<T>::operator T(void) const
     341             : {
     342    17746772 :     memoryBarrierAcquire();
     343    19827055 :     return _value;
     344             : }
     345             : 
     346             : template <class T>
     347      556303 : void Atomic<T>::operator=(const T v)
     348             : {
     349      556303 :     _value = v;
     350      556303 :     memoryBarrier();
     351      556347 : }
     352             : 
     353             : template <class T>
     354             : void Atomic<T>::operator=(const Atomic<T>& v)
     355             : {
     356             :     _value = v._value;
     357             :     memoryBarrier();
     358             : }
     359             : 
     360             : template <class T>
     361             : T Atomic<T>::operator+=(T v)
     362             : {
     363             :     return addAndGet(_value, v);
     364             : }
     365             : 
     366             : template <class T>
     367             : T Atomic<T>::operator-=(T v)
     368             : {
     369             :     return subAndGet(_value, v);
     370             : }
     371             : 
     372             : template <class T>
     373    13592321 : T Atomic<T>::operator++(void)
     374             : {
     375    13592321 :     return incAndGet(_value);
     376             : }
     377             : 
     378             : template <class T>
     379    15762243 : T Atomic<T>::operator--(void)
     380             : {
     381    15762243 :     return decAndGet(_value);
     382             : }
     383             : 
     384             : template <class T>
     385             : T Atomic<T>::operator++(int)
     386             : {
     387             :     return getAndAdd(_value, 1);
     388             : }
     389             : 
     390             : template <class T>
     391             : T Atomic<T>::operator--(int)
     392             : {
     393             :     return getAndSub(_value, 1);
     394             : }
     395             : 
     396             : template <class T>
     397      547262 : bool Atomic<T>::operator==(const Atomic<T>& rhs) const
     398             : {
     399      547262 :     memoryBarrier();
     400      547262 :     return _value == rhs._value;
     401             : }
     402             : 
     403             : template <class T>
     404             : bool Atomic<T>::operator!=(const Atomic<T>& rhs) const
     405             : {
     406             :     memoryBarrier();
     407             :     return _value != rhs._value;
     408             : }
     409             : 
     410             : template <class T>
     411        8599 : bool Atomic<T>::compareAndSwap(const T expected, const T newValue)
     412             : {
     413        8599 :     return compareAndSwap(&_value, expected, newValue);
     414             : }
     415             : }
     416             : #endif // LUNCHBOX_ATOMIC_H

Generated by: LCOV version 1.11