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#if defined(__cplusplus)
13
14#include "lldb/Host/Mutex.h"
15#include "lldb/Host/Condition.h"
16#include <stdint.h>
17#include <time.h>
18
19//#define DB_PTHREAD_LOG_EVENTS
20
21//----------------------------------------------------------------------
22/// Enumerations for broadcasting.
23//----------------------------------------------------------------------
24namespace lldb_private {
25
26typedef enum
27{
28    eBroadcastNever,    ///< No broadcast will be sent when the value is modified.
29    eBroadcastAlways,   ///< Always send a broadcast when the value is modified.
30    eBroadcastOnChange  ///< Only broadcast if the value changes when the value is modified.
31
32} PredicateBroadcastType;
33
34//----------------------------------------------------------------------
35/// @class Predicate Predicate.h "lldb/Host/Predicate.h"
36/// @brief A C++ wrapper class for providing threaded access to a value
37/// of type T.
38///
39/// A templatized class that provides multi-threaded access to a value
40/// of type T. Threads can efficiently wait for bits within T to be set
41/// or reset, or wait for T to be set to be equal/not equal to a
42/// specified values.
43//----------------------------------------------------------------------
44template <class T>
45class Predicate
46{
47public:
48
49    //------------------------------------------------------------------
50    /// Default constructor.
51    ///
52    /// Initializes the mutex, condition and value with their default
53    /// constructors.
54    //------------------------------------------------------------------
55    Predicate () :
56        m_value(),
57        m_mutex(),
58        m_condition()
59    {
60    }
61
62    //------------------------------------------------------------------
63    /// Construct with initial T value \a initial_value.
64    ///
65    /// Initializes the mutex and condition with their default
66    /// constructors, and initializes the value with \a initial_value.
67    ///
68    /// @param[in] initial_value
69    ///     The initial value for our T object.
70    //------------------------------------------------------------------
71    Predicate (T initial_value)  :
72        m_value(initial_value),
73        m_mutex(),
74        m_condition()
75    {
76    }
77
78    //------------------------------------------------------------------
79    /// Destructor.
80    ///
81    /// Destrory the condition, mutex, and T objects.
82    //------------------------------------------------------------------
83    ~Predicate ()
84    {
85    }
86
87
88    //------------------------------------------------------------------
89    /// Value get accessor.
90    ///
91    /// Copies the current \a m_value in a thread safe manor and returns
92    /// the copied value.
93    ///
94    /// @return
95    ///     A copy of the current value.
96    //------------------------------------------------------------------
97    T
98    GetValue () const
99    {
100        Mutex::Locker locker(m_mutex);
101        T value = m_value;
102        return value;
103    }
104
105    //------------------------------------------------------------------
106    /// Value set accessor.
107    ///
108    /// Set the contained \a m_value to \a new_value in a thread safe
109    /// way and broadcast if needed.
110    ///
111    /// @param[in] value
112    ///     The new value to set.
113    ///
114    /// @param[in] broadcast_type
115    ///     A value indicating when and if to broadast. See the
116    ///     PredicateBroadcastType enumeration for details.
117    ///
118    /// @see Predicate::Broadcast()
119    //------------------------------------------------------------------
120    void
121    SetValue (T value, PredicateBroadcastType broadcast_type)
122    {
123        Mutex::Locker locker(m_mutex);
124#ifdef DB_PTHREAD_LOG_EVENTS
125        printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, broadcast_type);
126#endif
127        const T old_value = m_value;
128        m_value = value;
129
130        Broadcast(old_value, broadcast_type);
131    }
132
133    //------------------------------------------------------------------
134    /// Set some bits in \a m_value.
135    ///
136    /// Logically set the bits \a bits in the contained \a m_value in a
137    /// thread safe way and broadcast if needed.
138    ///
139    /// @param[in] bits
140    ///     The bits to set in \a m_value.
141    ///
142    /// @param[in] broadcast_type
143    ///     A value indicating when and if to broadast. See the
144    ///     PredicateBroadcastType enumeration for details.
145    ///
146    /// @see Predicate::Broadcast()
147    //------------------------------------------------------------------
148    void
149    SetValueBits (T bits, PredicateBroadcastType broadcast_type)
150    {
151        Mutex::Locker locker(m_mutex);
152#ifdef DB_PTHREAD_LOG_EVENTS
153        printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type);
154#endif
155        const T old_value = m_value;
156        m_value |= bits;
157
158        Broadcast(old_value, broadcast_type);
159    }
160
161    //------------------------------------------------------------------
162    /// Reset some bits in \a m_value.
163    ///
164    /// Logically reset (clear) the bits \a bits in the contained
165    /// \a m_value in a thread safe way and broadcast if needed.
166    ///
167    /// @param[in] bits
168    ///     The bits to clear in \a m_value.
169    ///
170    /// @param[in] broadcast_type
171    ///     A value indicating when and if to broadast. See the
172    ///     PredicateBroadcastType enumeration for details.
173    ///
174    /// @see Predicate::Broadcast()
175    //------------------------------------------------------------------
176    void
177    ResetValueBits (T bits, PredicateBroadcastType broadcast_type)
178    {
179        Mutex::Locker locker(m_mutex);
180#ifdef DB_PTHREAD_LOG_EVENTS
181        printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type);
182#endif
183        const T old_value = m_value;
184        m_value &= ~bits;
185
186        Broadcast(old_value, broadcast_type);
187    }
188
189    //------------------------------------------------------------------
190    /// Wait for bits to be set in \a m_value.
191    ///
192    /// Waits in a thread safe way for any bits in \a bits to get
193    /// logically set in \a m_value. If any bits are already set in
194    /// \a m_value, this function will return without waiting.
195    ///
196    /// It is possible for the value to be changed between the time
197    /// the bits are set and the time the waiting thread wakes up.
198    /// If the bits are no longer set when the waiting thread wakes
199    /// up, it will go back into a wait state.  It may be necessary
200    /// for the calling code to use additional thread synchronization
201    /// methods to detect transitory states.
202    ///
203    /// @param[in] bits
204    ///     The bits we are waiting to be set in \a m_value.
205    ///
206    /// @param[in] abstime
207    ///     If non-NULL, the absolute time at which we should stop
208    ///     waiting, else wait an infinite amount of time.
209    ///
210    /// @return
211    ///     Any bits of the requested bits that actually were set within
212    ///     the time specified. Zero if a timeout or unrecoverable error
213    ///     occurred.
214    //------------------------------------------------------------------
215    T
216    WaitForSetValueBits (T bits, const TimeValue *abstime = NULL)
217    {
218        int err = 0;
219        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
220        // unlock the mutex and wait for the condition to be set. When either
221        // function returns, they will re-lock the mutex. We use an auto lock/unlock
222        // class (Mutex::Locker) to allow us to return at any point in this
223        // function and not have to worry about unlocking the mutex.
224        Mutex::Locker locker(m_mutex);
225#ifdef DB_PTHREAD_LOG_EVENTS
226        printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value);
227#endif
228        while (err == 0 && ((m_value & bits) == 0))
229        {
230            err = m_condition.Wait (m_mutex, abstime);
231        }
232#ifdef DB_PTHREAD_LOG_EVENTS
233        printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits);
234#endif
235
236        return m_value & bits;
237    }
238
239    //------------------------------------------------------------------
240    /// Wait for bits to be reset in \a m_value.
241    ///
242    /// Waits in a thread safe way for any bits in \a bits to get
243    /// logically reset in \a m_value. If all bits are already reset in
244    /// \a m_value, this function will return without waiting.
245    ///
246    /// It is possible for the value to be changed between the time
247    /// the bits are reset and the time the waiting thread wakes up.
248    /// If the bits are no set when the waiting thread wakes up, it will
249    /// go back into a wait state.  It may be necessary for the calling
250    /// code to use additional thread synchronization methods to detect
251    /// transitory states.
252    ///
253    /// @param[in] bits
254    ///     The bits we are waiting to be reset in \a m_value.
255    ///
256    /// @param[in] abstime
257    ///     If non-NULL, the absolute time at which we should stop
258    ///     waiting, else wait an infinite amount of time.
259    ///
260    /// @return
261    ///     Zero on successful waits, or non-zero if a timeout or
262    ///     unrecoverable error occurs.
263    //------------------------------------------------------------------
264    T
265    WaitForResetValueBits (T bits, const TimeValue *abstime = NULL)
266    {
267        int err = 0;
268
269        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
270        // unlock the mutex and wait for the condition to be set. When either
271        // function returns, they will re-lock the mutex. We use an auto lock/unlock
272        // class (Mutex::Locker) to allow us to return at any point in this
273        // function and not have to worry about unlocking the mutex.
274        Mutex::Locker locker(m_mutex);
275
276#ifdef DB_PTHREAD_LOG_EVENTS
277        printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value);
278#endif
279        while (err == 0 && ((m_value & bits) != 0))
280        {
281            err = m_condition.Wait (m_mutex, abstime);
282        }
283
284#ifdef DB_PTHREAD_LOG_EVENTS
285        printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits);
286#endif
287        return m_value & bits;
288    }
289
290    //------------------------------------------------------------------
291    /// Wait for \a m_value to be equal to \a value.
292    ///
293    /// Waits in a thread safe way for \a m_value to be equal to \a
294    /// value. If \a m_value is already equal to \a value, this
295    /// function will return without waiting.
296    ///
297    /// It is possible for the value to be changed between the time
298    /// the value is set and the time the waiting thread wakes up.
299    /// If the value no longer matches the requested value when the
300    /// waiting thread wakes up, it will go back into a wait state.  It
301    /// may be necessary for the calling code to use additional thread
302    /// synchronization methods to detect transitory states.
303    ///
304    /// @param[in] value
305    ///     The value we want \a m_value to be equal to.
306    ///
307    /// @param[in] abstime
308    ///     If non-NULL, the absolute time at which we should stop
309    ///     waiting, else wait an infinite amount of time.
310    ///
311    /// @param[out] timed_out
312    ///     If not null, set to true if we return because of a time out,
313    ///     and false if the value was set.
314    ///
315    /// @return
316    ///     @li \b true if the \a m_value is equal to \a value
317    ///     @li \b false otherwise
318    //------------------------------------------------------------------
319    bool
320    WaitForValueEqualTo (T value, const TimeValue *abstime = NULL, bool *timed_out = NULL)
321    {
322        int err = 0;
323        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
324        // unlock the mutex and wait for the condition to be set. When either
325        // function returns, they will re-lock the mutex. We use an auto lock/unlock
326        // class (Mutex::Locker) to allow us to return at any point in this
327        // function and not have to worry about unlocking the mutex.
328        Mutex::Locker locker(m_mutex);
329
330#ifdef DB_PTHREAD_LOG_EVENTS
331        printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value);
332#endif
333        if (timed_out)
334            *timed_out = false;
335
336        while (err == 0 && m_value != value)
337        {
338            err = m_condition.Wait (m_mutex, abstime, timed_out);
339        }
340
341        return m_value == value;
342    }
343
344    //------------------------------------------------------------------
345    /// Wait for \a m_value to be equal to \a value and then set it to
346    /// a new value.
347    ///
348    /// Waits in a thread safe way for \a m_value to be equal to \a
349    /// value and then sets \a m_value to \a new_value. If \a m_value
350    /// is already equal to \a value, this function will immediately
351    /// set \a m_value to \a new_value and return without waiting.
352    ///
353    /// It is possible for the value to be changed between the time
354    /// the value is set and the time the waiting thread wakes up.
355    /// If the value no longer matches the requested value when the
356    /// waiting thread wakes up, it will go back into a wait state.  It
357    /// may be necessary for the calling code to use additional thread
358    /// synchronization methods to detect transitory states.
359    ///
360    /// @param[in] value
361    ///     The value we want \a m_value to be equal to.
362    ///
363    /// @param[in] new_value
364    ///     The value to which \a m_value will be set if \b true is
365    ///     returned.
366    ///
367    /// @param[in] abstime
368    ///     If non-NULL, the absolute time at which we should stop
369    ///     waiting, else wait an infinite amount of time.
370    ///
371    /// @param[out] timed_out
372    ///     If not null, set to true if we return because of a time out,
373    ///     and false if the value was set.
374    ///
375    /// @return
376    ///     @li \b true if the \a m_value became equal to \a value
377    ///     @li \b false otherwise
378    //------------------------------------------------------------------
379    bool
380    WaitForValueEqualToAndSetValueTo (T wait_value, T new_value, const TimeValue *abstime = NULL, bool *timed_out = NULL)
381    {
382        int err = 0;
383        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
384        // unlock the mutex and wait for the condition to be set. When either
385        // function returns, they will re-lock the mutex. We use an auto lock/unlock
386        // class (Mutex::Locker) to allow us to return at any point in this
387        // function and not have to worry about unlocking the mutex.
388        Mutex::Locker locker(m_mutex);
389
390#ifdef DB_PTHREAD_LOG_EVENTS
391        printf("%s (wait_value = 0x%8.8x, new_value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, wait_value, new_value, abstime, m_value);
392#endif
393        if (timed_out)
394            *timed_out = false;
395
396        while (err == 0 && m_value != wait_value)
397        {
398            err = m_condition.Wait (m_mutex, abstime, timed_out);
399        }
400
401        if (m_value == wait_value)
402        {
403            m_value = new_value;
404            return true;
405        }
406
407        return false;
408    }
409
410
411    //------------------------------------------------------------------
412    /// Wait for \a m_value to not be equal to \a value.
413    ///
414    /// Waits in a thread safe way for \a m_value to not be equal to \a
415    /// value. If \a m_value is already not equal to \a value, this
416    /// function will return without waiting.
417    ///
418    /// It is possible for the value to be changed between the time
419    /// the value is set and the time the waiting thread wakes up.
420    /// If the value is equal to the test value when the waiting thread
421    /// wakes up, it will go back into a wait state.  It may be
422    /// necessary for the calling code to use additional thread
423    /// synchronization methods to detect transitory states.
424    ///
425    /// @param[in] value
426    ///     The value we want \a m_value to not be equal to.
427    ///
428    /// @param[out] new_value
429    ///     The new value if \b true is returned.
430    ///
431    /// @param[in] abstime
432    ///     If non-NULL, the absolute time at which we should stop
433    ///     waiting, else wait an infinite amount of time.
434    ///
435    /// @return
436    ///     @li \b true if the \a m_value is equal to \a value
437    ///     @li \b false otherwise
438    //------------------------------------------------------------------
439    bool
440    WaitForValueNotEqualTo (T value, T &new_value, const TimeValue *abstime = NULL)
441    {
442        int err = 0;
443        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
444        // unlock the mutex and wait for the condition to be set. When either
445        // function returns, they will re-lock the mutex. We use an auto lock/unlock
446        // class (Mutex::Locker) to allow us to return at any point in this
447        // function and not have to worry about unlocking the mutex.
448        Mutex::Locker locker(m_mutex);
449#ifdef DB_PTHREAD_LOG_EVENTS
450        printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value);
451#endif
452        while (err == 0 && m_value == value)
453        {
454            err = m_condition.Wait (m_mutex, abstime);
455        }
456
457        if (m_value != value)
458        {
459            new_value = m_value;
460            return true;
461        }
462        return false;
463    }
464
465protected:
466    //----------------------------------------------------------------------
467    // pthread condition and mutex variable to controll access and allow
468    // blocking between the main thread and the spotlight index thread.
469    //----------------------------------------------------------------------
470    T           m_value;        ///< The templatized value T that we are protecting access to
471    mutable Mutex m_mutex;      ///< The mutex to use when accessing the data
472    Condition   m_condition;    ///< The pthread condition variable to use for signaling that data available or changed.
473
474private:
475
476    //------------------------------------------------------------------
477    /// Broadcast if needed.
478    ///
479    /// Check to see if we need to broadcast to our condition variable
480    /// depedning on the \a old_value and on the \a broadcast_type.
481    ///
482    /// If \a broadcast_type is eBroadcastNever, no broadcast will be
483    /// sent.
484    ///
485    /// If \a broadcast_type is eBroadcastAlways, the condition variable
486    /// will always be broadcast.
487    ///
488    /// If \a broadcast_type is eBroadcastOnChange, the condition
489    /// variable be broadcast if the owned value changes.
490    //------------------------------------------------------------------
491    void
492    Broadcast (T old_value, PredicateBroadcastType broadcast_type)
493    {
494        bool broadcast = (broadcast_type == eBroadcastAlways) || ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
495#ifdef DB_PTHREAD_LOG_EVENTS
496        printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, broadcast = %u\n", __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
497#endif
498        if (broadcast)
499            m_condition.Broadcast();
500    }
501
502
503    DISALLOW_COPY_AND_ASSIGN(Predicate);
504};
505
506} // namespace lldb_private
507
508#endif  // #if defined(__cplusplus)
509#endif // #ifndef liblldb_Predicate_h_
510