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