Predicate.h revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
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_mutex(),
57        m_condition(),
58        m_value()
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_mutex(),
73        m_condition(),
74        m_value(initial_value)
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        while (err == 0 && m_value != value)
313        {
314            err = m_condition.Wait (m_mutex.GetMutex(), abstime, timed_out);
315        }
316
317        return m_value == value;
318    }
319
320    //------------------------------------------------------------------
321    /// Wait for \a m_value to not be equal to \a value.
322    ///
323    /// Waits in a thread safe way for \a m_value to not be equal to \a
324    /// value. If \a m_value is already not equal to \a value, this
325    /// function will return without waiting.
326    ///
327    /// @param[in] value
328    ///     The value we want \a m_value to not be equal to.
329    ///
330    /// @param[out] new_value
331    ///     The new value if \b true is returned.
332    ///
333    /// @param[in] abstime
334    ///     If non-NULL, the absolute time at which we should stop
335    ///     waiting, else wait an infinite amount of time.
336    ///
337    /// @return
338    ///     @li \b true if the \a m_value is equal to \a value
339    ///     @li \b false otherwise
340    //------------------------------------------------------------------
341    bool
342    WaitForValueNotEqualTo (T value, T &new_value, const TimeValue *abstime = NULL)
343    {
344        int err = 0;
345        // pthread_cond_timedwait() or pthread_cond_wait() will atomically
346        // unlock the mutex and wait for the condition to be set. When either
347        // function returns, they will re-lock the mutex. We use an auto lock/unlock
348        // class (Mutex::Locker) to allow us to return at any point in this
349        // function and not have to worry about unlocking the mutex.
350        Mutex::Locker locker(m_mutex);
351#ifdef DB_PTHREAD_LOG_EVENTS
352        printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, value, abstime, m_value);
353#endif
354        while (err == 0 && m_value == value)
355        {
356            err = m_condition.Wait (m_mutex.GetMutex(), abstime);
357        }
358
359        if (m_value != value)
360        {
361            new_value = m_value;
362            return true;
363        }
364        return false;
365    }
366
367protected:
368    //----------------------------------------------------------------------
369    // pthread condition and mutex variable to controll access and allow
370    // blocking between the main thread and the spotlight index thread.
371    //----------------------------------------------------------------------
372    T           m_value;        ///< The templatized value T that we are protecting access to
373    mutable Mutex m_mutex;      ///< The mutex to use when accessing the data
374    Condition   m_condition;    ///< The pthread condition variable to use for signaling that data available or changed.
375
376private:
377
378    //------------------------------------------------------------------
379    /// Broadcast if needed.
380    ///
381    /// Check to see if we need to broadcast to our condition variable
382    /// depedning on the \a old_value and on the \a broadcast_type.
383    ///
384    /// If \a broadcast_type is eBroadcastNever, no broadcast will be
385    /// sent.
386    ///
387    /// If \a broadcast_type is eBroadcastAlways, the condition variable
388    /// will always be broadcast.
389    ///
390    /// If \a broadcast_type is eBroadcastOnChange, the condition
391    /// variable be broadcast if the owned value changes.
392    //------------------------------------------------------------------
393    void
394    Broadcast (T old_value, PredicateBroadcastType broadcast_type)
395    {
396        bool broadcast = (broadcast_type == eBroadcastAlways) || ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
397#ifdef DB_PTHREAD_LOG_EVENTS
398        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);
399#endif
400        if (broadcast)
401            m_condition.Broadcast();
402    }
403
404
405    DISALLOW_COPY_AND_ASSIGN(Predicate);
406};
407
408} // namespace lldb_private
409
410#endif  // #if defined(__cplusplus)
411#endif // #ifndef liblldb_Predicate_h_
412