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 :
31 : namespace lunchbox
32 : {
33 : /**
34 : * A monitor primitive.
35 : *
36 : * A monitor has a value, which can be monitored to reach a certain state. The
37 : * caller is blocked until the condition is fulfilled. The concept is similar to
38 : * a pthread condition, with more usage convenience.
39 : *
40 : * Example: @include tests/monitor.cpp
41 : */
42 : template< class T > class Monitor
43 : {
44 : typedef void (Monitor< T >::*bool_t)() const;
45 0 : void bool_true() const {}
46 :
47 : public:
48 : /** Construct a new monitor with a default value of 0. @version 1.0 */
49 3 : Monitor() : _value( T( 0 )) {}
50 :
51 : /** Construct a new monitor with a given default value. @version 1.0 */
52 4179 : explicit Monitor( const T& value ) : _value( value ) {}
53 :
54 : /** Ctor initializing with the given monitor value. @version 1.1.5 */
55 : Monitor( const Monitor< T >& from ) : _value( from._value ) {}
56 :
57 : /** Destructs the monitor. @version 1.0 */
58 4179 : ~Monitor() {}
59 :
60 : /** @name Changing the monitored value. */
61 : //@{
62 : /** Increment the monitored value, prefix only. @version 1.0 */
63 3885 : Monitor& operator++ ()
64 : {
65 3885 : ScopedCondition mutex( _cond );
66 3888 : ++_value;
67 3888 : _cond.broadcast();
68 3888 : return *this;
69 : }
70 :
71 : /** Decrement the monitored value, prefix only. @version 1.0 */
72 : Monitor& operator-- ()
73 : {
74 : ScopedCondition mutex( _cond );
75 : --_value;
76 : _cond.broadcast();
77 : return *this;
78 : }
79 :
80 : /** Assign a new value. @version 1.0 */
81 813974 : Monitor& operator = ( const T& value )
82 : {
83 813974 : set( value );
84 813981 : return *this;
85 : }
86 :
87 : /** Assign a new value. @version 1.1.5 */
88 : const Monitor& operator = ( const Monitor< T >& from )
89 : {
90 : set( from._value );
91 : return *this;
92 : }
93 :
94 : /** Perform an or operation on the value. @version 1.0 */
95 : Monitor& operator |= ( const T& value )
96 : {
97 : ScopedCondition mutex( _cond );
98 : _value |= value;
99 : _cond.broadcast();
100 : return *this;
101 : }
102 :
103 : /** Perform an and operation on the value. @version 1.7 */
104 : Monitor& operator &= ( const T& value )
105 : {
106 : ScopedCondition mutex( _cond );
107 : _value &= value;
108 : _cond.broadcast();
109 : return *this;
110 : }
111 :
112 : /** Set a new value. @version 1.0 */
113 813974 : void set( const T& value )
114 : {
115 813974 : ScopedCondition mutex( _cond );
116 813980 : _value = value;
117 813980 : _cond.broadcast();
118 813983 : }
119 : //@}
120 :
121 : /** @name Monitor the value. */
122 : //@{
123 : /**
124 : * Block until the monitor has the given value.
125 : * @return the value when reaching the condition.
126 : * @version 1.0
127 : */
128 400036 : const T& waitEQ( const T& value ) const
129 : {
130 400036 : if( sizeof( T ) <= 8 && _value == value )
131 7 : return value;
132 400029 : ScopedCondition mutex( _cond );
133 1200927 : while( _value != value )
134 400869 : _cond.wait();
135 400029 : return value;
136 : }
137 :
138 : /**
139 : * Block until the monitor has not the given value.
140 : * @return the value when reaching the condition.
141 : * @version 1.0
142 : */
143 6961 : const T waitNE( const T& value ) const
144 : {
145 : if( sizeof( T ) <= 8 ) // issue #1
146 : {
147 6961 : const T current = _value;
148 6961 : if( current != value )
149 3067 : return current;
150 : }
151 3894 : ScopedCondition mutex( _cond );
152 11682 : while( _value == value )
153 3894 : _cond.wait();
154 3894 : return _value;
155 : }
156 :
157 : /**
158 : * Block until the monitor has none of the given values.
159 : * @return the value when reaching the condition.
160 : * @version 1.0
161 : */
162 : const T waitNE( const T& v1, const T& v2 ) const
163 : {
164 : if( sizeof( T ) <= 8 ) // issue #1
165 : {
166 : const T current = _value;
167 : if( current != v1 && current != v2 )
168 : return current;
169 : }
170 : ScopedCondition mutex( _cond );
171 : while( _value == v1 || _value == v2 )
172 : _cond.wait();
173 : return _value;
174 : }
175 :
176 : /**
177 : * Block until the monitor has a value greater or equal to the given value.
178 : * @return the value when reaching the condition.
179 : * @version 1.0
180 : */
181 3996 : const T waitGE( const T& value ) const
182 : {
183 : if( sizeof( T ) <= 8 ) // issue #1
184 : {
185 3996 : const T current = _value;
186 3996 : if( current >= value )
187 0 : return current;
188 : }
189 3996 : ScopedCondition mutex( _cond );
190 88288 : while( _value < value )
191 80296 : _cond.wait();
192 3996 : return _value;
193 : }
194 : /**
195 : * Block until the monitor has a value less or equal to the given value.
196 : * @return the value when reaching the condition.
197 : * @version 1.0
198 : */
199 76731 : const T waitLE( const T& value ) const
200 : {
201 : if( sizeof( T ) <= 8 ) // issue #1
202 : {
203 : const T current = _value;
204 : if( current <= value )
205 : return current;
206 : }
207 76731 : ScopedCondition mutex( _cond );
208 153462 : while( _value > value )
209 0 : _cond.wait();
210 76731 : return _value;
211 : }
212 :
213 : /** @name Monitor the value with a timeout. */
214 : //@{
215 : /**
216 : * Block until the monitor has the given value.
217 : * @param value the exact value to monitor.
218 : * @param timeout the timeout in milliseconds to wait for the value.
219 : * @return true on success, false on timeout.
220 : * @version 1.1
221 : */
222 : bool timedWaitEQ( const T& value, const uint32_t timeout ) const
223 : {
224 : if( sizeof( T ) <= 8 && _value == value )
225 : return true;
226 :
227 : ScopedCondition mutex( _cond );
228 : while( _value != value )
229 : {
230 : if( !_cond.timedWait( timeout ) )
231 : {
232 : return false;
233 : }
234 : }
235 : return true;
236 : }
237 :
238 : /**
239 : * Block until the monitor has a value greater or equal to the given value.
240 : * @param value the exact value to monitor.
241 : * @param timeout the timeout in milliseconds to wait for the value.
242 : * @return true on success, false on timeout.
243 : * @version 1.1
244 : */
245 : bool timedWaitGE( const T& value, const uint32_t timeout ) const
246 : {
247 : if( sizeof( T ) <= 8 && _value >= value )
248 : return true;
249 :
250 : ScopedCondition mutex( _cond );
251 : while( _value < value )
252 : {
253 : if ( !_cond.timedWait( timeout ) )
254 : {
255 : return false;
256 : }
257 : }
258 : return true;
259 : }
260 :
261 : /**
262 : * Block until the monitor has not the given value.
263 : * @param value the exact value to monitor.
264 : * @param timeout the timeout in milliseconds to wait for not the value.
265 : * @return true on success, false on timeout.
266 : * @version 1.3.3
267 : */
268 : bool timedWaitNE( const T& value, const uint32_t timeout ) const
269 : {
270 : if( sizeof( T ) <= 8 && _value != value )
271 : return true;
272 :
273 : ScopedCondition mutex( _cond );
274 : while( _value == value )
275 : {
276 : if( !_cond.timedWait( timeout ) )
277 : {
278 : return false;
279 : }
280 : }
281 : return true;
282 : }
283 : //@}
284 :
285 : /** @name Comparison Operators. @version 1.0 */
286 : //@{
287 7976 : bool operator == ( const T& value ) const
288 : {
289 7976 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
290 7976 : return _value == value;
291 : }
292 237186 : bool operator != ( const T& value ) const
293 : {
294 237186 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
295 237186 : return _value != value;
296 : }
297 : bool operator < ( const T& value ) const
298 : {
299 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
300 : return _value < value;
301 : }
302 : bool operator > ( const T& value ) const
303 : {
304 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
305 : return _value > value;
306 : }
307 : bool operator <= ( const T& value ) const
308 : {
309 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
310 : return _value <= value;
311 : }
312 : bool operator >= ( const T& value ) const
313 : {
314 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
315 : return _value >= value;
316 : }
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 : 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 : /** @return a bool conversion of the result. @version 1.9.1 */
349 2 : operator bool_t()
350 : {
351 2 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
352 2 : return _value ? &Monitor< T >::bool_true : 0;
353 : }
354 : //@}
355 :
356 : /** @name Data Access. */
357 : //@{
358 : /** @return the current value. @version 1.0 */
359 : const T& operator->() const { return _value; }
360 :
361 : /** @return the current value. @version 1.0 */
362 : const T& get() const { return _value; }
363 :
364 : /** @return the current plus the given value. @version 1.0 */
365 : T operator + ( const T& value ) const
366 : {
367 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
368 : return _value + value;
369 : }
370 :
371 : /** @return the current or'ed with the given value. @version 1.0 */
372 : T operator | ( const T& value ) const
373 : {
374 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
375 : return static_cast< T >( _value | value );
376 : }
377 :
378 : /** @return the current and the given value. @version 1.0 */
379 : T operator & ( const T& value ) const
380 : {
381 : ScopedCondition mutex( sizeof(T)>8 ? &_cond : 0 ); // issue #1
382 : return static_cast< T >( _value & value );
383 : }
384 : //@}
385 :
386 : private:
387 : T _value;
388 : mutable Condition _cond;
389 : };
390 :
391 : typedef Monitor< bool > Monitorb; //!< A boolean monitor variable
392 : typedef Monitor< uint32_t > Monitoru; //!< An unsigned 32bit integer monitor
393 :
394 : /** Print the monitor to the given output stream. @version 1.0 */
395 : template< typename T >
396 : inline std::ostream& operator << ( std::ostream& os,
397 : const Monitor<T>& monitor )
398 : {
399 : os << "Monitor< " << monitor.get() << " >";
400 : return os;
401 : }
402 :
403 : template<> inline Monitor< bool >& Monitor< bool >::operator++ ()
404 : {
405 : ScopedCondition mutex( _cond );
406 : assert( !_value );
407 : _value = !_value;
408 : _cond.broadcast();
409 : return *this;
410 : }
411 :
412 : template<> inline Monitor< bool >& Monitor< bool >::operator-- ()
413 : {
414 : ScopedCondition mutex( _cond );
415 : assert( !_value );
416 : _value = !_value;
417 : _cond.broadcast();
418 : return *this;
419 : }
420 :
421 : template<> inline
422 : Monitor< bool >& Monitor< bool >::operator |= ( const bool& value )
423 : {
424 : if( value )
425 : {
426 : ScopedCondition mutex( _cond );
427 : _value = value;
428 : _cond.broadcast();
429 : }
430 : return *this;
431 : }
432 : }
433 :
434 : #include <lunchbox/uint128_t.h>
435 : namespace lunchbox
436 : {
437 1 : template<> inline Monitor< uint128_t >::Monitor() {}
438 : }
439 :
440 : #endif //LUNCHBOX_MONITOR_H
|