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