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
|