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 830622 : Monitor& operator=(const T& value)
93 : {
94 830622 : set(value);
95 830632 : 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 830622 : T set(const T& value)
125 : {
126 1661254 : std::unique_lock<std::mutex> lock(_mutex);
127 830624 : const T old = _value;
128 830624 : _value = value;
129 830624 : _condition.notify_all();
130 1661264 : 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 1199961 : 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 32307 : 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 79715 : 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 61227 : const T waitLE(const T& value) const
184 : {
185 199372 : 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 81465 : 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 79400 : 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 1278 : bool timedWaitGE(const T& value, const uint32_t timeout) const
242 : {
243 60315 : 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 1346 : bool timedWaitLE(const T& value, const uint32_t timeout) const
254 : {
255 63896 : 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 1324 : bool timedWaitGT(const T& value, const uint32_t timeout) const
266 : {
267 61694 : 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 1377 : bool timedWaitLT(const T& value, const uint32_t timeout) const
278 : {
279 64369 : 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 184008 : bool operator!=(const T& value) const
292 : {
293 368016 : std::unique_lock<std::mutex> lock(_mutex);
294 368016 : 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 475532 : const T _wait(const F& predicate) const
390 : {
391 951064 : std::unique_lock<std::mutex> lock(_mutex);
392 475532 : _condition.wait(lock, predicate);
393 951064 : return _value;
394 : }
395 :
396 : template <typename F>
397 5325 : bool _timedWait(const F& predicate, const uint32_t timeout) const
398 : {
399 10650 : std::unique_lock<std::mutex> lock(_mutex);
400 : return _condition.wait_for(lock, std::chrono::milliseconds(timeout),
401 10650 : 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
|