blob: 1b0900ca71074dd1b50ed2b124aa684a8e92ef5c [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000015#include "DNBLog.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000016#include "errno.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000017
Kate Stoneb9c1b512016-09-06 20:57:50 +000018PThreadEvent::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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000023}
24
Kate Stoneb9c1b512016-09-06 20:57:50 +000025PThreadEvent::~PThreadEvent() {
26 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027}
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029uint32_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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000037}
38
Kate Stoneb9c1b512016-09-06 20:57:50 +000039void 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000047}
48
Kate Stoneb9c1b512016-09-06 20:57:50 +000049uint32_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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000054}
55
56// Replace the event bits with a new bitmask value
Kate Stoneb9c1b512016-09-06 20:57:50 +000057void 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000071}
72
73// Set one or more event bits and broadcast if any new event bits get set
74// that weren't already set.
75
Kate Stoneb9c1b512016-09-06 20:57:50 +000076void 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000090}
91
92// Reset one or more event bits
Kate Stoneb9c1b512016-09-06 20:57:50 +000093void 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000098
Kate Stoneb9c1b512016-09-06 20:57:50 +000099 // 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000107}
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//----------------------------------------------------------------------
113uint32_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114PThreadEvent::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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000151}
152
153//----------------------------------------------------------------------
154// Wait until 'timeout_abstime' for any events in 'mask' to reset.
155// If 'timeout_abstime' is NULL, then wait forever.
156//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157uint32_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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189}
190
191uint32_t
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192PThreadEvent::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;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000200}