@@ -108,79 +108,55 @@ void PThreadEvent::ResetEvents(const uint32_t mask) {
108
108
// Wait until 'timeout_abstime' for any events that are set in
109
109
// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
110
110
uint32_t
111
- PThreadEvent::WaitForSetEvents (const uint32_t mask,
112
- const struct timespec *timeout_abstime) const {
111
+ PThreadEvent::WaitForEventsImpl (const uint32_t mask,
112
+ const struct timespec *timeout_abstime,
113
+ std::function<bool ()> predicate) const {
113
114
// DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
114
115
// __FUNCTION__, mask, timeout_abstime);
116
+
115
117
int err = 0 ;
118
+
116
119
// pthread_cond_timedwait() or pthread_cond_wait() will atomically
117
120
// unlock the mutex and wait for the condition to be set. When either
118
121
// function returns, they will re-lock the mutex. We use an auto lock/unlock
119
122
// class (PThreadMutex::Locker) to allow us to return at any point in this
120
123
// function and not have to worry about unlocking the mutex.
121
124
PTHREAD_MUTEX_LOCKER (locker, m_mutex);
122
- do {
123
- // Check our predicate (event bits) in case any are already set
124
- if (mask & m_bits) {
125
- uint32_t bits_set = mask & m_bits;
126
- // Our PThreadMutex::Locker will automatically unlock our mutex
127
- return bits_set;
128
- }
125
+
126
+ // Check the predicate and the error code. The functions below do not return
127
+ // EINTR so that's not something we need to handle.
128
+ while (!predicate () && err == 0 ) {
129
129
if (timeout_abstime) {
130
130
// Wait for condition to get broadcast, or for a timeout. If we get
131
- // a timeout we will drop out of the do loop and return false which
132
- // is what we want.
131
+ // a timeout we will drop out of the loop on the next iteration and we
132
+ // will recompute the mask in case of a race between the condition and the
133
+ // timeout.
133
134
err = ::pthread_cond_timedwait (m_set_condition.Condition (),
134
135
m_mutex.Mutex (), timeout_abstime);
135
- // Retest our predicate in case of a race condition right at the end
136
- // of the timeout.
137
- if (err == ETIMEDOUT) {
138
- uint32_t bits_set = mask & m_bits;
139
- return bits_set;
140
- }
141
136
} else {
142
- // Wait for condition to get broadcast. The only error this function
143
- // should return is if
137
+ // Wait for condition to get broadcast.
144
138
err = ::pthread_cond_wait (m_set_condition.Condition (), m_mutex.Mutex ());
145
139
}
146
- } while (err == 0 );
147
- return 0 ;
140
+ }
141
+
142
+ // Either the predicate passed, we hit the specified timeout (ETIMEDOUT) or we
143
+ // encountered an unrecoverable error (EINVAL, EPERM). Regardless of how we
144
+ // got here, recompute and return the mask indicating which bits (if any) are
145
+ // set.
146
+ return GetBitsMasked (mask);
147
+ }
148
+
149
+ uint32_t
150
+ PThreadEvent::WaitForSetEvents (const uint32_t mask,
151
+ const struct timespec *timeout_abstime) const {
152
+ auto predicate = [&]() -> uint32_t { return GetBitsMasked (mask) != 0 ; };
153
+ return WaitForEventsImpl (mask, timeout_abstime, predicate);
148
154
}
149
155
150
- // Wait until 'timeout_abstime' for any events in 'mask' to reset.
151
- // If 'timeout_abstime' is NULL, then wait forever.
152
156
uint32_t PThreadEvent::WaitForEventsToReset (
153
157
const uint32_t mask, const struct timespec *timeout_abstime) const {
154
- // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
155
- // __FUNCTION__, mask, timeout_abstime);
156
- int err = 0 ;
157
- // pthread_cond_timedwait() or pthread_cond_wait() will atomically
158
- // unlock the mutex and wait for the condition to be set. When either
159
- // function returns, they will re-lock the mutex. We use an auto lock/unlock
160
- // class (PThreadMutex::Locker) to allow us to return at any point in this
161
- // function and not have to worry about unlocking the mutex.
162
- PTHREAD_MUTEX_LOCKER (locker, m_mutex);
163
- do {
164
- // Check our predicate (event bits) each time through this do loop
165
- if ((mask & m_bits) == 0 ) {
166
- // All the bits requested have been reset, return zero indicating
167
- // which bits from the mask were still set (none of them)
168
- return 0 ;
169
- }
170
- if (timeout_abstime) {
171
- // Wait for condition to get broadcast, or for a timeout. If we get
172
- // a timeout we will drop out of the do loop and return false which
173
- // is what we want.
174
- err = ::pthread_cond_timedwait (m_reset_condition.Condition (),
175
- m_mutex.Mutex (), timeout_abstime);
176
- } else {
177
- // Wait for condition to get broadcast. The only error this function
178
- // should return is if
179
- err = ::pthread_cond_wait (m_reset_condition.Condition (), m_mutex.Mutex ());
180
- }
181
- } while (err == 0 );
182
- // Return a mask indicating which bits (if any) were still set
183
- return mask & m_bits;
158
+ auto predicate = [&]() -> uint32_t { return GetBitsMasked (mask) == 0 ; };
159
+ return WaitForEventsImpl (mask, timeout_abstime, predicate);
184
160
}
185
161
186
162
uint32_t
0 commit comments