LCOV - code coverage report
Current view: top level - lunchbox - monitor.h (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 79 81 97.5 %
Date: 2016-03-29 17:09:06 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        1646 :     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        1649 :     ~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     2002000 :         ScopedCondition mutex( _cond );
      68     2002000 :         ++_value;
      69     2002000 :         _cond.broadcast();
      70     2002000 :         return *this;
      71             :     }
      72             : 
      73             :     /** Decrement the monitored value, prefix only. @version 1.0 */
      74     2002000 :     Monitor& operator-- ()
      75             :     {
      76     2002000 :         ScopedCondition mutex( _cond );
      77     2002000 :         --_value;
      78     2002000 :         _cond.broadcast();
      79     2002000 :         return *this;
      80             :     }
      81             : 
      82             :     /** Assign a new value. @version 1.0 */
      83      830638 :     Monitor& operator = ( const T& value )
      84      830638 :         { 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. @version 1.0 */
     109      830636 :     void set( const T& value )
     110             :     {
     111      830636 :         ScopedCondition mutex( _cond );
     112      830641 :         _value = value;
     113      830641 :         _cond.broadcast();
     114      830647 :     }
     115             :     //@}
     116             : 
     117             :     /** @name Monitor the value. */
     118             :     //@{
     119             :     /**
     120             :      * Block until the monitor has the given value.
     121             :      * @return the value when reaching the condition.
     122             :      * @version 1.0
     123             :      */
     124      400000 :     const T waitEQ( const T& value ) const
     125             :     {
     126      400000 :         return _waitPredicate( boost::bind( std::equal_to<T>(), value, _1 ));
     127             :     }
     128             : 
     129             :     /**
     130             :      * Block until the monitor has not the given value.
     131             :      * @return the value when reaching the condition.
     132             :      * @version 1.0
     133             :      */
     134       11310 :     const T waitNE( const T& value ) const
     135             :     {
     136       11310 :         return _waitPredicate( boost::bind( std::not_equal_to<T>(), value, _1));
     137             :     }
     138             : 
     139             :     /**
     140             :      * Block until the monitor has none of the given values.
     141             :      * @return the value when reaching the condition.
     142             :      * @version 1.0
     143             :      */
     144             :     const T waitNE( const T& v1, const T& v2 ) const
     145             :     {
     146             :         if( sizeof( T ) <= 8 ) // issue #1
     147             :         {
     148             :             const T current = _value;
     149             :             if( current != v1 && current != v2 )
     150             :                 return current;
     151             :         }
     152             :         ScopedCondition mutex( _cond );
     153             :         while( _value == v1 || _value == v2 )
     154             :             _cond.wait();
     155             :         return _value;
     156             :     }
     157             : 
     158             :     /**
     159             :      * Block until the monitor has a value greater or equal to the given value.
     160             :      * @return the value when reaching the condition.
     161             :      * @version 1.0
     162             :      */
     163        1000 :     const T waitGE( const T& value ) const
     164             :     {
     165             :         return _waitPredicate( boost::bind( std::greater_equal<T>(), _1,
     166        1000 :                                             value ));
     167             :     }
     168             : 
     169             :     /**
     170             :      * Block until the monitor has a value less or equal to the given value.
     171             :      * @return the value when reaching the condition.
     172             :      * @version 1.0
     173             :      */
     174       62827 :     const T waitLE( const T& value ) const
     175       62827 :     { return _waitPredicate( boost::bind( std::less_equal<T>(), _1, value )); }
     176             : 
     177             :     /**
     178             :      * Block until the monitor has a value greater than the given value.
     179             :      * @return the value when reaching the condition.
     180             :      * @version 1.10
     181             :      */
     182        1000 :     const T waitGT( const T& value ) const
     183        1000 :     { return _waitPredicate( boost::bind( std::greater<T>(), _1, value )); }
     184             : 
     185             :     /**
     186             :      * Block until the monitor has a value less than the given value.
     187             :      * @return the value when reaching the condition.
     188             :      * @version 1.10
     189             :      */
     190        1000 :     const T waitLT( const T& value ) const
     191        1000 :     { return _waitPredicate( boost::bind( std::less<T>(), _1, value )); }
     192             : 
     193             :     /** @name Monitor the value with a timeout. */
     194             :     //@{
     195             :     /**
     196             :      * Block until the monitor has the given value.
     197             :      * @param value the exact value to monitor.
     198             :      * @param timeout the timeout in milliseconds to wait for the value.
     199             :      * @return true on success, false on timeout.
     200             :      * @version 1.1
     201             :      */
     202             :     bool timedWaitEQ( const T& value, const uint32_t timeout ) const
     203             :     {
     204             :         return _timedWaitPredicate( boost::bind( std::equal_to<T>(), _1,
     205             :                                                  value ), timeout );
     206             :     }
     207             : 
     208             :     /**
     209             :      * Block until the monitor has not the given value.
     210             :      * @param value the exact value to monitor.
     211             :      * @param timeout the timeout in milliseconds to wait for not the value.
     212             :      * @return true on success, false on timeout.
     213             :      * @version 1.10
     214             :      */
     215             :     bool timedWaitNE( const T& value, const uint32_t timeout ) const
     216             :     {
     217             :         return _timedWaitPredicate( boost::bind( std::not_equal_to<T>(), _1,
     218             :                                                  value ), timeout );
     219             :     }
     220             : 
     221             :     /**
     222             :      * Block until the monitor has a value greater or equal to the given value.
     223             :      * @param value the exact value to monitor.
     224             :      * @param timeout the timeout in milliseconds to wait for the value.
     225             :      * @return true on success, false on timeout.
     226             :      * @version 1.1
     227             :      */
     228        1000 :     bool timedWaitGE( const T& value, const uint32_t timeout ) const
     229             :     {
     230             :         return _timedWaitPredicate( boost::bind( std::greater_equal<T>(), _1,
     231        1000 :                                                  value ), timeout );
     232             :     }
     233             : 
     234             :     /**
     235             :      * Block until the monitor has a value less or equal to the given value.
     236             :      * @param value the exact value to monitor.
     237             :      * @param timeout the timeout in milliseconds to wait for the value.
     238             :      * @return true on success, false on timeout.
     239             :      * @version 1.10
     240             :      */
     241        1000 :     bool timedWaitLE( const T& value, const uint32_t timeout ) const
     242             :     {
     243             :         return _timedWaitPredicate( boost::bind( std::less_equal<T>(), _1,
     244        1000 :                                                  value ), timeout );
     245             :     }
     246             : 
     247             :     /**
     248             :      * Block until the monitor has a value greater than the given value.
     249             :      * @param value the exact value to monitor.
     250             :      * @param timeout the timeout in milliseconds to wait for the value.
     251             :      * @return true on success, false on timeout.
     252             :      * @version 1.10
     253             :      */
     254        1000 :     bool timedWaitGT( const T& value, const uint32_t timeout ) const
     255             :     {
     256             :         return _timedWaitPredicate( boost::bind( std::greater<T>(), _1,
     257        1000 :                                                  value ), timeout );
     258             :     }
     259             : 
     260             :     /**
     261             :      * Block until the monitor has a value less than the given value.
     262             :      * @param value the exact value to monitor.
     263             :      * @param timeout the timeout in milliseconds to wait for the value.
     264             :      * @return true on success, false on timeout.
     265             :      * @version 1.10
     266             :      */
     267        1000 :     bool timedWaitLT( const T& value, const uint32_t timeout ) const
     268             :     {
     269        2000 :         return _timedWaitPredicate( boost::bind( std::less<T>(), _1, value ),
     270        2000 :                                     timeout );
     271             :     }
     272             : 
     273             :     //@}
     274             : 
     275             :     /** @name Comparison Operators. @version 1.0 */
     276             :     //@{
     277        2157 :     bool operator == ( const T& value ) const
     278             :         {
     279        2157 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     280        2157 :             return _value == value;
     281             :         }
     282      188818 :     bool operator != ( const T& value ) const
     283             :         {
     284      188818 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     285      188818 :             return _value != value;
     286             :         }
     287        2000 :     bool operator < ( const T& value ) const
     288             :         {
     289        2000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     290        2000 :             return _value < value;
     291             :         }
     292     4006000 :     bool operator > ( const T& value ) const
     293             :         {
     294     4006000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     295     4006000 :             return _value > value;
     296             :         }
     297        2000 :     bool operator <= ( const T& value ) const
     298             :         {
     299        2000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     300        2000 :             return _value <= value;
     301             :         }
     302        2000 :     bool operator >= ( const T& value ) const
     303             :         {
     304        2000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     305        2000 :             return _value >= value;
     306             :         }
     307             : 
     308             :     bool operator == ( const Monitor<T>& rhs ) const
     309             :         {
     310             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     311             :             return _value == rhs._value;
     312             :         }
     313             :     bool operator != ( const Monitor<T>& rhs ) const
     314             :         {
     315             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     316             :             return _value != rhs._value;
     317             :         }
     318             :     bool operator < ( const Monitor<T>& rhs ) const
     319             :         {
     320             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     321             :             return _value < rhs._value;
     322             :         }
     323             :     bool operator > ( const Monitor<T>& rhs ) const
     324             :         {
     325             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     326             :             return _value > rhs._value;
     327             :         }
     328             :     bool operator <= ( const Monitor<T>& rhs ) const
     329             :         {
     330             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     331             :             return _value <= rhs._value;
     332             :         }
     333             :     bool operator >= ( const Monitor<T>& rhs ) const
     334             :         {
     335             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     336             :             return _value >= rhs._value;
     337             :         }
     338             :     /** @return a bool conversion of the result. @version 1.9.1 */
     339           2 :     operator bool_t()
     340             :         {
     341           2 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     342           2 :             return _value ? &Monitor< T >::bool_true : 0;
     343             :         }
     344             :     //@}
     345             : 
     346             :     /** @name Data Access. */
     347             :     //@{
     348             :     /** @return the current value. @version 1.0 */
     349             :     const T& operator->() const { return _value; }
     350             : 
     351             :     /** @return the current value. @version 1.0 */
     352             :     const T& get() const { return _value; }
     353             : 
     354             :     /** @return the current plus the given value. @version 1.0 */
     355             :     T operator + ( const T& value ) const
     356             :         {
     357             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     358             :             return _value + value;
     359             :         }
     360             : 
     361             :     /** @return the current or'ed with the given value. @version 1.0 */
     362             :     T operator | ( const T& value ) const
     363             :         {
     364             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     365             :             return static_cast< T >( _value | value );
     366             :         }
     367             : 
     368             :     /** @return the current and the given value. @version 1.0 */
     369             :     T operator & ( const T& value ) const
     370             :         {
     371             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     372             :             return static_cast< T >( _value & value );
     373             :         }
     374             :     //@}
     375             : 
     376             : private:
     377             :     T _value;
     378             :     mutable Condition _cond;
     379             : 
     380             :     template< typename F >
     381      477137 :     const T _waitPredicate( const F& predicate ) const
     382             :         {
     383             :             if( sizeof( T ) <= 8 ) // issue #1
     384             :             {
     385      415310 :                 const T current = _value;
     386      415310 :                 if( predicate( current ))
     387        1648 :                     return current;
     388             :             }
     389      475489 :             ScopedCondition mutex( _cond );
     390     1534146 :             while( !predicate( _value ))
     391      583168 :                 _cond.wait();
     392      475489 :             return _value;
     393             :         }
     394             : 
     395             :     template< typename F >
     396        4000 :     bool _timedWaitPredicate( const F& predicate, const uint32_t timeout ) const
     397             :         {
     398             :             if( sizeof( T ) <= 8 ) // issue #1
     399             :             {
     400        4000 :                 const T current = _value;
     401        4000 :                 if( predicate( current ))
     402           1 :                     return true;
     403             :             }
     404        3999 :             ScopedCondition mutex( _cond );
     405      148655 :             while( !predicate( _value ))
     406             :             {
     407      140657 :                 if( !_cond.timedWait( timeout ) )
     408             :                 {
     409           0 :                     return false;
     410             :                 }
     411             :             }
     412        3999 :             return true;
     413             :         }
     414             : };
     415             : 
     416             : typedef Monitor< bool >     Monitorb; //!< A boolean monitor variable
     417             : typedef Monitor< uint32_t > Monitoru; //!< An unsigned 32bit integer monitor
     418             : 
     419             : /** Print the monitor to the given output stream. @version 1.0 */
     420             : template< typename T >
     421             : inline std::ostream& operator << ( std::ostream& os,
     422             :                                    const Monitor<T>& monitor )
     423             : {
     424             :     os << "Monitor< " << monitor.get() << " >";
     425             :     return os;
     426             : }
     427             : 
     428             : template<> inline Monitor< bool >& Monitor< bool >::operator++ ()
     429             : {
     430             :     ScopedCondition mutex( _cond );
     431             :     assert( !_value );
     432             :     _value = !_value;
     433             :     _cond.broadcast();
     434             :     return *this;
     435             : }
     436             : 
     437             : template<> inline Monitor< bool >& Monitor< bool >::operator-- ()
     438             : {
     439             :     ScopedCondition mutex( _cond );
     440             :     assert( !_value );
     441             :     _value = !_value;
     442             :     _cond.broadcast();
     443             :     return *this;
     444             : }
     445             : 
     446             : template<> inline
     447             : Monitor< bool >& Monitor< bool >::operator |= ( const bool& value )
     448             : {
     449             :     if( value )
     450             :     {
     451             :         ScopedCondition mutex( _cond );
     452             :         _value = value;
     453             :         _cond.broadcast();
     454             :     }
     455             :     return *this;
     456             : }
     457             : }
     458             : 
     459             : #include <servus/uint128_t.h>
     460             : namespace lunchbox
     461             : {
     462           1 : template<> inline Monitor< servus::uint128_t >::Monitor() {}
     463             : }
     464             : 
     465             : #endif //LUNCHBOX_MONITOR_H

Generated by: LCOV version 1.11