LCOV - code coverage report
Current view: top level - lunchbox - monitor.h (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 79 81 97.5 %
Date: 2015-07-07 14:54:45 Functions: 49 52 94.2 %

          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        1646 :     ~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      830647 :     Monitor& operator = ( const T& value )
      84             :         {
      85      830647 :             set( value );
      86      830646 :             return *this;
      87             :         }
      88             : 
      89             :     /** Assign a new value. @version 1.1.5 */
      90             :     const Monitor& operator = ( const Monitor< T >& from )
      91             :         {
      92             :             set( from._value );
      93             :             return *this;
      94             :         }
      95             : 
      96             :     /** Perform an or operation on the value. @version 1.0 */
      97             :     Monitor& operator |= ( const T& value )
      98             :         {
      99             :             ScopedCondition mutex( _cond );
     100             :             _value |= value;
     101             :             _cond.broadcast();
     102             :             return *this;
     103             :         }
     104             : 
     105             :     /** Perform an and operation on the value. @version 1.7 */
     106             :     Monitor& operator &= ( const T& value )
     107             :         {
     108             :             ScopedCondition mutex( _cond );
     109             :             _value &= value;
     110             :             _cond.broadcast();
     111             :             return *this;
     112             :         }
     113             : 
     114             :     /** Set a new value. @version 1.0 */
     115      830644 :     void set( const T& value )
     116             :         {
     117      830644 :             ScopedCondition mutex( _cond );
     118      830648 :             _value = value;
     119      830648 :             _cond.broadcast();
     120      830645 :         }
     121             :     //@}
     122             : 
     123             :     /** @name Monitor the value. */
     124             :     //@{
     125             :     /**
     126             :      * Block until the monitor has the given value.
     127             :      * @return the value when reaching the condition.
     128             :      * @version 1.0
     129             :      */
     130      400000 :     const T waitEQ( const T& value ) const
     131             :         {
     132             :             return _waitPredicate(
     133      400000 :                 boost::bind( std::equal_to< T >(), value, _1 ));
     134             :         }
     135             : 
     136             :     /**
     137             :      * Block until the monitor has not the given value.
     138             :      * @return the value when reaching the condition.
     139             :      * @version 1.0
     140             :      */
     141       11310 :     const T waitNE( const T& value ) const
     142             :         {
     143             :             return _waitPredicate(
     144       11310 :                 boost::bind( std::not_equal_to< T >(), value, _1 ));
     145             :         }
     146             : 
     147             :     /**
     148             :      * Block until the monitor has none of the given values.
     149             :      * @return the value when reaching the condition.
     150             :      * @version 1.0
     151             :      */
     152             :     const T waitNE( const T& v1, const T& v2 ) const
     153             :         {
     154             :             if( sizeof( T ) <= 8 ) // issue #1
     155             :             {
     156             :                 const T current = _value;
     157             :                 if( current != v1 && current != v2 )
     158             :                     return current;
     159             :             }
     160             :             ScopedCondition mutex( _cond );
     161             :             while( _value == v1 || _value == v2 )
     162             :                 _cond.wait();
     163             :             return _value;
     164             :         }
     165             : 
     166             :     /**
     167             :      * Block until the monitor has a value greater or equal to the given value.
     168             :      * @return the value when reaching the condition.
     169             :      * @version 1.0
     170             :      */
     171        1000 :     const T waitGE( const T& value ) const
     172             :         {
     173             :             return _waitPredicate(
     174        1000 :                 boost::bind( std::greater_equal< T >(), _1, value ));
     175             :         }
     176             :     /**
     177             :      * Block until the monitor has a value less or equal to the given value.
     178             :      * @return the value when reaching the condition.
     179             :      * @version 1.0
     180             :      */
     181       80296 :     const T waitLE( const T& value ) const
     182             :         {
     183             :             return _waitPredicate(
     184       80296 :                 boost::bind( std::less_equal< T >(), _1, value ));
     185             :         }
     186             : 
     187             :     /**
     188             :      * Block until the monitor has a value greater than the given value.
     189             :      * @return the value when reaching the condition.
     190             :      * @version 1.10
     191             :      */
     192        1000 :     const T waitGT( const T& value ) const
     193             :         {
     194             :             return _waitPredicate(
     195        1000 :                 boost::bind( std::greater< T >(), _1, value ));
     196             :         }
     197             :     /**
     198             :      * Block until the monitor has a value less than the given value.
     199             :      * @return the value when reaching the condition.
     200             :      * @version 1.10
     201             :      */
     202        1000 :     const T waitLT( const T& value ) const
     203             :         {
     204             :             return _waitPredicate(
     205        1000 :                 boost::bind( std::less< T >(), _1, value ));
     206             :         }
     207             : 
     208             :     /** @name Monitor the value with a timeout. */
     209             :     //@{
     210             :     /**
     211             :      * Block until the monitor has the given value.
     212             :      * @param value the exact value to monitor.
     213             :      * @param timeout the timeout in milliseconds to wait for the value.
     214             :      * @return true on success, false on timeout.
     215             :      * @version 1.1
     216             :      */
     217             :     bool timedWaitEQ( const T& value, const uint32_t timeout ) const
     218             :         {
     219             :             return _timedWaitPredicate(
     220             :                 boost::bind( std::equal_to< T >(), _1, value ), timeout);
     221             :         }
     222             : 
     223             :     /**
     224             :      * Block until the monitor has not the given value.
     225             :      * @param value the exact value to monitor.
     226             :      * @param timeout the timeout in milliseconds to wait for not the value.
     227             :      * @return true on success, false on timeout.
     228             :      * @version 1.10
     229             :      */
     230             :     bool timedWaitNE( const T& value, const uint32_t timeout ) const
     231             :         {
     232             :             return _timedWaitPredicate(
     233             :                 boost::bind( std::not_equal_to< T >(), _1, value ), timeout);
     234             :         }
     235             : 
     236             :     /**
     237             :      * Block until the monitor has a value greater 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.1
     242             :      */
     243        1036 :     bool timedWaitGE( const T& value, const uint32_t timeout ) const
     244             :         {
     245             :             return _timedWaitPredicate(
     246        1036 :                 boost::bind( std::greater_equal< T >(), _1, value ), timeout);
     247             :         }
     248             : 
     249             :     /**
     250             :      * Block until the monitor has a value less or equal to 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        1022 :     bool timedWaitLE( const T& value, const uint32_t timeout ) const
     257             :         {
     258             :             return _timedWaitPredicate(
     259        1022 :                 boost::bind( std::less_equal< T >(), _1, value ), timeout);
     260             :         }
     261             : 
     262             :     /**
     263             :      * Block until the monitor has a value greater 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        1036 :     bool timedWaitGT( const T& value, const uint32_t timeout ) const
     270             :         {
     271             :             return _timedWaitPredicate(
     272        1036 :                 boost::bind( std::greater< T >(), _1, value ), timeout);
     273             :         }
     274             : 
     275             :     /**
     276             :      * Block until the monitor has a value less than the given value.
     277             :      * @param value the exact value to monitor.
     278             :      * @param timeout the timeout in milliseconds to wait for the value.
     279             :      * @return true on success, false on timeout.
     280             :      * @version 1.10
     281             :      */
     282        1036 :     bool timedWaitLT( const T& value, const uint32_t timeout ) const
     283             :         {
     284             :             return _timedWaitPredicate(
     285        1036 :                 boost::bind( std::less< T >(), _1, value ), timeout);
     286             :         }
     287             : 
     288             :     //@}
     289             : 
     290             :     /** @name Comparison Operators. @version 1.0 */
     291             :     //@{
     292        2157 :     bool operator == ( const T& value ) const
     293             :         {
     294        2157 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     295        2157 :             return _value == value;
     296             :         }
     297      241225 :     bool operator != ( const T& value ) const
     298             :         {
     299      241225 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     300      241225 :             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     4006000 :     bool operator > ( const T& value ) const
     308             :         {
     309     4006000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     310     4006000 :             return _value > value;
     311             :         }
     312        2000 :     bool operator <= ( const T& value ) const
     313             :         {
     314        2000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     315        2000 :             return _value <= value;
     316             :         }
     317        2000 :     bool operator >= ( const T& value ) const
     318             :         {
     319        2000 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     320        2000 :             return _value >= value;
     321             :         }
     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             :     bool operator > ( const Monitor<T>& rhs ) const
     339             :         {
     340             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     341             :             return _value > rhs._value;
     342             :         }
     343             :     bool operator <= ( const Monitor<T>& rhs ) const
     344             :         {
     345             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     346             :             return _value <= rhs._value;
     347             :         }
     348             :     bool operator >= ( const Monitor<T>& rhs ) const
     349             :         {
     350             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     351             :             return _value >= rhs._value;
     352             :         }
     353             :     /** @return a bool conversion of the result. @version 1.9.1 */
     354           2 :     operator bool_t()
     355             :         {
     356           2 :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     357           2 :             return _value ? &Monitor< T >::bool_true : 0;
     358             :         }
     359             :     //@}
     360             : 
     361             :     /** @name Data Access. */
     362             :     //@{
     363             :     /** @return the current value. @version 1.0 */
     364             :     const T& operator->() const { return _value; }
     365             : 
     366             :     /** @return the current value. @version 1.0 */
     367             :     const T& get() const { return _value; }
     368             : 
     369             :     /** @return the current plus the given value. @version 1.0 */
     370             :     T operator + ( const T& value ) const
     371             :         {
     372             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     373             :             return _value + value;
     374             :         }
     375             : 
     376             :     /** @return the current or'ed with the given value. @version 1.0 */
     377             :     T operator | ( const T& value ) const
     378             :         {
     379             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     380             :             return static_cast< T >( _value | value );
     381             :         }
     382             : 
     383             :     /** @return the current and the given value. @version 1.0 */
     384             :     T operator & ( const T& value ) const
     385             :         {
     386             :             ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
     387             :             return static_cast< T >( _value & value );
     388             :         }
     389             :     //@}
     390             : 
     391             : private:
     392             :     T _value;
     393             :     mutable Condition _cond;
     394             : 
     395             :     template< typename F >
     396      494606 :     const T _waitPredicate( const F& predicate ) const
     397             :         {
     398             :             if( sizeof( T ) <= 8 ) // issue #1
     399             :             {
     400      415310 :                 const T current = _value;
     401      415310 :                 if( predicate( current ))
     402       22594 :                     return current;
     403             :             }
     404      472012 :             ScopedCondition mutex( _cond );
     405     1638281 :             while( !predicate( _value ))
     406      694257 :                 _cond.wait();
     407      472012 :             return _value;
     408             :         }
     409             : 
     410             :     template< typename F >
     411        4130 :     bool _timedWaitPredicate( const F& predicate, const uint32_t timeout ) const
     412             :         {
     413             :             if( sizeof( T ) <= 8 ) // issue #1
     414             :             {
     415        4130 :                 const T current = _value;
     416        4130 :                 if( predicate( current ))
     417           0 :                     return true;
     418             :             }
     419        4130 :             ScopedCondition mutex( _cond );
     420       51086 :             while( !predicate( _value ))
     421             :             {
     422       42956 :                 if( !_cond.timedWait( timeout ) )
     423             :                 {
     424         130 :                     return false;
     425             :                 }
     426             :             }
     427        4000 :             return true;
     428             :         }
     429             : };
     430             : 
     431             : typedef Monitor< bool >     Monitorb; //!< A boolean monitor variable
     432             : typedef Monitor< uint32_t > Monitoru; //!< An unsigned 32bit integer monitor
     433             : 
     434             : /** Print the monitor to the given output stream. @version 1.0 */
     435             : template< typename T >
     436             : inline std::ostream& operator << ( std::ostream& os,
     437             :                                    const Monitor<T>& monitor )
     438             : {
     439             :     os << "Monitor< " << monitor.get() << " >";
     440             :     return os;
     441             : }
     442             : 
     443             : template<> inline Monitor< bool >& Monitor< bool >::operator++ ()
     444             : {
     445             :     ScopedCondition mutex( _cond );
     446             :     assert( !_value );
     447             :     _value = !_value;
     448             :     _cond.broadcast();
     449             :     return *this;
     450             : }
     451             : 
     452             : template<> inline Monitor< bool >& Monitor< bool >::operator-- ()
     453             : {
     454             :     ScopedCondition mutex( _cond );
     455             :     assert( !_value );
     456             :     _value = !_value;
     457             :     _cond.broadcast();
     458             :     return *this;
     459             : }
     460             : 
     461             : template<> inline
     462             : Monitor< bool >& Monitor< bool >::operator |= ( const bool& value )
     463             : {
     464             :     if( value )
     465             :     {
     466             :         ScopedCondition mutex( _cond );
     467             :         _value = value;
     468             :         _cond.broadcast();
     469             :     }
     470             :     return *this;
     471             : }
     472             : }
     473             : 
     474             : #include <servus/uint128_t.h>
     475             : namespace lunchbox
     476             : {
     477           1 : template<> inline Monitor< servus::uint128_t >::Monitor() {}
     478             : }
     479             : 
     480             : #endif //LUNCHBOX_MONITOR_H

Generated by: LCOV version 1.11