130fdc8d8SChris Lattner //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 6/16/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "PThreadEvent.h"
1530fdc8d8SChris Lattner #include "DNBLog.h"
16*b9c1b51eSKate Stone #include "errno.h"
1730fdc8d8SChris Lattner 
18*b9c1b51eSKate Stone PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits)
19*b9c1b51eSKate Stone     : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits),
20*b9c1b51eSKate Stone       m_validBits(validBits), m_reset_ack_mask(0) {
21*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)",
22*b9c1b51eSKate Stone   // this, __FUNCTION__, bits, validBits);
2330fdc8d8SChris Lattner }
2430fdc8d8SChris Lattner 
25*b9c1b51eSKate Stone PThreadEvent::~PThreadEvent() {
26f343968fSZachary Turner   // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
2730fdc8d8SChris Lattner }
2830fdc8d8SChris Lattner 
29*b9c1b51eSKate Stone uint32_t PThreadEvent::NewEventBit() {
30f343968fSZachary Turner   // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
3130fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
3230fdc8d8SChris Lattner   uint32_t mask = 1;
3330fdc8d8SChris Lattner   while (mask & m_validBits)
3430fdc8d8SChris Lattner     mask <<= 1;
3530fdc8d8SChris Lattner   m_validBits |= mask;
3630fdc8d8SChris Lattner   return mask;
3730fdc8d8SChris Lattner }
3830fdc8d8SChris Lattner 
39*b9c1b51eSKate Stone void PThreadEvent::FreeEventBits(const uint32_t mask) {
40*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
41*b9c1b51eSKate Stone   // __FUNCTION__, mask);
42*b9c1b51eSKate Stone   if (mask) {
4330fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER(locker, m_mutex);
4430fdc8d8SChris Lattner     m_bits &= ~mask;
4530fdc8d8SChris Lattner     m_validBits &= ~mask;
4630fdc8d8SChris Lattner   }
4730fdc8d8SChris Lattner }
4830fdc8d8SChris Lattner 
49*b9c1b51eSKate Stone uint32_t PThreadEvent::GetEventBits() const {
50f343968fSZachary Turner   // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
5130fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
5230fdc8d8SChris Lattner   uint32_t bits = m_bits;
5330fdc8d8SChris Lattner   return bits;
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
5630fdc8d8SChris Lattner // Replace the event bits with a new bitmask value
57*b9c1b51eSKate Stone void PThreadEvent::ReplaceEventBits(const uint32_t bits) {
58*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
59*b9c1b51eSKate Stone   // __FUNCTION__, bits);
6030fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
6130fdc8d8SChris Lattner   // Make sure we have some bits and that they aren't already set...
62*b9c1b51eSKate Stone   if (m_bits != bits) {
6330fdc8d8SChris Lattner     // Figure out which bits are changing
6430fdc8d8SChris Lattner     uint32_t changed_bits = m_bits ^ bits;
6530fdc8d8SChris Lattner     // Set the new bit values
6630fdc8d8SChris Lattner     m_bits = bits;
6730fdc8d8SChris Lattner     // If any new bits are set, then broadcast
6830fdc8d8SChris Lattner     if (changed_bits & m_bits)
6930fdc8d8SChris Lattner       m_set_condition.Broadcast();
7030fdc8d8SChris Lattner   }
7130fdc8d8SChris Lattner }
7230fdc8d8SChris Lattner 
7330fdc8d8SChris Lattner // Set one or more event bits and broadcast if any new event bits get set
7430fdc8d8SChris Lattner // that weren't already set.
7530fdc8d8SChris Lattner 
76*b9c1b51eSKate Stone void PThreadEvent::SetEvents(const uint32_t mask) {
77*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
78*b9c1b51eSKate Stone   // __FUNCTION__, mask);
7930fdc8d8SChris Lattner   // Make sure we have some bits to set
80*b9c1b51eSKate Stone   if (mask) {
8130fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER(locker, m_mutex);
8230fdc8d8SChris Lattner     // Save the old event bit state so we can tell if things change
8330fdc8d8SChris Lattner     uint32_t old = m_bits;
8430fdc8d8SChris Lattner     // Set the all event bits that are set in 'mask'
8530fdc8d8SChris Lattner     m_bits |= mask;
8630fdc8d8SChris Lattner     // Broadcast only if any extra bits got set.
8730fdc8d8SChris Lattner     if (old != m_bits)
8830fdc8d8SChris Lattner       m_set_condition.Broadcast();
8930fdc8d8SChris Lattner   }
9030fdc8d8SChris Lattner }
9130fdc8d8SChris Lattner 
9230fdc8d8SChris Lattner // Reset one or more event bits
93*b9c1b51eSKate Stone void PThreadEvent::ResetEvents(const uint32_t mask) {
94*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
95*b9c1b51eSKate Stone   // __FUNCTION__, mask);
96*b9c1b51eSKate Stone   if (mask) {
9730fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER(locker, m_mutex);
9830fdc8d8SChris Lattner 
9930fdc8d8SChris Lattner     // Save the old event bit state so we can tell if things change
10030fdc8d8SChris Lattner     uint32_t old = m_bits;
10130fdc8d8SChris Lattner     // Clear the all event bits that are set in 'mask'
10230fdc8d8SChris Lattner     m_bits &= ~mask;
10330fdc8d8SChris Lattner     // Broadcast only if any extra bits got reset.
10430fdc8d8SChris Lattner     if (old != m_bits)
10530fdc8d8SChris Lattner       m_reset_condition.Broadcast();
10630fdc8d8SChris Lattner   }
10730fdc8d8SChris Lattner }
10830fdc8d8SChris Lattner 
10930fdc8d8SChris Lattner //----------------------------------------------------------------------
11030fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in
11130fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
11230fdc8d8SChris Lattner //----------------------------------------------------------------------
11330fdc8d8SChris Lattner uint32_t
114*b9c1b51eSKate Stone PThreadEvent::WaitForSetEvents(const uint32_t mask,
115*b9c1b51eSKate Stone                                const struct timespec *timeout_abstime) const {
116*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
117*b9c1b51eSKate Stone   // __FUNCTION__, mask, timeout_abstime);
11830fdc8d8SChris Lattner   int err = 0;
11930fdc8d8SChris Lattner   // pthread_cond_timedwait() or pthread_cond_wait() will atomically
12030fdc8d8SChris Lattner   // unlock the mutex and wait for the condition to be set. When either
12130fdc8d8SChris Lattner   // function returns, they will re-lock the mutex. We use an auto lock/unlock
12230fdc8d8SChris Lattner   // class (PThreadMutex::Locker) to allow us to return at any point in this
12330fdc8d8SChris Lattner   // function and not have to worry about unlocking the mutex.
12430fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
125*b9c1b51eSKate Stone   do {
12630fdc8d8SChris Lattner     // Check our predicate (event bits) in case any are already set
127*b9c1b51eSKate Stone     if (mask & m_bits) {
12830fdc8d8SChris Lattner       uint32_t bits_set = mask & m_bits;
12930fdc8d8SChris Lattner       // Our PThreadMutex::Locker will automatically unlock our mutex
13030fdc8d8SChris Lattner       return bits_set;
13130fdc8d8SChris Lattner     }
132*b9c1b51eSKate Stone     if (timeout_abstime) {
13330fdc8d8SChris Lattner       // Wait for condition to get broadcast, or for a timeout. If we get
13430fdc8d8SChris Lattner       // a timeout we will drop out of the do loop and return false which
13530fdc8d8SChris Lattner       // is what we want.
136*b9c1b51eSKate Stone       err = ::pthread_cond_timedwait(m_set_condition.Condition(),
137*b9c1b51eSKate Stone                                      m_mutex.Mutex(), timeout_abstime);
13830fdc8d8SChris Lattner       // Retest our predicate in case of a race condition right at the end
13930fdc8d8SChris Lattner       // of the timeout.
140*b9c1b51eSKate Stone       if (err == ETIMEDOUT) {
14130fdc8d8SChris Lattner         uint32_t bits_set = mask & m_bits;
14230fdc8d8SChris Lattner         return bits_set;
14330fdc8d8SChris Lattner       }
144*b9c1b51eSKate Stone     } else {
14530fdc8d8SChris Lattner       // Wait for condition to get broadcast. The only error this function
14630fdc8d8SChris Lattner       // should return is if
14730fdc8d8SChris Lattner       err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex());
14830fdc8d8SChris Lattner     }
14930fdc8d8SChris Lattner   } while (err == 0);
15030fdc8d8SChris Lattner   return 0;
15130fdc8d8SChris Lattner }
15230fdc8d8SChris Lattner 
15330fdc8d8SChris Lattner //----------------------------------------------------------------------
15430fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset.
15530fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever.
15630fdc8d8SChris Lattner //----------------------------------------------------------------------
157*b9c1b51eSKate Stone uint32_t PThreadEvent::WaitForEventsToReset(
158*b9c1b51eSKate Stone     const uint32_t mask, const struct timespec *timeout_abstime) const {
159*b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
160*b9c1b51eSKate Stone   // __FUNCTION__, mask, timeout_abstime);
16130fdc8d8SChris Lattner   int err = 0;
16230fdc8d8SChris Lattner   // pthread_cond_timedwait() or pthread_cond_wait() will atomically
16330fdc8d8SChris Lattner   // unlock the mutex and wait for the condition to be set. When either
16430fdc8d8SChris Lattner   // function returns, they will re-lock the mutex. We use an auto lock/unlock
16530fdc8d8SChris Lattner   // class (PThreadMutex::Locker) to allow us to return at any point in this
16630fdc8d8SChris Lattner   // function and not have to worry about unlocking the mutex.
16730fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
168*b9c1b51eSKate Stone   do {
16930fdc8d8SChris Lattner     // Check our predicate (event bits) each time through this do loop
170*b9c1b51eSKate Stone     if ((mask & m_bits) == 0) {
17130fdc8d8SChris Lattner       // All the bits requested have been reset, return zero indicating
17230fdc8d8SChris Lattner       // which bits from the mask were still set (none of them)
17330fdc8d8SChris Lattner       return 0;
17430fdc8d8SChris Lattner     }
175*b9c1b51eSKate Stone     if (timeout_abstime) {
17630fdc8d8SChris Lattner       // Wait for condition to get broadcast, or for a timeout. If we get
17730fdc8d8SChris Lattner       // a timeout we will drop out of the do loop and return false which
17830fdc8d8SChris Lattner       // is what we want.
179*b9c1b51eSKate Stone       err = ::pthread_cond_timedwait(m_reset_condition.Condition(),
180*b9c1b51eSKate Stone                                      m_mutex.Mutex(), timeout_abstime);
181*b9c1b51eSKate Stone     } else {
18230fdc8d8SChris Lattner       // Wait for condition to get broadcast. The only error this function
18330fdc8d8SChris Lattner       // should return is if
18430fdc8d8SChris Lattner       err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex());
18530fdc8d8SChris Lattner     }
18630fdc8d8SChris Lattner   } while (err == 0);
18730fdc8d8SChris Lattner   // Return a mask indicating which bits (if any) were still set
18830fdc8d8SChris Lattner   return mask & m_bits;
18930fdc8d8SChris Lattner }
19030fdc8d8SChris Lattner 
19130fdc8d8SChris Lattner uint32_t
192*b9c1b51eSKate Stone PThreadEvent::WaitForResetAck(const uint32_t mask,
193*b9c1b51eSKate Stone                               const struct timespec *timeout_abstime) const {
194*b9c1b51eSKate Stone   if (mask & m_reset_ack_mask) {
195*b9c1b51eSKate Stone     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
196*b9c1b51eSKate Stone     // __FUNCTION__, mask, timeout_abstime);
19730fdc8d8SChris Lattner     return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime);
19830fdc8d8SChris Lattner   }
19930fdc8d8SChris Lattner   return 0;
20030fdc8d8SChris Lattner }
201