1 //===-- Predicate.h ---------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef liblldb_Predicate_h_
11 #define liblldb_Predicate_h_
18 #include <condition_variable>
21 // Other libraries and framework includes
23 #include "lldb/lldb-defines.h"
25 //#define DB_PTHREAD_LOG_EVENTS
27 //----------------------------------------------------------------------
28 /// Enumerations for broadcasting.
29 //----------------------------------------------------------------------
30 namespace lldb_private {
33 eBroadcastNever, ///< No broadcast will be sent when the value is modified.
34 eBroadcastAlways, ///< Always send a broadcast when the value is modified.
35 eBroadcastOnChange ///< Only broadcast if the value changes when the value is
37 } PredicateBroadcastType;
39 //----------------------------------------------------------------------
40 /// @class Predicate Predicate.h "lldb/Host/Predicate.h"
41 /// @brief A C++ wrapper class for providing threaded access to a value
44 /// A templatized class that provides multi-threaded access to a value
45 /// of type T. Threads can efficiently wait for bits within T to be set
46 /// or reset, or wait for T to be set to be equal/not equal to a
48 //----------------------------------------------------------------------
49 template <class T> class Predicate {
51 //------------------------------------------------------------------
52 /// Default constructor.
54 /// Initializes the mutex, condition and value with their default
56 //------------------------------------------------------------------
57 Predicate() : m_value(), m_mutex(), m_condition() {}
59 //------------------------------------------------------------------
60 /// Construct with initial T value \a initial_value.
62 /// Initializes the mutex and condition with their default
63 /// constructors, and initializes the value with \a initial_value.
65 /// @param[in] initial_value
66 /// The initial value for our T object.
67 //------------------------------------------------------------------
68 Predicate(T initial_value)
69 : m_value(initial_value), m_mutex(), m_condition() {}
71 //------------------------------------------------------------------
74 /// Destroy the condition, mutex, and T objects.
75 //------------------------------------------------------------------
76 ~Predicate() = default;
78 //------------------------------------------------------------------
79 /// Value get accessor.
81 /// Copies the current \a m_value in a thread safe manor and returns
85 /// A copy of the current value.
86 //------------------------------------------------------------------
88 std::lock_guard<std::mutex> guard(m_mutex);
93 //------------------------------------------------------------------
94 /// Value set accessor.
96 /// Set the contained \a m_value to \a new_value in a thread safe
97 /// way and broadcast if needed.
100 /// The new value to set.
102 /// @param[in] broadcast_type
103 /// A value indicating when and if to broadcast. See the
104 /// PredicateBroadcastType enumeration for details.
106 /// @see Predicate::Broadcast()
107 //------------------------------------------------------------------
108 void SetValue(T value, PredicateBroadcastType broadcast_type) {
109 std::lock_guard<std::mutex> guard(m_mutex);
110 #ifdef DB_PTHREAD_LOG_EVENTS
111 printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value,
114 const T old_value = m_value;
117 Broadcast(old_value, broadcast_type);
120 //------------------------------------------------------------------
121 /// Set some bits in \a m_value.
123 /// Logically set the bits \a bits in the contained \a m_value in a
124 /// thread safe way and broadcast if needed.
127 /// The bits to set in \a m_value.
129 /// @param[in] broadcast_type
130 /// A value indicating when and if to broadcast. See the
131 /// PredicateBroadcastType enumeration for details.
133 /// @see Predicate::Broadcast()
134 //------------------------------------------------------------------
135 void SetValueBits(T bits, PredicateBroadcastType broadcast_type) {
136 std::lock_guard<std::mutex> guard(m_mutex);
137 #ifdef DB_PTHREAD_LOG_EVENTS
138 printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits,
141 const T old_value = m_value;
144 Broadcast(old_value, broadcast_type);
147 //------------------------------------------------------------------
148 /// Reset some bits in \a m_value.
150 /// Logically reset (clear) the bits \a bits in the contained
151 /// \a m_value in a thread safe way and broadcast if needed.
154 /// The bits to clear in \a m_value.
156 /// @param[in] broadcast_type
157 /// A value indicating when and if to broadcast. See the
158 /// PredicateBroadcastType enumeration for details.
160 /// @see Predicate::Broadcast()
161 //------------------------------------------------------------------
162 void ResetValueBits(T bits, PredicateBroadcastType broadcast_type) {
163 std::lock_guard<std::mutex> guard(m_mutex);
164 #ifdef DB_PTHREAD_LOG_EVENTS
165 printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits,
168 const T old_value = m_value;
171 Broadcast(old_value, broadcast_type);
174 //------------------------------------------------------------------
175 /// Wait for bits to be set in \a m_value.
177 /// Waits in a thread safe way for any bits in \a bits to get
178 /// logically set in \a m_value. If any bits are already set in
179 /// \a m_value, this function will return without waiting.
181 /// It is possible for the value to be changed between the time
182 /// the bits are set and the time the waiting thread wakes up.
183 /// If the bits are no longer set when the waiting thread wakes
184 /// up, it will go back into a wait state. It may be necessary
185 /// for the calling code to use additional thread synchronization
186 /// methods to detect transitory states.
189 /// The bits we are waiting to be set in \a m_value.
191 /// @param[in] abstime
192 /// If non-nullptr, the absolute time at which we should stop
193 /// waiting, else wait an infinite amount of time.
196 /// Any bits of the requested bits that actually were set within
197 /// the time specified. Zero if a timeout or unrecoverable error
199 //------------------------------------------------------------------
200 T WaitForSetValueBits(T bits, const std::chrono::microseconds &timeout =
201 std::chrono::microseconds(0)) {
202 // pthread_cond_timedwait() or pthread_cond_wait() will atomically
203 // unlock the mutex and wait for the condition to be set. When either
204 // function returns, they will re-lock the mutex. We use an auto lock/unlock
205 // class (std::lock_guard) to allow us to return at any point in this
206 // function and not have to worry about unlocking the mutex.
207 std::unique_lock<std::mutex> lock(m_mutex);
208 #ifdef DB_PTHREAD_LOG_EVENTS
209 printf("%s (bits = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n",
210 __FUNCTION__, bits, timeout.count(), m_value);
212 while ((m_value & bits) == 0) {
213 if (timeout == std::chrono::microseconds(0)) {
214 m_condition.wait(lock);
216 std::cv_status result = m_condition.wait_for(lock, timeout);
217 if (result == std::cv_status::timeout)
221 #ifdef DB_PTHREAD_LOG_EVENTS
222 printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n",
223 __FUNCTION__, bits, m_value, m_value & bits);
226 return m_value & bits;
229 //------------------------------------------------------------------
230 /// Wait for bits to be reset in \a m_value.
232 /// Waits in a thread safe way for any bits in \a bits to get
233 /// logically reset in \a m_value. If all bits are already reset in
234 /// \a m_value, this function will return without waiting.
236 /// It is possible for the value to be changed between the time
237 /// the bits are reset and the time the waiting thread wakes up.
238 /// If the bits are no set when the waiting thread wakes up, it will
239 /// go back into a wait state. It may be necessary for the calling
240 /// code to use additional thread synchronization methods to detect
241 /// transitory states.
244 /// The bits we are waiting to be reset in \a m_value.
246 /// @param[in] abstime
247 /// If non-nullptr, the absolute time at which we should stop
248 /// waiting, else wait an infinite amount of time.
251 /// Zero on successful waits, or non-zero if a timeout or
252 /// unrecoverable error occurs.
253 //------------------------------------------------------------------
254 T WaitForResetValueBits(T bits, const std::chrono::microseconds &timeout =
255 std::chrono::microseconds(0)) {
256 // pthread_cond_timedwait() or pthread_cond_wait() will atomically
257 // unlock the mutex and wait for the condition to be set. When either
258 // function returns, they will re-lock the mutex. We use an auto lock/unlock
259 // class (std::lock_guard) to allow us to return at any point in this
260 // function and not have to worry about unlocking the mutex.
261 std::unique_lock<std::mutex> lock(m_mutex);
263 #ifdef DB_PTHREAD_LOG_EVENTS
264 printf("%s (bits = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n",
265 __FUNCTION__, bits, timeout.count(), m_value);
267 while ((m_value & bits) != 0) {
268 if (timeout == std::chrono::microseconds(0)) {
269 m_condition.wait(lock);
271 std::cv_status result = m_condition.wait_for(lock, timeout);
272 if (result == std::cv_status::timeout)
277 #ifdef DB_PTHREAD_LOG_EVENTS
278 printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n",
279 __FUNCTION__, bits, m_value, m_value & bits);
281 return m_value & bits;
284 //------------------------------------------------------------------
285 /// Wait for \a m_value to be equal to \a value.
287 /// Waits in a thread safe way for \a m_value to be equal to \a
288 /// value. If \a m_value is already equal to \a value, this
289 /// function will return without waiting.
291 /// It is possible for the value to be changed between the time
292 /// the value is set and the time the waiting thread wakes up.
293 /// If the value no longer matches the requested value when the
294 /// waiting thread wakes up, it will go back into a wait state. It
295 /// may be necessary for the calling code to use additional thread
296 /// synchronization methods to detect transitory states.
299 /// The value we want \a m_value to be equal to.
301 /// @param[in] abstime
302 /// If non-nullptr, the absolute time at which we should stop
303 /// waiting, else wait an infinite amount of time.
305 /// @param[out] timed_out
306 /// If not null, set to true if we return because of a time out,
307 /// and false if the value was set.
310 /// @li \b true if the \a m_value is equal to \a value
311 /// @li \b false otherwise
312 //------------------------------------------------------------------
313 bool WaitForValueEqualTo(T value, const std::chrono::microseconds &timeout =
314 std::chrono::microseconds(0),
315 bool *timed_out = nullptr) {
316 // pthread_cond_timedwait() or pthread_cond_wait() will atomically
317 // unlock the mutex and wait for the condition to be set. When either
318 // function returns, they will re-lock the mutex. We use an auto lock/unlock
319 // class (std::lock_guard) to allow us to return at any point in this
320 // function and not have to worry about unlocking the mutex.
321 std::unique_lock<std::mutex> lock(m_mutex);
323 #ifdef DB_PTHREAD_LOG_EVENTS
324 printf("%s (value = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n",
325 __FUNCTION__, value, timeout.count(), m_value);
330 while (m_value != value) {
331 if (timeout == std::chrono::microseconds(0)) {
332 m_condition.wait(lock);
334 std::cv_status result = m_condition.wait_for(lock, timeout);
335 if (result == std::cv_status::timeout) {
343 return m_value == value;
346 //------------------------------------------------------------------
347 /// Wait for \a m_value to be equal to \a value and then set it to
350 /// Waits in a thread safe way for \a m_value to be equal to \a
351 /// value and then sets \a m_value to \a new_value. If \a m_value
352 /// is already equal to \a value, this function will immediately
353 /// set \a m_value to \a new_value and return without waiting.
355 /// It is possible for the value to be changed between the time
356 /// the value is set and the time the waiting thread wakes up.
357 /// If the value no longer matches the requested value when the
358 /// waiting thread wakes up, it will go back into a wait state. It
359 /// may be necessary for the calling code to use additional thread
360 /// synchronization methods to detect transitory states.
363 /// The value we want \a m_value to be equal to.
365 /// @param[in] new_value
366 /// The value to which \a m_value will be set if \b true is
369 /// @param[in] abstime
370 /// If non-nullptr, the absolute time at which we should stop
371 /// waiting, else wait an infinite amount of time.
373 /// @param[out] timed_out
374 /// If not null, set to true if we return because of a time out,
375 /// and false if the value was set.
378 /// @li \b true if the \a m_value became equal to \a value
379 /// @li \b false otherwise
380 //------------------------------------------------------------------
381 bool WaitForValueEqualToAndSetValueTo(
382 T wait_value, T new_value,
383 const std::chrono::microseconds &timeout = std::chrono::microseconds(0),
384 bool *timed_out = nullptr) {
385 // pthread_cond_timedwait() or pthread_cond_wait() will atomically
386 // unlock the mutex and wait for the condition to be set. When either
387 // function returns, they will re-lock the mutex. We use an auto lock/unlock
388 // class (std::lock_guard) to allow us to return at any point in this
389 // function and not have to worry about unlocking the mutex.
390 std::unique_lock<std::mutex> lock(m_mutex);
392 #ifdef DB_PTHREAD_LOG_EVENTS
393 printf("%s (wait_value = 0x%8.8x, new_value = 0x%8.8x, timeout = %llu), "
394 "m_value = 0x%8.8x\n",
395 __FUNCTION__, wait_value, new_value, timeout.count(), m_value);
400 while (m_value != wait_value) {
401 if (timeout == std::chrono::microseconds(0)) {
402 m_condition.wait(lock);
404 std::cv_status result = m_condition.wait_for(lock, timeout);
405 if (result == std::cv_status::timeout) {
413 if (m_value == wait_value) {
421 //------------------------------------------------------------------
422 /// Wait for \a m_value to not be equal to \a value.
424 /// Waits in a thread safe way for \a m_value to not be equal to \a
425 /// value. If \a m_value is already not equal to \a value, this
426 /// function will return without waiting.
428 /// It is possible for the value to be changed between the time
429 /// the value is set and the time the waiting thread wakes up.
430 /// If the value is equal to the test value when the waiting thread
431 /// wakes up, it will go back into a wait state. It may be
432 /// necessary for the calling code to use additional thread
433 /// synchronization methods to detect transitory states.
436 /// The value we want \a m_value to not be equal to.
438 /// @param[out] new_value
439 /// The new value if \b true is returned.
441 /// @param[in] abstime
442 /// If non-nullptr, the absolute time at which we should stop
443 /// waiting, else wait an infinite amount of time.
446 /// @li \b true if the \a m_value is equal to \a value
447 /// @li \b false otherwise
448 //------------------------------------------------------------------
449 bool WaitForValueNotEqualTo(
450 T value, T &new_value,
451 const std::chrono::microseconds &timeout = std::chrono::microseconds(0)) {
452 // pthread_cond_timedwait() or pthread_cond_wait() will atomically
453 // unlock the mutex and wait for the condition to be set. When either
454 // function returns, they will re-lock the mutex. We use an auto lock/unlock
455 // class (std::lock_guard) to allow us to return at any point in this
456 // function and not have to worry about unlocking the mutex.
457 std::unique_lock<std::mutex> lock(m_mutex);
458 #ifdef DB_PTHREAD_LOG_EVENTS
459 printf("%s (value = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n",
460 __FUNCTION__, value, timeout.count(), m_value);
462 while (m_value == value) {
463 if (timeout == std::chrono::microseconds(0)) {
464 m_condition.wait(lock);
466 std::cv_status result = m_condition.wait_for(lock, timeout);
467 if (result == std::cv_status::timeout)
472 if (m_value != value) {
480 //----------------------------------------------------------------------
481 // pthread condition and mutex variable to control access and allow
482 // blocking between the main thread and the spotlight index thread.
483 //----------------------------------------------------------------------
484 T m_value; ///< The templatized value T that we are protecting access to
485 mutable std::mutex m_mutex; ///< The mutex to use when accessing the data
486 std::condition_variable m_condition; ///< The pthread condition variable to
487 ///use for signaling that data available
491 //------------------------------------------------------------------
492 /// Broadcast if needed.
494 /// Check to see if we need to broadcast to our condition variable
495 /// depending on the \a old_value and on the \a broadcast_type.
497 /// If \a broadcast_type is eBroadcastNever, no broadcast will be
500 /// If \a broadcast_type is eBroadcastAlways, the condition variable
501 /// will always be broadcast.
503 /// If \a broadcast_type is eBroadcastOnChange, the condition
504 /// variable be broadcast if the owned value changes.
505 //------------------------------------------------------------------
506 void Broadcast(T old_value, PredicateBroadcastType broadcast_type) {
508 (broadcast_type == eBroadcastAlways) ||
509 ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
510 #ifdef DB_PTHREAD_LOG_EVENTS
511 printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, "
513 __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
516 m_condition.notify_all();
519 DISALLOW_COPY_AND_ASSIGN(Predicate);
522 } // namespace lldb_private
524 #endif // liblldb_Predicate_h_