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
|