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
|