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