]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - include/lldb/Host/Predicate.h
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / include / lldb / Host / Predicate.h
1 //===-- Predicate.h ---------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #ifndef liblldb_Predicate_h_
11 #define liblldb_Predicate_h_
12
13 // C Includes
14 #include <stdint.h>
15 #include <time.h>
16
17 // C++ Includes
18 #include <condition_variable>
19 #include <mutex>
20
21 // Other libraries and framework includes
22 // Project includes
23 #include "lldb/lldb-defines.h"
24
25 //#define DB_PTHREAD_LOG_EVENTS
26
27 //----------------------------------------------------------------------
28 /// Enumerations for broadcasting.
29 //----------------------------------------------------------------------
30 namespace lldb_private {
31
32 typedef enum {
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
36                      ///modified.
37 } PredicateBroadcastType;
38
39 //----------------------------------------------------------------------
40 /// @class Predicate Predicate.h "lldb/Host/Predicate.h"
41 /// @brief A C++ wrapper class for providing threaded access to a value
42 /// of type T.
43 ///
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
47 /// specified values.
48 //----------------------------------------------------------------------
49 template <class T> class Predicate {
50 public:
51   //------------------------------------------------------------------
52   /// Default constructor.
53   ///
54   /// Initializes the mutex, condition and value with their default
55   /// constructors.
56   //------------------------------------------------------------------
57   Predicate() : m_value(), m_mutex(), m_condition() {}
58
59   //------------------------------------------------------------------
60   /// Construct with initial T value \a initial_value.
61   ///
62   /// Initializes the mutex and condition with their default
63   /// constructors, and initializes the value with \a initial_value.
64   ///
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() {}
70
71   //------------------------------------------------------------------
72   /// Destructor.
73   ///
74   /// Destroy the condition, mutex, and T objects.
75   //------------------------------------------------------------------
76   ~Predicate() = default;
77
78   //------------------------------------------------------------------
79   /// Value get accessor.
80   ///
81   /// Copies the current \a m_value in a thread safe manor and returns
82   /// the copied value.
83   ///
84   /// @return
85   ///     A copy of the current value.
86   //------------------------------------------------------------------
87   T GetValue() const {
88     std::lock_guard<std::mutex> guard(m_mutex);
89     T value = m_value;
90     return value;
91   }
92
93   //------------------------------------------------------------------
94   /// Value set accessor.
95   ///
96   /// Set the contained \a m_value to \a new_value in a thread safe
97   /// way and broadcast if needed.
98   ///
99   /// @param[in] value
100   ///     The new value to set.
101   ///
102   /// @param[in] broadcast_type
103   ///     A value indicating when and if to broadcast. See the
104   ///     PredicateBroadcastType enumeration for details.
105   ///
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,
112            broadcast_type);
113 #endif
114     const T old_value = m_value;
115     m_value = value;
116
117     Broadcast(old_value, broadcast_type);
118   }
119
120   //------------------------------------------------------------------
121   /// Set some bits in \a m_value.
122   ///
123   /// Logically set the bits \a bits in the contained \a m_value in a
124   /// thread safe way and broadcast if needed.
125   ///
126   /// @param[in] bits
127   ///     The bits to set in \a m_value.
128   ///
129   /// @param[in] broadcast_type
130   ///     A value indicating when and if to broadcast. See the
131   ///     PredicateBroadcastType enumeration for details.
132   ///
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,
139            broadcast_type);
140 #endif
141     const T old_value = m_value;
142     m_value |= bits;
143
144     Broadcast(old_value, broadcast_type);
145   }
146
147   //------------------------------------------------------------------
148   /// Reset some bits in \a m_value.
149   ///
150   /// Logically reset (clear) the bits \a bits in the contained
151   /// \a m_value in a thread safe way and broadcast if needed.
152   ///
153   /// @param[in] bits
154   ///     The bits to clear in \a m_value.
155   ///
156   /// @param[in] broadcast_type
157   ///     A value indicating when and if to broadcast. See the
158   ///     PredicateBroadcastType enumeration for details.
159   ///
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,
166            broadcast_type);
167 #endif
168     const T old_value = m_value;
169     m_value &= ~bits;
170
171     Broadcast(old_value, broadcast_type);
172   }
173
174   //------------------------------------------------------------------
175   /// Wait for bits to be set in \a m_value.
176   ///
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.
180   ///
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.
187   ///
188   /// @param[in] bits
189   ///     The bits we are waiting to be set in \a m_value.
190   ///
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.
194   ///
195   /// @return
196   ///     Any bits of the requested bits that actually were set within
197   ///     the time specified. Zero if a timeout or unrecoverable error
198   ///     occurred.
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);
211 #endif
212     while ((m_value & bits) == 0) {
213       if (timeout == std::chrono::microseconds(0)) {
214         m_condition.wait(lock);
215       } else {
216         std::cv_status result = m_condition.wait_for(lock, timeout);
217         if (result == std::cv_status::timeout)
218           break;
219       }
220     }
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);
224 #endif
225
226     return m_value & bits;
227   }
228
229   //------------------------------------------------------------------
230   /// Wait for bits to be reset in \a m_value.
231   ///
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.
235   ///
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.
242   ///
243   /// @param[in] bits
244   ///     The bits we are waiting to be reset in \a m_value.
245   ///
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.
249   ///
250   /// @return
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);
262
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);
266 #endif
267     while ((m_value & bits) != 0) {
268       if (timeout == std::chrono::microseconds(0)) {
269         m_condition.wait(lock);
270       } else {
271         std::cv_status result = m_condition.wait_for(lock, timeout);
272         if (result == std::cv_status::timeout)
273           break;
274       }
275     }
276
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);
280 #endif
281     return m_value & bits;
282   }
283
284   //------------------------------------------------------------------
285   /// Wait for \a m_value to be equal to \a value.
286   ///
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.
290   ///
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.
297   ///
298   /// @param[in] value
299   ///     The value we want \a m_value to be equal to.
300   ///
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.
304   ///
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.
308   ///
309   /// @return
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);
322
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);
326 #endif
327     if (timed_out)
328       *timed_out = false;
329
330     while (m_value != value) {
331       if (timeout == std::chrono::microseconds(0)) {
332         m_condition.wait(lock);
333       } else {
334         std::cv_status result = m_condition.wait_for(lock, timeout);
335         if (result == std::cv_status::timeout) {
336           if (timed_out)
337             *timed_out = true;
338           break;
339         }
340       }
341     }
342
343     return m_value == value;
344   }
345
346   //------------------------------------------------------------------
347   /// Wait for \a m_value to be equal to \a value and then set it to
348   /// a new value.
349   ///
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.
354   ///
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.
361   ///
362   /// @param[in] value
363   ///     The value we want \a m_value to be equal to.
364   ///
365   /// @param[in] new_value
366   ///     The value to which \a m_value will be set if \b true is
367   ///     returned.
368   ///
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.
372   ///
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.
376   ///
377   /// @return
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);
391
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);
396 #endif
397     if (timed_out)
398       *timed_out = false;
399
400     while (m_value != wait_value) {
401       if (timeout == std::chrono::microseconds(0)) {
402         m_condition.wait(lock);
403       } else {
404         std::cv_status result = m_condition.wait_for(lock, timeout);
405         if (result == std::cv_status::timeout) {
406           if (timed_out)
407             *timed_out = true;
408           break;
409         }
410       }
411     }
412
413     if (m_value == wait_value) {
414       m_value = new_value;
415       return true;
416     }
417
418     return false;
419   }
420
421   //------------------------------------------------------------------
422   /// Wait for \a m_value to not be equal to \a value.
423   ///
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.
427   ///
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.
434   ///
435   /// @param[in] value
436   ///     The value we want \a m_value to not be equal to.
437   ///
438   /// @param[out] new_value
439   ///     The new value if \b true is returned.
440   ///
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.
444   ///
445   /// @return
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);
461 #endif
462     while (m_value == value) {
463       if (timeout == std::chrono::microseconds(0)) {
464         m_condition.wait(lock);
465       } else {
466         std::cv_status result = m_condition.wait_for(lock, timeout);
467         if (result == std::cv_status::timeout)
468           break;
469       }
470     }
471
472     if (m_value != value) {
473       new_value = m_value;
474       return true;
475     }
476     return false;
477   }
478
479 protected:
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
488                                        ///or changed.
489
490 private:
491   //------------------------------------------------------------------
492   /// Broadcast if needed.
493   ///
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.
496   ///
497   /// If \a broadcast_type is eBroadcastNever, no broadcast will be
498   /// sent.
499   ///
500   /// If \a broadcast_type is eBroadcastAlways, the condition variable
501   /// will always be broadcast.
502   ///
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) {
507     bool broadcast =
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, "
512            "broadcast = %u\n",
513            __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
514 #endif
515     if (broadcast)
516       m_condition.notify_all();
517   }
518
519   DISALLOW_COPY_AND_ASSIGN(Predicate);
520 };
521
522 } // namespace lldb_private
523
524 #endif // liblldb_Predicate_h_