PThreadEvent.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1//===-- PThreadEvent.cpp ----------------------------------------*- 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//  Created by Greg Clayton on 6/16/07.
11//
12//===----------------------------------------------------------------------===//
13
14#include "PThreadEvent.h"
15#include "errno.h"
16#include "DNBLog.h"
17
18PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) :
19    m_mutex(),
20    m_set_condition(),
21    m_reset_condition(),
22    m_bits(bits),
23    m_validBits(validBits),
24    m_reset_ack_mask(0)
25{
26    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits);
27}
28
29PThreadEvent::~PThreadEvent()
30{
31    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
32}
33
34
35uint32_t
36PThreadEvent::NewEventBit()
37{
38    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
39    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
40    uint32_t mask = 1;
41    while (mask & m_validBits)
42        mask <<= 1;
43    m_validBits |= mask;
44    return mask;
45}
46
47void
48PThreadEvent::FreeEventBits(const uint32_t mask)
49{
50    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
51    if (mask)
52    {
53        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
54        m_bits &= ~mask;
55        m_validBits &= ~mask;
56    }
57}
58
59
60uint32_t
61PThreadEvent::GetEventBits() const
62{
63    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
64    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
65    uint32_t bits = m_bits;
66    return bits;
67}
68
69// Replace the event bits with a new bitmask value
70void
71PThreadEvent::ReplaceEventBits(const uint32_t bits)
72{
73    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits);
74    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
75    // Make sure we have some bits and that they aren't already set...
76    if (m_bits != bits)
77    {
78        // Figure out which bits are changing
79        uint32_t changed_bits = m_bits ^ bits;
80        // Set the new bit values
81        m_bits = bits;
82        // If any new bits are set, then broadcast
83        if (changed_bits & m_bits)
84            m_set_condition.Broadcast();
85    }
86}
87
88// Set one or more event bits and broadcast if any new event bits get set
89// that weren't already set.
90
91void
92PThreadEvent::SetEvents(const uint32_t mask)
93{
94    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
95    // Make sure we have some bits to set
96    if (mask)
97    {
98        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
99        // Save the old event bit state so we can tell if things change
100        uint32_t old = m_bits;
101        // Set the all event bits that are set in 'mask'
102        m_bits |= mask;
103        // Broadcast only if any extra bits got set.
104        if (old != m_bits)
105            m_set_condition.Broadcast();
106    }
107}
108
109// Reset one or more event bits
110void
111PThreadEvent::ResetEvents(const uint32_t mask)
112{
113    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
114    if (mask)
115    {
116        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
117
118        // Save the old event bit state so we can tell if things change
119        uint32_t old = m_bits;
120        // Clear the all event bits that are set in 'mask'
121        m_bits &= ~mask;
122        // Broadcast only if any extra bits got reset.
123        if (old != m_bits)
124            m_reset_condition.Broadcast();
125    }
126}
127
128//----------------------------------------------------------------------
129// Wait until 'timeout_abstime' for any events that are set in
130// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
131//----------------------------------------------------------------------
132uint32_t
133PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const
134{
135    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
136    int err = 0;
137    // pthread_cond_timedwait() or pthread_cond_wait() will atomically
138    // unlock the mutex and wait for the condition to be set. When either
139    // function returns, they will re-lock the mutex. We use an auto lock/unlock
140    // class (PThreadMutex::Locker) to allow us to return at any point in this
141    // function and not have to worry about unlocking the mutex.
142    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
143    do
144    {
145        // Check our predicate (event bits) in case any are already set
146        if (mask & m_bits)
147        {
148            uint32_t bits_set = mask & m_bits;
149            // Our PThreadMutex::Locker will automatically unlock our mutex
150            return bits_set;
151        }
152        if (timeout_abstime)
153        {
154            // Wait for condition to get broadcast, or for a timeout. If we get
155            // a timeout we will drop out of the do loop and return false which
156            // is what we want.
157            err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
158            // Retest our predicate in case of a race condition right at the end
159            // of the timeout.
160            if (err == ETIMEDOUT)
161            {
162                uint32_t bits_set = mask & m_bits;
163                return bits_set;
164            }
165        }
166        else
167        {
168            // Wait for condition to get broadcast. The only error this function
169            // should return is if
170            err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex());
171        }
172    } while (err == 0);
173    return 0;
174}
175
176//----------------------------------------------------------------------
177// Wait until 'timeout_abstime' for any events in 'mask' to reset.
178// If 'timeout_abstime' is NULL, then wait forever.
179//----------------------------------------------------------------------
180uint32_t
181PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const
182{
183    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
184    int err = 0;
185    // pthread_cond_timedwait() or pthread_cond_wait() will atomically
186    // unlock the mutex and wait for the condition to be set. When either
187    // function returns, they will re-lock the mutex. We use an auto lock/unlock
188    // class (PThreadMutex::Locker) to allow us to return at any point in this
189    // function and not have to worry about unlocking the mutex.
190    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
191    do
192    {
193        // Check our predicate (event bits) each time through this do loop
194        if ((mask & m_bits) == 0)
195        {
196            // All the bits requested have been reset, return zero indicating
197            // which bits from the mask were still set (none of them)
198            return 0;
199        }
200        if (timeout_abstime)
201        {
202            // Wait for condition to get broadcast, or for a timeout. If we get
203            // a timeout we will drop out of the do loop and return false which
204            // is what we want.
205            err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
206        }
207        else
208        {
209            // Wait for condition to get broadcast. The only error this function
210            // should return is if
211            err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex());
212        }
213    } while (err == 0);
214    // Return a mask indicating which bits (if any) were still set
215    return mask & m_bits;
216}
217
218uint32_t
219PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const
220{
221    if (mask & m_reset_ack_mask)
222    {
223        // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
224        return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime);
225    }
226    return 0;
227}
228