130fdc8d8SChris Lattner //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner // 930fdc8d8SChris Lattner // Created by Greg Clayton on 6/16/07. 1030fdc8d8SChris Lattner // 1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 1230fdc8d8SChris Lattner 1330fdc8d8SChris Lattner #include "PThreadEvent.h" 1430fdc8d8SChris Lattner #include "DNBLog.h" 15b9c1b51eSKate Stone #include "errno.h" 1630fdc8d8SChris Lattner 17b9c1b51eSKate Stone PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) 18b9c1b51eSKate Stone : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits), 19b9c1b51eSKate Stone m_validBits(validBits), m_reset_ack_mask(0) { 20b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", 21b9c1b51eSKate Stone // this, __FUNCTION__, bits, validBits); 2230fdc8d8SChris Lattner } 2330fdc8d8SChris Lattner 24b9c1b51eSKate Stone PThreadEvent::~PThreadEvent() { 25f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 2630fdc8d8SChris Lattner } 2730fdc8d8SChris Lattner 28b9c1b51eSKate Stone uint32_t PThreadEvent::NewEventBit() { 29f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 3030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 3130fdc8d8SChris Lattner uint32_t mask = 1; 3230fdc8d8SChris Lattner while (mask & m_validBits) 3330fdc8d8SChris Lattner mask <<= 1; 3430fdc8d8SChris Lattner m_validBits |= mask; 3530fdc8d8SChris Lattner return mask; 3630fdc8d8SChris Lattner } 3730fdc8d8SChris Lattner 38b9c1b51eSKate Stone void PThreadEvent::FreeEventBits(const uint32_t mask) { 39b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, 40b9c1b51eSKate Stone // __FUNCTION__, mask); 41b9c1b51eSKate Stone if (mask) { 4230fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 4330fdc8d8SChris Lattner m_bits &= ~mask; 4430fdc8d8SChris Lattner m_validBits &= ~mask; 4530fdc8d8SChris Lattner } 4630fdc8d8SChris Lattner } 4730fdc8d8SChris Lattner 48b9c1b51eSKate Stone uint32_t PThreadEvent::GetEventBits() const { 49f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); 5030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 5130fdc8d8SChris Lattner uint32_t bits = m_bits; 5230fdc8d8SChris Lattner return bits; 5330fdc8d8SChris Lattner } 5430fdc8d8SChris Lattner 5530fdc8d8SChris Lattner // Replace the event bits with a new bitmask value 56b9c1b51eSKate Stone void PThreadEvent::ReplaceEventBits(const uint32_t bits) { 57b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, 58b9c1b51eSKate Stone // __FUNCTION__, bits); 5930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 6030fdc8d8SChris Lattner // Make sure we have some bits and that they aren't already set... 61b9c1b51eSKate Stone if (m_bits != bits) { 6230fdc8d8SChris Lattner // Figure out which bits are changing 6330fdc8d8SChris Lattner uint32_t changed_bits = m_bits ^ bits; 6430fdc8d8SChris Lattner // Set the new bit values 6530fdc8d8SChris Lattner m_bits = bits; 6630fdc8d8SChris Lattner // If any new bits are set, then broadcast 6730fdc8d8SChris Lattner if (changed_bits & m_bits) 6830fdc8d8SChris Lattner m_set_condition.Broadcast(); 6930fdc8d8SChris Lattner } 7030fdc8d8SChris Lattner } 7130fdc8d8SChris Lattner 7230fdc8d8SChris Lattner // Set one or more event bits and broadcast if any new event bits get set 7330fdc8d8SChris Lattner // that weren't already set. 7430fdc8d8SChris Lattner 75b9c1b51eSKate Stone void PThreadEvent::SetEvents(const uint32_t mask) { 76b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, 77b9c1b51eSKate Stone // __FUNCTION__, mask); 7830fdc8d8SChris Lattner // Make sure we have some bits to set 79b9c1b51eSKate Stone if (mask) { 8030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 8130fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change 8230fdc8d8SChris Lattner uint32_t old = m_bits; 8330fdc8d8SChris Lattner // Set the all event bits that are set in 'mask' 8430fdc8d8SChris Lattner m_bits |= mask; 8530fdc8d8SChris Lattner // Broadcast only if any extra bits got set. 8630fdc8d8SChris Lattner if (old != m_bits) 8730fdc8d8SChris Lattner m_set_condition.Broadcast(); 8830fdc8d8SChris Lattner } 8930fdc8d8SChris Lattner } 9030fdc8d8SChris Lattner 9130fdc8d8SChris Lattner // Reset one or more event bits 92b9c1b51eSKate Stone void PThreadEvent::ResetEvents(const uint32_t mask) { 93b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, 94b9c1b51eSKate Stone // __FUNCTION__, mask); 95b9c1b51eSKate Stone if (mask) { 9630fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 9730fdc8d8SChris Lattner 9830fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change 9930fdc8d8SChris Lattner uint32_t old = m_bits; 10030fdc8d8SChris Lattner // Clear the all event bits that are set in 'mask' 10130fdc8d8SChris Lattner m_bits &= ~mask; 10230fdc8d8SChris Lattner // Broadcast only if any extra bits got reset. 10330fdc8d8SChris Lattner if (old != m_bits) 10430fdc8d8SChris Lattner m_reset_condition.Broadcast(); 10530fdc8d8SChris Lattner } 10630fdc8d8SChris Lattner } 10730fdc8d8SChris Lattner 10830fdc8d8SChris Lattner //---------------------------------------------------------------------- 10930fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in 11030fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever. 11130fdc8d8SChris Lattner //---------------------------------------------------------------------- 11230fdc8d8SChris Lattner uint32_t 113b9c1b51eSKate Stone PThreadEvent::WaitForSetEvents(const uint32_t mask, 114b9c1b51eSKate Stone const struct timespec *timeout_abstime) const { 115b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, 116b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime); 11730fdc8d8SChris Lattner int err = 0; 11830fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically 11930fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either 12030fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock 12130fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this 12230fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex. 12330fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 124b9c1b51eSKate Stone do { 12530fdc8d8SChris Lattner // Check our predicate (event bits) in case any are already set 126b9c1b51eSKate Stone if (mask & m_bits) { 12730fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits; 12830fdc8d8SChris Lattner // Our PThreadMutex::Locker will automatically unlock our mutex 12930fdc8d8SChris Lattner return bits_set; 13030fdc8d8SChris Lattner } 131b9c1b51eSKate Stone if (timeout_abstime) { 13230fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get 13330fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which 13430fdc8d8SChris Lattner // is what we want. 135b9c1b51eSKate Stone err = ::pthread_cond_timedwait(m_set_condition.Condition(), 136b9c1b51eSKate Stone m_mutex.Mutex(), timeout_abstime); 13730fdc8d8SChris Lattner // Retest our predicate in case of a race condition right at the end 13830fdc8d8SChris Lattner // of the timeout. 139b9c1b51eSKate Stone if (err == ETIMEDOUT) { 14030fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits; 14130fdc8d8SChris Lattner return bits_set; 14230fdc8d8SChris Lattner } 143b9c1b51eSKate Stone } else { 14430fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function 14530fdc8d8SChris Lattner // should return is if 14630fdc8d8SChris Lattner err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex()); 14730fdc8d8SChris Lattner } 14830fdc8d8SChris Lattner } while (err == 0); 14930fdc8d8SChris Lattner return 0; 15030fdc8d8SChris Lattner } 15130fdc8d8SChris Lattner 15230fdc8d8SChris Lattner //---------------------------------------------------------------------- 15330fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset. 15430fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever. 15530fdc8d8SChris Lattner //---------------------------------------------------------------------- 156b9c1b51eSKate Stone uint32_t PThreadEvent::WaitForEventsToReset( 157b9c1b51eSKate Stone const uint32_t mask, const struct timespec *timeout_abstime) const { 158b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, 159b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime); 16030fdc8d8SChris Lattner int err = 0; 16130fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically 16230fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either 16330fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock 16430fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this 16530fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex. 16630fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex); 167b9c1b51eSKate Stone do { 16830fdc8d8SChris Lattner // Check our predicate (event bits) each time through this do loop 169b9c1b51eSKate Stone if ((mask & m_bits) == 0) { 17030fdc8d8SChris Lattner // All the bits requested have been reset, return zero indicating 17130fdc8d8SChris Lattner // which bits from the mask were still set (none of them) 17230fdc8d8SChris Lattner return 0; 17330fdc8d8SChris Lattner } 174b9c1b51eSKate Stone if (timeout_abstime) { 17530fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get 17630fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which 17730fdc8d8SChris Lattner // is what we want. 178b9c1b51eSKate Stone err = ::pthread_cond_timedwait(m_reset_condition.Condition(), 179b9c1b51eSKate Stone m_mutex.Mutex(), timeout_abstime); 180b9c1b51eSKate Stone } else { 18130fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function 18230fdc8d8SChris Lattner // should return is if 18330fdc8d8SChris Lattner err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex()); 18430fdc8d8SChris Lattner } 18530fdc8d8SChris Lattner } while (err == 0); 18630fdc8d8SChris Lattner // Return a mask indicating which bits (if any) were still set 18730fdc8d8SChris Lattner return mask & m_bits; 18830fdc8d8SChris Lattner } 18930fdc8d8SChris Lattner 19030fdc8d8SChris Lattner uint32_t 191b9c1b51eSKate Stone PThreadEvent::WaitForResetAck(const uint32_t mask, 192b9c1b51eSKate Stone const struct timespec *timeout_abstime) const { 193b9c1b51eSKate Stone if (mask & m_reset_ack_mask) { 194b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, 195b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime); 19630fdc8d8SChris Lattner return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime); 19730fdc8d8SChris Lattner } 19830fdc8d8SChris Lattner return 0; 19930fdc8d8SChris Lattner } 200