Predicate.h revision 31ab22bfc055d8bd088ae4d8002ad281f929e60d
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)", __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)", __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)", __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    /// @param[in] bits
197    ///     The bits we are waiting to be set in \a m_value.
198    ///
199    /// @param[in] abstime
200    ///     If non-NULL, the absolute time at which we should stop
201    ///     waiting, else wait an infinite amount of time.
202    ///
203    /// @return
204    ///     Any bits of the requested bits that actually were set within
205    ///     the time specified. Zero if a timeout or unrecoverable error
206    ///     occurred.
207    //------------------------------------------------------------------
208    T
209    WaitForSetValueBits (T bits, const TimeValue *abstime = NULL)
210    {
211        int err = 0;
212        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
213        // unlock the mutex and wait for the condition to be set. When either
214        // function returns, they will re-lock the mutex. We use an auto lock/unlock
215        // class (Mutex::Locker) to allow us to return at any point in this
216        // function and not have to worry about unlocking the mutex.
217        Mutex::Locker locker(m_mutex);
218#ifdef DB_PTHREAD_LOG_EVENTS
219        printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, bits, abstime, m_value);
220#endif
221        while (err == 0 && ((m_value & bits) == 0))
222        {
223            err = m_condition.Wait (m_mutex.GetMutex(), abstime);
224        }
225#ifdef DB_PTHREAD_LOG_EVENTS
226        printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x", __FUNCTION__, bits, m_value, m_value & bits);
227#endif
228
229        return m_value & bits;
230    }
231
232    //------------------------------------------------------------------
233    /// Wait for bits to be reset in \a m_value.
234    ///
235    /// Waits in a thread safe way for any bits in \a bits to get
236    /// logically reset in \a m_value. If all bits are already reset in
237    /// \a m_value, this function will return without waiting.
238    ///
239    /// @param[in] bits
240    ///     The bits we are waiting to be reset in \a m_value.
241    ///
242    /// @param[in] abstime
243    ///     If non-NULL, the absolute time at which we should stop
244    ///     waiting, else wait an infinite amount of time.
245    ///
246    /// @return
247    ///     Zero on successful waits, or non-zero if a timeout or
248    ///     unrecoverable error occurs.
249    //------------------------------------------------------------------
250    T
251    WaitForResetValueBits (T bits, const TimeValue *abstime = NULL)
252    {
253        int err = 0;
254
255        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
256        // unlock the mutex and wait for the condition to be set. When either
257        // function returns, they will re-lock the mutex. We use an auto lock/unlock
258        // class (Mutex::Locker) to allow us to return at any point in this
259        // function and not have to worry about unlocking the mutex.
260        Mutex::Locker locker(m_mutex);
261
262#ifdef DB_PTHREAD_LOG_EVENTS
263        printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, bits, abstime, m_value);
264#endif
265        while (err == 0 && ((m_value & bits) != 0))
266        {
267            err = m_condition.Wait (m_mutex.GetMutex(), abstime);
268        }
269
270#ifdef DB_PTHREAD_LOG_EVENTS
271        printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x", __FUNCTION__, bits, m_value);
272#endif
273        return m_value & bits;
274    }
275
276    //------------------------------------------------------------------
277    /// Wait for \a m_value to be equal to \a value.
278    ///
279    /// Waits in a thread safe way for \a m_value to be equal to \a
280    /// value. If \a m_value is already equal to \a value, this
281    /// function will return without waiting.
282    ///
283    /// @param[in] value
284    ///     The value we want \a m_value to be equal to.
285    ///
286    /// @param[in] abstime
287    ///     If non-NULL, the absolute time at which we should stop
288    ///     waiting, else wait an infinite amount of time.
289    ///
290    /// @param[out] timed_out
291    ///     If not null, set to true if we return because of a time out,
292    ///     and false if the value was set.
293    ///
294    /// @return
295    ///     @li \b true if the \a m_value is equal to \a value
296    ///     @li \b false otherwise
297    //------------------------------------------------------------------
298    bool
299    WaitForValueEqualTo (T value, const TimeValue *abstime = NULL, bool *timed_out = NULL)
300    {
301        int err = 0;
302        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
303        // unlock the mutex and wait for the condition to be set. When either
304        // function returns, they will re-lock the mutex. We use an auto lock/unlock
305        // class (Mutex::Locker) to allow us to return at any point in this
306        // function and not have to worry about unlocking the mutex.
307        Mutex::Locker locker(m_mutex);
308
309#ifdef DB_PTHREAD_LOG_EVENTS
310        printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, value, abstime, m_value);
311#endif
312        if (timed_out)
313            *timed_out = false;
314
315        while (err == 0 && m_value != value)
316        {
317            err = m_condition.Wait (m_mutex.GetMutex(), abstime, timed_out);
318        }
319
320        return m_value == value;
321    }
322
323    //------------------------------------------------------------------
324    /// Wait for \a m_value to not be equal to \a value.
325    ///
326    /// Waits in a thread safe way for \a m_value to not be equal to \a
327    /// value. If \a m_value is already not equal to \a value, this
328    /// function will return without waiting.
329    ///
330    /// @param[in] value
331    ///     The value we want \a m_value to not be equal to.
332    ///
333    /// @param[out] new_value
334    ///     The new value if \b true is returned.
335    ///
336    /// @param[in] abstime
337    ///     If non-NULL, the absolute time at which we should stop
338    ///     waiting, else wait an infinite amount of time.
339    ///
340    /// @return
341    ///     @li \b true if the \a m_value is equal to \a value
342    ///     @li \b false otherwise
343    //------------------------------------------------------------------
344    bool
345    WaitForValueNotEqualTo (T value, T &new_value, const TimeValue *abstime = NULL)
346    {
347        int err = 0;
348        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
349        // unlock the mutex and wait for the condition to be set. When either
350        // function returns, they will re-lock the mutex. We use an auto lock/unlock
351        // class (Mutex::Locker) to allow us to return at any point in this
352        // function and not have to worry about unlocking the mutex.
353        Mutex::Locker locker(m_mutex);
354#ifdef DB_PTHREAD_LOG_EVENTS
355        printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, value, abstime, m_value);
356#endif
357        while (err == 0 && m_value == value)
358        {
359            err = m_condition.Wait (m_mutex.GetMutex(), abstime);
360        }
361
362        if (m_value != value)
363        {
364            new_value = m_value;
365            return true;
366        }
367        return false;
368    }
369
370protected:
371    //----------------------------------------------------------------------
372    // pthread condition and mutex variable to controll access and allow
373    // blocking between the main thread and the spotlight index thread.
374    //----------------------------------------------------------------------
375    T           m_value;        ///< The templatized value T that we are protecting access to
376    mutable Mutex m_mutex;      ///< The mutex to use when accessing the data
377    Condition   m_condition;    ///< The pthread condition variable to use for signaling that data available or changed.
378
379private:
380
381    //------------------------------------------------------------------
382    /// Broadcast if needed.
383    ///
384    /// Check to see if we need to broadcast to our condition variable
385    /// depedning on the \a old_value and on the \a broadcast_type.
386    ///
387    /// If \a broadcast_type is eBroadcastNever, no broadcast will be
388    /// sent.
389    ///
390    /// If \a broadcast_type is eBroadcastAlways, the condition variable
391    /// will always be broadcast.
392    ///
393    /// If \a broadcast_type is eBroadcastOnChange, the condition
394    /// variable be broadcast if the owned value changes.
395    //------------------------------------------------------------------
396    void
397    Broadcast (T old_value, PredicateBroadcastType broadcast_type)
398    {
399        bool broadcast = (broadcast_type == eBroadcastAlways) || ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
400#ifdef DB_PTHREAD_LOG_EVENTS
401        printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, broadcast = %u", __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
402#endif
403        if (broadcast)
404            m_condition.Broadcast();
405    }
406
407
408    DISALLOW_COPY_AND_ASSIGN(Predicate);
409};
410
411} // namespace lldb_private
412
413#endif  // #if defined(__cplusplus)
414#endif // #ifndef liblldb_Predicate_h_
415