LCOV - code coverage report
Current view: top level - lunchbox - monitor.h (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 83 86 96.5 %
Date: 2016-11-11 05:21:33 Functions: 51 52 98.1 %

          Line data    Source code
       1             : /* Copyright (c) 2006-2013, Stefan Eilemann <eile@equalizergraphics.com>
       2             :  *                    2011, Cedric Stalder <cedric.stalder@gmail.com>
       3             :  *               2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #ifndef LUNCHBOX_MONITOR_H
      20             : #define LUNCHBOX_MONITOR_H
      21             : 
      22             : #include <lunchbox/condition.h>   // member
      23             : #include <lunchbox/scopedMutex.h> // used inline
      24             : #include <lunchbox/types.h>
      25             : 
      26             : #include <errno.h>
      27             : #include <string.h>
      28             : #include <iostream>
      29             : #include <typeinfo>
      30             : #include <functional>
      31             : #include <boost/bind.hpp>
      32             : 
      33             : namespace lunchbox
      34             : {
      35             : /**
      36             :  * A monitor primitive.
      37             :  *
      38             :  * A monitor has a value, which can be monitored to reach a certain state. The
      39             :  * caller is blocked until the condition is fulfilled. The concept is similar to
      40             :  * a pthread condition, with more usage convenience.
      41             :  *
      42             :  * Example: @include tests/monitor.cpp
      43             :  */
      44             : template< class T > class Monitor
      45             : {
      46             :     typedef void (Monitor< T >::*bool_t)() const;
      47           0 :     void bool_true() const {}
      48             : 
      49             : public:
      50             :     /** Construct a new monitor with a default value of 0. @version 1.0 */
      51           2 :     Monitor() : _value( T( 0 )) {}
      52             : 
      53             :     /** Construct a new monitor with a given default value. @version 1.0 */
      54        1642 :     explicit Monitor( const T& value ) : _value( value ) {}
      55             : 
      56             :     /** Ctor initializing with the given monitor value. @version 1.1.5 */
      57             :     Monitor( const Monitor< T >& from ) : _value( from._value ) {}
      58             : 
      59             :     /** Destructs the monitor. @version 1.0 */
      60        1645 :     ~Monitor() {}
      61             : 
      62             :     /** @name Changing the monitored value. */
      63             :     //@{
      64             :     /** Increment the monitored value, prefix only. @version 1.0 */
      65     2002000 :     Monitor& operator++ ()
      66             :     {
      67     4004000 :         ScopedCondition mutex( _cond );
      68     2002000 :         ++_value;
      69     2002000 :         _cond.broadcast();
      70     4004000 :         return *this;
      71             :     }
      72             : 
      73             :     /** Decrement the monitored value, prefix only. @version 1.0 */
      74     2002000 :     Monitor& operator-- ()
      75             :     {
      76     4004000 :         ScopedCondition mutex( _cond );
      77     2002000 :         --_value;
      78     2002000 :         _cond.broadcast();
      79     4004000 :         return *this;
      80             :     }
      81             : 
      82             :     /** Assign a new value. @version 1.0 */
      83      830631 :     Monitor& operator = ( const T& value )
      84      830631 :         { set( value ); return *this; }
      85             : 
      86             :     /** Assign a new value. @version 1.1.5 */
      87             :     const Monitor& operator = ( const Monitor< T >& from )
      88             :         { set( from._value ); return *this; }
      89             : 
      90             :     /** Perform an or operation on the value. @version 1.0 */
      91             :     Monitor& operator |= ( const T& value )
      92             :     {
      93             :         ScopedCondition mutex( _cond );
      94             :         _value |= value;
      95             :         _cond.broadcast();
      96             :         return *this;
      97             :     }
      98             : 
      99             :     /** Perform an and operation on the value. @version 1.7 */
     100             :     Monitor& operator &= ( const T& value )
     101             :     {
     102             :         ScopedCondition mutex( _cond );
     103             :         _value &= value;
     104             :         _cond.broadcast();
     105             :         return *this;
     106             :     }
     107             : 
     108             :     /** Set a new value. @return the old value @version 1.0 */
     109      830632 :     T set( const T& value )
     110             :     {
     111     1661268 :         ScopedCondition mutex( _cond );
     112      830636 :         const T old = _value;
     113      830636 :         _value = value;
     114      830636 :         _cond.broadcast();
     115     1661272 :         return old;
     116             :     }
     117             :     //@}
     118             : 
     119             :     /** @name Monitor the value. */
     120             :     //@{
     121             :     /**
     122             :      * Block until the monitor has the given value.
     123             :      * @return the value when reaching the condition.
     124             :      * @version 1.0
     125             :      */
     126      400000 :     const T waitEQ( const T& value ) const
     127             :     {
     128      400000 :         return _waitPredicate( boost::bind( std::equal_to<T>(), value, _1 ));
     129             :     }
     130             : 
     131             :     /**
     132             :      * Block until the monitor has not the given value.
     133             :      * @return the value when reaching the condition.
     134             :      * @version 1.0
     135             :      */
     136       11306 :     const T waitNE( const T& value ) const
     137             :     {
     138       11306 :         return _waitPredicate( boost::bind( std::not_equal_to<T>(), value, _1));
     139             :     }
     140             : 
     141             :     /**
     142             :      * Block until the monitor has none of the given values.
     143             :      * @return the value when reaching the condition.
     144             :      * @version 1.0
     145             :      */
     146             :     const T waitNE( const T& v1, const T& v2 ) const
     147             :     {
     148             :         if( sizeof( T ) <= 8 ) // issue #1
     149             :         {
     150             :             const T current = _value;
     151             :             if( current != v1 && current != v2 )
     152             :                 return current;
     153             :         }
     154             :         ScopedCondition mutex( _cond );
     155             :         while( _value == v1 || _value == v2 )
     156             :             _cond.wait();
     157             :         return _value;
     158             :     }
     159             : 
     160             :     /**
     161             :      * Block until the monitor has a value greater or equal to the given value.
     162             :      * @return the value when reaching the condition.
     163             :      * @version 1.0
     164             :      */
     165        1000 :     const T waitGE( const T& value ) const
     166             :     {
     167        2000 :         return _waitPredicate( boost::bind( std::greater_equal<T>(), _1,
     168        2000 :                                             value ));
     169             :     }
     170             : 
     171             :     /**
     172             :      * Block until the monitor has a value less or equal to the given value.
     173             :      * @return the value when reaching the condition.
     174             :      * @version 1.0
     175             :      */
     176       64819 :     const T waitLE( const T& value ) const
     177       64819 :      { return _waitPredicate( boost::bind( std::less_equal<T>(), _1, value )); }
     178             : 
     179             :     /**
     180             :      * Block until the monitor has a value greater than the given value.
     181             :      * @return the value when reaching the condition.
     182             :      * @version 1.10
     183             :      */
     184        1000 :     const T waitGT( const T& value ) const
     185        1000 :         { return _waitPredicate( boost::bind( std::greater<T>(), _1, value )); }
     186             : 
     187             :     /**
     188             :      * Block until the monitor has a value less than the given value.
     189             :      * @return the value when reaching the condition.
     190             :      * @version 1.10
     191             :      */
     192        1000 :     const T waitLT( const T& value ) const
     193        1000 :         { return _waitPredicate( boost::bind( std::less<T>(), _1, value )); }
     194             : 
     195             :     /** @name Monitor the value with a timeout. */
     196             :     //@{
     197             :     /**
     198             :      * Block until the monitor has the given value.
     199             :      * @param value the exact value to monitor.
     200             :      * @param timeout the timeout in milliseconds to wait for the value.
     201             :      * @return true on success, false on timeout.
     202             :      * @version 1.1
     203             :      */
     204             :     bool timedWaitEQ( const T& value, const uint32_t timeout ) const
     205             :     {
     206             :         return _timedWaitPredicate( boost::bind( std::equal_to<T>(), _1,
     207             :                                                  value ), timeout );
     208             :     }
     209             : 
     210             :     /**
     211             :      * Block until the monitor has not the given value.
     212             :      * @param value the exact value to monitor.
     213             :      * @param timeout the timeout in milliseconds to wait for not the value.
     214             :      * @return true on success, false on timeout.
     215             :      * @version 1.10
     216             :      */
     217             :     bool timedWaitNE( const T& value, const uint32_t timeout ) const
     218             :     {
     219             :         return _timedWaitPredicate( boost::bind( std::not_equal_to<T>(), _1,
     220             :                                                  value ), timeout );
     221             :     }
     222             : 
     223             :     /**
     224             :      * Block until the monitor has a value greater or equal to the given value.
     225             :      * @param value the exact value to monitor.
     226             :      * @param timeout the timeout in milliseconds to wait for the value.
     227             :      * @return true on success, false on timeout.
     228             :      * @version 1.1
     229             :      */
     230        1000 :     bool timedWaitGE( const T& value, const uint32_t timeout ) const
     231             :     {
     232        2000 :         return _timedWaitPredicate( boost::bind( std::greater_equal<T>(), _1,
     233        2000 :                                                  value ), timeout );
     234             :     }
     235             : 
     236             :     /**
     237             :      * Block until the monitor has a value less or equal to the given value.
     238             :      * @param value the exact value to monitor.
     239             :      * @param timeout the timeout in milliseconds to wait for the value.
     240             :      * @return true on success, false on timeout.
     241             :      * @version 1.10
     242             :      */
     243        1000 :     bool timedWaitLE( const T& value, const uint32_t timeout ) const
     244             :     {
     245        2000 :         return _timedWaitPredicate( boost::bind( std::less_equal<T>(), _1,
     246        2000 :                                                  value ), timeout );
     247             :     }
     248             : 
     249             :     /**
     250             :      * Block until the monitor has a value greater than the given value.
     251             :      * @param value the exact value to monitor.
     252             :      * @param timeout the timeout in milliseconds to wait for the value.
     253             :      * @return true on success, false on timeout.
     254             :      * @version 1.10
     255             :      */
     256        1000 :     bool timedWaitGT( const T& value, const uint32_t timeout ) const
     257             :     {
     258        2000 :         return _timedWaitPredicate( boost::bind( std::greater<T>(), _1,
     259        2000 :                                                  value ), timeout );
     260             :     }
     261             : 
     262             :     /**
     263             :      * Block until the monitor has a value less than the given value.
     264             :      * @param value the exact value to monitor.
     265             :      * @param timeout the timeout in milliseconds to wait for the value.
     266             :      * @return true on success, false on timeout.
     267             :      * @version 1.10
     268             :      */
     269        1000 :     bool timedWaitLT( const T& value, const uint32_t timeout ) const
     270             :     {
     271        2000 :         return _timedWaitPredicate( boost::bind( std::less<T>(), _1, value ),
     272        2000 :                                     timeout );
     273             :     }
     274             : 
     275             :     //@}
     276             : 
     277             :     /** @name Comparison Operators. @version 1.0 */
     278             :     //@{
     279        2157 :     bool operator == ( const T& value ) const
     280             :     {
     281        4314 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     282        4314 :         return _value == value;
     283             :     }
     284      194786 :     bool operator != ( const T& value ) const
     285             :     {
     286      389572 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     287      389572 :         return _value != value;
     288             :     }
     289        2000 :     bool operator < ( const T& value ) const
     290             :     {
     291        4000 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     292        4000 :         return _value < value;
     293             :     }
     294     4006000 :     bool operator > ( const T& value ) const
     295             :     {
     296     8012000 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     297     8012000 :         return _value > value;
     298             :     }
     299        2000 :     bool operator <= ( const T& value ) const
     300             :     {
     301        4000 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     302        4000 :         return _value <= value;
     303             :     }
     304        2000 :     bool operator >= ( const T& value ) const
     305             :     {
     306        4000 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     307        4000 :         return _value >= value;
     308             :     }
     309             : 
     310             :     bool operator == ( const Monitor<T>& rhs ) const
     311             :     {
     312             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     313             :         return _value == rhs._value;
     314             :     }
     315             :     bool operator != ( const Monitor<T>& rhs ) const
     316             :     {
     317             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     318             :         return _value != rhs._value;
     319             :     }
     320             :     bool operator < ( const Monitor<T>& rhs ) const
     321             :     {
     322             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     323             :         return _value < rhs._value;
     324             :     }
     325             :     bool operator > ( const Monitor<T>& rhs ) const
     326             :     {
     327             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     328             :         return _value > rhs._value;
     329             :     }
     330             :     bool operator <= ( const Monitor<T>& rhs ) const
     331             :     {
     332             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     333             :         return _value <= rhs._value;
     334             :     }
     335             :     bool operator >= ( const Monitor<T>& rhs ) const
     336             :     {
     337             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     338             :         return _value >= rhs._value;
     339             :     }
     340             :     /** @return a bool conversion of the result. @version 1.9.1 */
     341           2 :     operator bool_t()
     342             :     {
     343           4 :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     344           4 :         return _value ? &Monitor< T >::bool_true : 0;
     345             :     }
     346             :     //@}
     347             : 
     348             :     /** @name Data Access. */
     349             :     //@{
     350             :     /** @return the current value. @version 1.0 */
     351             :     const T& operator->() const { return _value; }
     352             : 
     353             :     /** @return the current value. @version 1.0 */
     354             :     const T& get() const { return _value; }
     355             : 
     356             :     /** @return the current plus the given value. @version 1.0 */
     357             :     T operator + ( const T& value ) const
     358             :     {
     359             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     360             :         return _value + value;
     361             :     }
     362             : 
     363             :     /** @return the current or'ed with the given value. @version 1.0 */
     364             :     T operator | ( const T& value ) const
     365             :     {
     366             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     367             :         return static_cast< T >( _value | value );
     368             :     }
     369             : 
     370             :     /** @return the current and the given value. @version 1.0 */
     371             :     T operator & ( const T& value ) const
     372             :     {
     373             :         ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     374             :         return static_cast< T >( _value & value );
     375             :     }
     376             :     //@}
     377             : 
     378             : private:
     379             :     T _value;
     380             :     mutable Condition _cond;
     381             : 
     382             :     template< typename F >
     383      479125 :     const T _waitPredicate( const F& predicate ) const
     384             :     {
     385             :         if( sizeof( T ) <= 8 ) // issue #1
     386             :         {
     387      415306 :             const T current = _value;
     388      415306 :             if( predicate( current ))
     389        1625 :                 return current;
     390             :         }
     391      955000 :         ScopedCondition mutex( _cond );
     392     1621266 :         while( !predicate( _value ))
     393      571883 :             _cond.wait();
     394      477500 :         return _value;
     395             :     }
     396             : 
     397             :     template< typename F >
     398        4000 :     bool _timedWaitPredicate( const F& predicate, const uint32_t timeout ) const
     399             :     {
     400             :         if( sizeof( T ) <= 8 ) // issue #1
     401             :         {
     402        4000 :             const T current = _value;
     403        4000 :             if( predicate( current ))
     404           0 :                 return true;
     405             :         }
     406        8000 :         ScopedCondition mutex( _cond );
     407      294374 :         while( !predicate( _value ))
     408             :         {
     409      145187 :             if( !_cond.timedWait( timeout ) )
     410             :             {
     411           0 :                 return false;
     412             :             }
     413             :         }
     414        4000 :         return true;
     415             :     }
     416             : };
     417             : 
     418             : typedef Monitor< bool >     Monitorb; //!< A boolean monitor variable
     419             : typedef Monitor< uint32_t > Monitoru; //!< An unsigned 32bit integer monitor
     420             : 
     421             : /** Print the monitor to the given output stream. @version 1.0 */
     422             : template< typename T >
     423             : inline std::ostream& operator << ( std::ostream& os,
     424             :                                    const Monitor<T>& monitor )
     425             : {
     426             :     os << "Monitor< " << monitor.get() << " >";
     427             :     return os;
     428             : }
     429             : 
     430             : template<> inline Monitor< bool >& Monitor< bool >::operator++ ()
     431             : {
     432             :     ScopedCondition mutex( _cond );
     433             :     assert( !_value );
     434             :     _value = !_value;
     435             :     _cond.broadcast();
     436             :     return *this;
     437             : }
     438             : 
     439             : template<> inline Monitor< bool >& Monitor< bool >::operator-- ()
     440             : {
     441             :     ScopedCondition mutex( _cond );
     442             :     assert( !_value );
     443             :     _value = !_value;
     444             :     _cond.broadcast();
     445             :     return *this;
     446             : }
     447             : 
     448             : template<> inline
     449             : Monitor< bool >& Monitor< bool >::operator |= ( const bool& value )
     450             : {
     451             :     if( value )
     452             :     {
     453             :         ScopedCondition mutex( _cond );
     454             :         _value = value;
     455             :         _cond.broadcast();
     456             :     }
     457             :     return *this;
     458             : }
     459             : }
     460             : 
     461             : #include <servus/uint128_t.h>
     462             : namespace lunchbox
     463             : {
     464           1 : template<> inline Monitor< servus::uint128_t >::Monitor() {}
     465             : }
     466             : 
     467             : #endif //LUNCHBOX_MONITOR_H

Generated by: LCOV version 1.11