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 "errno.h" 1630fdc8d8SChris Lattner #include "DNBLog.h" 1730fdc8d8SChris Lattner 1830fdc8d8SChris Lattner PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) : 1930fdc8d8SChris Lattner m_mutex(), 2030fdc8d8SChris Lattner m_set_condition(), 2130fdc8d8SChris Lattner m_reset_condition(), 2230fdc8d8SChris Lattner m_bits(bits), 2330fdc8d8SChris Lattner m_validBits(validBits), 2430fdc8d8SChris Lattner m_reset_ack_mask(0) 2530fdc8d8SChris Lattner { 2630fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits); 2730fdc8d8SChris Lattner } 2830fdc8d8SChris Lattner 2930fdc8d8SChris Lattner PThreadEvent::~PThreadEvent() 3030fdc8d8SChris Lattner { 31*f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 3230fdc8d8SChris Lattner } 3330fdc8d8SChris Lattner 3430fdc8d8SChris Lattner 3530fdc8d8SChris Lattner uint32_t 3630fdc8d8SChris Lattner PThreadEvent::NewEventBit() 3730fdc8d8SChris Lattner { 38*f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 3930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 4030fdc8d8SChris Lattner uint32_t mask = 1; 4130fdc8d8SChris Lattner while (mask & m_validBits) 4230fdc8d8SChris Lattner mask <<= 1; 4330fdc8d8SChris Lattner m_validBits |= mask; 4430fdc8d8SChris Lattner return mask; 4530fdc8d8SChris Lattner } 4630fdc8d8SChris Lattner 4730fdc8d8SChris Lattner void 4830fdc8d8SChris Lattner PThreadEvent::FreeEventBits(const uint32_t mask) 4930fdc8d8SChris Lattner { 5030fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); 5130fdc8d8SChris Lattner if (mask) 5230fdc8d8SChris Lattner { 5330fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 5430fdc8d8SChris Lattner m_bits &= ~mask; 5530fdc8d8SChris Lattner m_validBits &= ~mask; 5630fdc8d8SChris Lattner } 5730fdc8d8SChris Lattner } 5830fdc8d8SChris Lattner 5930fdc8d8SChris Lattner 6030fdc8d8SChris Lattner uint32_t 6130fdc8d8SChris Lattner PThreadEvent::GetEventBits() const 6230fdc8d8SChris Lattner { 63*f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 6430fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 6530fdc8d8SChris Lattner uint32_t bits = m_bits; 6630fdc8d8SChris Lattner return bits; 6730fdc8d8SChris Lattner } 6830fdc8d8SChris Lattner 6930fdc8d8SChris Lattner // Replace the event bits with a new bitmask value 7030fdc8d8SChris Lattner void 7130fdc8d8SChris Lattner PThreadEvent::ReplaceEventBits(const uint32_t bits) 7230fdc8d8SChris Lattner { 7330fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits); 7430fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 7530fdc8d8SChris Lattner // Make sure we have some bits and that they aren't already set... 7630fdc8d8SChris Lattner if (m_bits != bits) 7730fdc8d8SChris Lattner { 7830fdc8d8SChris Lattner // Figure out which bits are changing 7930fdc8d8SChris Lattner uint32_t changed_bits = m_bits ^ bits; 8030fdc8d8SChris Lattner // Set the new bit values 8130fdc8d8SChris Lattner m_bits = bits; 8230fdc8d8SChris Lattner // If any new bits are set, then broadcast 8330fdc8d8SChris Lattner if (changed_bits & m_bits) 8430fdc8d8SChris Lattner m_set_condition.Broadcast(); 8530fdc8d8SChris Lattner } 8630fdc8d8SChris Lattner } 8730fdc8d8SChris Lattner 8830fdc8d8SChris Lattner // Set one or more event bits and broadcast if any new event bits get set 8930fdc8d8SChris Lattner // that weren't already set. 9030fdc8d8SChris Lattner 9130fdc8d8SChris Lattner void 9230fdc8d8SChris Lattner PThreadEvent::SetEvents(const uint32_t mask) 9330fdc8d8SChris Lattner { 9430fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); 9530fdc8d8SChris Lattner // Make sure we have some bits to set 9630fdc8d8SChris Lattner if (mask) 9730fdc8d8SChris Lattner { 9830fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 9930fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change 10030fdc8d8SChris Lattner uint32_t old = m_bits; 10130fdc8d8SChris Lattner // Set the all event bits that are set in 'mask' 10230fdc8d8SChris Lattner m_bits |= mask; 10330fdc8d8SChris Lattner // Broadcast only if any extra bits got set. 10430fdc8d8SChris Lattner if (old != m_bits) 10530fdc8d8SChris Lattner m_set_condition.Broadcast(); 10630fdc8d8SChris Lattner } 10730fdc8d8SChris Lattner } 10830fdc8d8SChris Lattner 10930fdc8d8SChris Lattner // Reset one or more event bits 11030fdc8d8SChris Lattner void 11130fdc8d8SChris Lattner PThreadEvent::ResetEvents(const uint32_t mask) 11230fdc8d8SChris Lattner { 11330fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); 11430fdc8d8SChris Lattner if (mask) 11530fdc8d8SChris Lattner { 11630fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 11730fdc8d8SChris Lattner 11830fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change 11930fdc8d8SChris Lattner uint32_t old = m_bits; 12030fdc8d8SChris Lattner // Clear the all event bits that are set in 'mask' 12130fdc8d8SChris Lattner m_bits &= ~mask; 12230fdc8d8SChris Lattner // Broadcast only if any extra bits got reset. 12330fdc8d8SChris Lattner if (old != m_bits) 12430fdc8d8SChris Lattner m_reset_condition.Broadcast(); 12530fdc8d8SChris Lattner } 12630fdc8d8SChris Lattner } 12730fdc8d8SChris Lattner 12830fdc8d8SChris Lattner //---------------------------------------------------------------------- 12930fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in 13030fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever. 13130fdc8d8SChris Lattner //---------------------------------------------------------------------- 13230fdc8d8SChris Lattner uint32_t 13330fdc8d8SChris Lattner PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const 13430fdc8d8SChris Lattner { 13530fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); 13630fdc8d8SChris Lattner int err = 0; 13730fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically 13830fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either 13930fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock 14030fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this 14130fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex. 14230fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 14330fdc8d8SChris Lattner do 14430fdc8d8SChris Lattner { 14530fdc8d8SChris Lattner // Check our predicate (event bits) in case any are already set 14630fdc8d8SChris Lattner if (mask & m_bits) 14730fdc8d8SChris Lattner { 14830fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits; 14930fdc8d8SChris Lattner // Our PThreadMutex::Locker will automatically unlock our mutex 15030fdc8d8SChris Lattner return bits_set; 15130fdc8d8SChris Lattner } 15230fdc8d8SChris Lattner if (timeout_abstime) 15330fdc8d8SChris Lattner { 15430fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get 15530fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which 15630fdc8d8SChris Lattner // is what we want. 15730fdc8d8SChris Lattner err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime); 15830fdc8d8SChris Lattner // Retest our predicate in case of a race condition right at the end 15930fdc8d8SChris Lattner // of the timeout. 16030fdc8d8SChris Lattner if (err == ETIMEDOUT) 16130fdc8d8SChris Lattner { 16230fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits; 16330fdc8d8SChris Lattner return bits_set; 16430fdc8d8SChris Lattner } 16530fdc8d8SChris Lattner } 16630fdc8d8SChris Lattner else 16730fdc8d8SChris Lattner { 16830fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function 16930fdc8d8SChris Lattner // should return is if 17030fdc8d8SChris Lattner err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex()); 17130fdc8d8SChris Lattner } 17230fdc8d8SChris Lattner } while (err == 0); 17330fdc8d8SChris Lattner return 0; 17430fdc8d8SChris Lattner } 17530fdc8d8SChris Lattner 17630fdc8d8SChris Lattner //---------------------------------------------------------------------- 17730fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset. 17830fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever. 17930fdc8d8SChris Lattner //---------------------------------------------------------------------- 18030fdc8d8SChris Lattner uint32_t 18130fdc8d8SChris Lattner PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const 18230fdc8d8SChris Lattner { 18330fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); 18430fdc8d8SChris Lattner int err = 0; 18530fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically 18630fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either 18730fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock 18830fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this 18930fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex. 19030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER (locker, m_mutex); 19130fdc8d8SChris Lattner do 19230fdc8d8SChris Lattner { 19330fdc8d8SChris Lattner // Check our predicate (event bits) each time through this do loop 19430fdc8d8SChris Lattner if ((mask & m_bits) == 0) 19530fdc8d8SChris Lattner { 19630fdc8d8SChris Lattner // All the bits requested have been reset, return zero indicating 19730fdc8d8SChris Lattner // which bits from the mask were still set (none of them) 19830fdc8d8SChris Lattner return 0; 19930fdc8d8SChris Lattner } 20030fdc8d8SChris Lattner if (timeout_abstime) 20130fdc8d8SChris Lattner { 20230fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get 20330fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which 20430fdc8d8SChris Lattner // is what we want. 20530fdc8d8SChris Lattner err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime); 20630fdc8d8SChris Lattner } 20730fdc8d8SChris Lattner else 20830fdc8d8SChris Lattner { 20930fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function 21030fdc8d8SChris Lattner // should return is if 21130fdc8d8SChris Lattner err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex()); 21230fdc8d8SChris Lattner } 21330fdc8d8SChris Lattner } while (err == 0); 21430fdc8d8SChris Lattner // Return a mask indicating which bits (if any) were still set 21530fdc8d8SChris Lattner return mask & m_bits; 21630fdc8d8SChris Lattner } 21730fdc8d8SChris Lattner 21830fdc8d8SChris Lattner uint32_t 21930fdc8d8SChris Lattner PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const 22030fdc8d8SChris Lattner { 22130fdc8d8SChris Lattner if (mask & m_reset_ack_mask) 22230fdc8d8SChris Lattner { 22330fdc8d8SChris Lattner // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); 22430fdc8d8SChris Lattner return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime); 22530fdc8d8SChris Lattner } 22630fdc8d8SChris Lattner return 0; 22730fdc8d8SChris Lattner } 228