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