LCOV - code coverage report
Current view: top level - lunchbox - monitor.h (source / functions) Hit Total Coverage
Test: Lunchbox Lines: 76 77 98.7 %
Date: 2017-08-03 05:21:41 Functions: 63 64 98.4 %

          Line data    Source code
       1             : /* Copyright (c) 2006-2017, Stefan Eilemann <eile@equalizergraphics.com>
       2             :  *                          Cedric Stalder <cedric.stalder@gmail.com>
       3             :  *                          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/scopedMutex.h> // used inline
      23             : #include <lunchbox/types.h>
      24             : 
      25             : #include <boost/bind.hpp>
      26             : #include <condition_variable>
      27             : #include <errno.h>
      28             : #include <functional>
      29             : #include <iostream>
      30             : #include <mutex>
      31             : #include <string.h>
      32             : #include <typeinfo>
      33             : 
      34             : namespace lunchbox
      35             : {
      36             : /**
      37             :  * A monitor primitive.
      38             :  *
      39             :  * A monitor has a value, which can be monitored to reach a certain state. The
      40             :  * caller is blocked until the condition is fulfilled. The concept is similar to
      41             :  * a pthread condition, with more usage convenience.
      42             :  *
      43             :  * Example: @include tests/monitor.cpp
      44             :  */
      45             : template <class T>
      46             : class Monitor
      47             : {
      48             :     typedef void (Monitor<T>::*bool_t)() const;
      49           0 :     void bool_true() const {}
      50             : public:
      51             :     /** Construct a new monitor with a default value of 0. @version 1.0 */
      52           2 :     Monitor()
      53           2 :         : _value(T(0))
      54             :     {
      55           2 :     }
      56             : 
      57             :     /** Construct a new monitor with a given default value. @version 1.0 */
      58        1641 :     explicit Monitor(const T& value)
      59        1641 :         : _value(value)
      60             :     {
      61        1641 :     }
      62             : 
      63             :     /** Ctor initializing with the given monitor value. @version 1.1.5 */
      64             :     Monitor(const Monitor<T>& from)
      65             :         : _value(from._value)
      66             :     {
      67             :     }
      68             : 
      69             :     /** Destructs the monitor. @version 1.0 */
      70        1644 :     ~Monitor() {}
      71             :     /** @name Changing the monitored value. */
      72             :     //@{
      73             :     /** Increment the monitored value, prefix only. @version 1.0 */
      74     2002000 :     Monitor& operator++()
      75             :     {
      76     4004000 :         std::unique_lock<std::mutex> lock(_mutex);
      77     2002000 :         ++_value;
      78     2002000 :         _condition.notify_all();
      79     4004000 :         return *this;
      80             :     }
      81             : 
      82             :     /** Decrement the monitored value, prefix only. @version 1.0 */
      83     2002000 :     Monitor& operator--()
      84             :     {
      85     4004000 :         std::unique_lock<std::mutex> lock(_mutex);
      86     2002000 :         --_value;
      87     2002000 :         _condition.notify_all();
      88     4004000 :         return *this;
      89             :     }
      90             : 
      91             :     /** Assign a new value. @version 1.0 */
      92      830624 :     Monitor& operator=(const T& value)
      93             :     {
      94      830624 :         set(value);
      95      830633 :         return *this;
      96             :     }
      97             : 
      98             :     /** Assign a new value. @version 1.1.5 */
      99             :     const Monitor& operator=(const Monitor<T>& from)
     100             :     {
     101             :         set(from._value);
     102             :         return *this;
     103             :     }
     104             : 
     105             :     /** Perform an or operation on the value. @version 1.0 */
     106             :     Monitor& operator|=(const T& value)
     107             :     {
     108             :         std::unique_lock<std::mutex> lock(_mutex);
     109             :         _value |= value;
     110             :         _condition.notify_all();
     111             :         return *this;
     112             :     }
     113             : 
     114             :     /** Perform an and operation on the value. @version 1.7 */
     115             :     Monitor& operator&=(const T& value)
     116             :     {
     117             :         std::unique_lock<std::mutex> lock(_mutex);
     118             :         _value &= value;
     119             :         _condition.notify_all();
     120             :         return *this;
     121             :     }
     122             : 
     123             :     /** Set a new value. @return the old value @version 1.0 */
     124      830624 :     T set(const T& value)
     125             :     {
     126     1661256 :         std::unique_lock<std::mutex> lock(_mutex);
     127      830629 :         const T old = _value;
     128      830629 :         _value = value;
     129      830629 :         _condition.notify_all();
     130     1661265 :         return old;
     131             :     }
     132             :     //@}
     133             : 
     134             :     /** @name Monitor the value. */
     135             :     //@{
     136             :     /**
     137             :      * Block until the monitor has the given value.
     138             :      * @return the value when reaching the condition.
     139             :      * @version 1.0
     140             :      */
     141      400000 :     const T waitEQ(const T& value) const
     142             :     {
     143     1199978 :         return _wait([&] { return _value == value; });
     144             :     }
     145             : 
     146             :     /**
     147             :      * Block until the monitor has not the given value.
     148             :      * @return the value when reaching the condition.
     149             :      * @version 1.0
     150             :      */
     151       11305 :     const T waitNE(const T& value) const
     152             :     {
     153       32302 :         return _wait([&] { return _value != value; });
     154             :     }
     155             : 
     156             :     /**
     157             :      * Block until the monitor has none of the given values.
     158             :      * @return the value when reaching the condition.
     159             :      * @version 1.0
     160             :      */
     161             :     const T waitNE(const T& v1, const T& v2) const
     162             :     {
     163             :         std::unique_lock<std::mutex> lock(_mutex);
     164             :         _condition.wait(lock, [&] { return _value != v1 && _value != v2; });
     165             :         return _value;
     166             :     }
     167             : 
     168             :     /**
     169             :      * Block until the monitor has a value greater or equal to the given value.
     170             :      * @return the value when reaching the condition.
     171             :      * @version 1.0
     172             :      */
     173        1000 :     const T waitGE(const T& value) const
     174             :     {
     175       83040 :         return _wait([&] { return _value >= value; });
     176             :     }
     177             : 
     178             :     /**
     179             :      * Block until the monitor has a value less or equal to the given value.
     180             :      * @return the value when reaching the condition.
     181             :      * @version 1.0
     182             :      */
     183       61643 :     const T waitLE(const T& value) const
     184             :     {
     185      200684 :         return _wait([&] { return _value <= value; });
     186             :     }
     187             : 
     188             :     /**
     189             :      * Block until the monitor has a value greater than the given value.
     190             :      * @return the value when reaching the condition.
     191             :      * @version 1.10
     192             :      */
     193        1000 :     const T waitGT(const T& value) const
     194             :     {
     195       82755 :         return _wait([&] { return _value > value; });
     196             :     }
     197             : 
     198             :     /**
     199             :      * Block until the monitor has a value less than the given value.
     200             :      * @return the value when reaching the condition.
     201             :      * @version 1.10
     202             :      */
     203        1000 :     const T waitLT(const T& value) const
     204             :     {
     205       80163 :         return _wait([&] { return _value < 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 _timedWait([&] { return _value == value; }, timeout);
     220             :     }
     221             : 
     222             :     /**
     223             :      * Block until the monitor has not the given value.
     224             :      * @param value the exact value to monitor.
     225             :      * @param timeout the timeout in milliseconds to wait for not the value.
     226             :      * @return true on success, false on timeout.
     227             :      * @version 1.10
     228             :      */
     229             :     bool timedWaitNE(const T& value, const uint32_t timeout) const
     230             :     {
     231             :         return _timedWait([&] { return _value != value; }, timeout);
     232             :     }
     233             : 
     234             :     /**
     235             :      * Block until the monitor has a value greater 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.1
     240             :      */
     241        1334 :     bool timedWaitGE(const T& value, const uint32_t timeout) const
     242             :     {
     243       60815 :         return _timedWait([&] { return _value >= value; }, timeout);
     244             :     }
     245             : 
     246             :     /**
     247             :      * Block until the monitor has a value less or equal to the given value.
     248             :      * @param value the exact value to monitor.
     249             :      * @param timeout the timeout in milliseconds to wait for the value.
     250             :      * @return true on success, false on timeout.
     251             :      * @version 1.10
     252             :      */
     253        1351 :     bool timedWaitLE(const T& value, const uint32_t timeout) const
     254             :     {
     255       63140 :         return _timedWait([&] { return _value <= value; }, timeout);
     256             :     }
     257             : 
     258             :     /**
     259             :      * Block until the monitor has a value greater than the given value.
     260             :      * @param value the exact value to monitor.
     261             :      * @param timeout the timeout in milliseconds to wait for the value.
     262             :      * @return true on success, false on timeout.
     263             :      * @version 1.10
     264             :      */
     265        1339 :     bool timedWaitGT(const T& value, const uint32_t timeout) const
     266             :     {
     267       60531 :         return _timedWait([&] { return _value > value; }, timeout);
     268             :     }
     269             : 
     270             :     /**
     271             :      * Block until the monitor has a value less than the given value.
     272             :      * @param value the exact value to monitor.
     273             :      * @param timeout the timeout in milliseconds to wait for the value.
     274             :      * @return true on success, false on timeout.
     275             :      * @version 1.10
     276             :      */
     277        1383 :     bool timedWaitLT(const T& value, const uint32_t timeout) const
     278             :     {
     279       64783 :         return _timedWait([&] { return _value < value; }, timeout);
     280             :     }
     281             : 
     282             :     //@}
     283             : 
     284             :     /** @name Comparison Operators. @version 1.0 */
     285             :     //@{
     286        2157 :     bool operator==(const T& value) const
     287             :     {
     288        4314 :         std::unique_lock<std::mutex> lock(_mutex);
     289        4314 :         return _value == value;
     290             :     }
     291      185256 :     bool operator!=(const T& value) const
     292             :     {
     293      370512 :         std::unique_lock<std::mutex> lock(_mutex);
     294      370512 :         return _value != value;
     295             :     }
     296        2000 :     bool operator<(const T& value) const
     297             :     {
     298        4000 :         std::unique_lock<std::mutex> lock(_mutex);
     299        4000 :         return _value < value;
     300             :     }
     301     4006000 :     bool operator>(const T& value) const
     302             :     {
     303     8012000 :         std::unique_lock<std::mutex> lock(_mutex);
     304     8012000 :         return _value > value;
     305             :     }
     306        2000 :     bool operator<=(const T& value) const
     307             :     {
     308        4000 :         std::unique_lock<std::mutex> lock(_mutex);
     309        4000 :         return _value <= value;
     310             :     }
     311        2000 :     bool operator>=(const T& value) const
     312             :     {
     313        4000 :         std::unique_lock<std::mutex> lock(_mutex);
     314        4000 :         return _value >= value;
     315             :     }
     316             : 
     317             :     bool operator==(const Monitor<T>& rhs) const
     318             :     {
     319             :         std::unique_lock<std::mutex> lock(_mutex);
     320             :         return _value == rhs._value;
     321             :     }
     322             :     bool operator!=(const Monitor<T>& rhs) const
     323             :     {
     324             :         std::unique_lock<std::mutex> lock(_mutex);
     325             :         return _value != rhs._value;
     326             :     }
     327             :     bool operator<(const Monitor<T>& rhs) const
     328             :     {
     329             :         std::unique_lock<std::mutex> lock(_mutex);
     330             :         return _value < rhs._value;
     331             :     }
     332             :     bool operator>(const Monitor<T>& rhs) const
     333             :     {
     334             :         std::unique_lock<std::mutex> lock(_mutex);
     335             :         return _value > rhs._value;
     336             :     }
     337             :     bool operator<=(const Monitor<T>& rhs) const
     338             :     {
     339             :         std::unique_lock<std::mutex> lock(_mutex);
     340             :         return _value <= rhs._value;
     341             :     }
     342             :     bool operator>=(const Monitor<T>& rhs) const
     343             :     {
     344             :         std::unique_lock<std::mutex> lock(_mutex);
     345             :         return _value >= rhs._value;
     346             :     }
     347             :     /** @return a bool conversion of the result. @version 1.9.1 */
     348           2 :     operator bool_t()
     349             :     {
     350           4 :         std::unique_lock<std::mutex> lock(_mutex);
     351           4 :         return _value ? &Monitor<T>::bool_true : 0;
     352             :     }
     353             :     //@}
     354             : 
     355             :     /** @name Data Access. */
     356             :     //@{
     357             :     /** @return the current value. @version 1.0 */
     358             :     const T& operator->() const { return _value; }
     359             :     /** @return the current value. @version 1.0 */
     360             :     const T& get() const { return _value; }
     361             :     /** @return the current plus the given value. @version 1.0 */
     362             :     T operator+(const T& value) const
     363             :     {
     364             :         std::unique_lock<std::mutex> lock(_mutex);
     365             :         return _value + value;
     366             :     }
     367             : 
     368             :     /** @return the current or'ed with the given value. @version 1.0 */
     369             :     T operator|(const T& value) const
     370             :     {
     371             :         std::unique_lock<std::mutex> lock(_mutex);
     372             :         return static_cast<T>(_value | value);
     373             :     }
     374             : 
     375             :     /** @return the current and the given value. @version 1.0 */
     376             :     T operator&(const T& value) const
     377             :     {
     378             :         std::unique_lock<std::mutex> lock(_mutex);
     379             :         return static_cast<T>(_value & value);
     380             :     }
     381             :     //@}
     382             : 
     383             : private:
     384             :     T _value;
     385             :     mutable std::mutex _mutex;
     386             :     mutable std::condition_variable _condition;
     387             : 
     388             :     template <typename F>
     389      475948 :     const T _wait(const F& predicate) const
     390             :     {
     391      951896 :         std::unique_lock<std::mutex> lock(_mutex);
     392      475948 :         _condition.wait(lock, predicate);
     393      951896 :         return _value;
     394             :     }
     395             : 
     396             :     template <typename F>
     397        5407 :     bool _timedWait(const F& predicate, const uint32_t timeout) const
     398             :     {
     399       10814 :         std::unique_lock<std::mutex> lock(_mutex);
     400             :         return _condition.wait_for(lock, std::chrono::milliseconds(timeout),
     401       10814 :                                    predicate);
     402             :     }
     403             : };
     404             : 
     405             : typedef Monitor<bool> Monitorb;     //!< A boolean monitor variable
     406             : typedef Monitor<uint32_t> Monitoru; //!< An unsigned 32bit integer monitor
     407             : 
     408             : /** Print the monitor to the given output stream. @version 1.0 */
     409             : template <typename T>
     410             : inline std::ostream& operator<<(std::ostream& os, const Monitor<T>& monitor)
     411             : {
     412             :     os << "Monitor< " << monitor.get() << " >";
     413             :     return os;
     414             : }
     415             : 
     416             : template <>
     417             : inline Monitor<bool>& Monitor<bool>::operator++()
     418             : {
     419             :     std::unique_lock<std::mutex> lock(_mutex);
     420             :     assert(!_value);
     421             :     _value = !_value;
     422             :     _condition.notify_all();
     423             :     return *this;
     424             : }
     425             : 
     426             : template <>
     427             : inline Monitor<bool>& Monitor<bool>::operator--()
     428             : {
     429             :     std::unique_lock<std::mutex> lock(_mutex);
     430             :     assert(!_value);
     431             :     _value = !_value;
     432             :     _condition.notify_all();
     433             :     return *this;
     434             : }
     435             : 
     436             : template <>
     437             : inline Monitor<bool>& Monitor<bool>::operator|=(const bool& value)
     438             : {
     439             :     if (value)
     440             :     {
     441             :         std::unique_lock<std::mutex> lock(_mutex);
     442             :         _value = value;
     443             :         _condition.notify_all();
     444             :     }
     445             :     return *this;
     446             : }
     447             : }
     448             : 
     449             : #include <servus/uint128_t.h>
     450             : namespace lunchbox
     451             : {
     452             : template <>
     453           1 : inline Monitor<servus::uint128_t>::Monitor()
     454             : {
     455           1 : }
     456             : }
     457             : 
     458             : #endif // LUNCHBOX_MONITOR_H

Generated by: LCOV version 1.11