Skip to content

Commit 8c9fb82

Browse files
authored
Merge pull request #10126 from swiftlang/cherrypick-stable/20240723-87f2c25f3dad
2 parents a9a0b6a + f8cc8a4 commit 8c9fb82

File tree

2 files changed

+36
-53
lines changed

2 files changed

+36
-53
lines changed

lldb/tools/debugserver/source/PThreadEvent.cpp

Lines changed: 29 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -108,79 +108,55 @@ void PThreadEvent::ResetEvents(const uint32_t mask) {
108108
// Wait until 'timeout_abstime' for any events that are set in
109109
// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
110110
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 {
113114
// DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
114115
// __FUNCTION__, mask, timeout_abstime);
116+
115117
int err = 0;
118+
116119
// pthread_cond_timedwait() or pthread_cond_wait() will atomically
117120
// unlock the mutex and wait for the condition to be set. When either
118121
// function returns, they will re-lock the mutex. We use an auto lock/unlock
119122
// class (PThreadMutex::Locker) to allow us to return at any point in this
120123
// function and not have to worry about unlocking the mutex.
121124
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) {
129129
if (timeout_abstime) {
130130
// 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.
133134
err = ::pthread_cond_timedwait(m_set_condition.Condition(),
134135
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-
}
141136
} 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.
144138
err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex());
145139
}
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);
148154
}
149155

150-
// Wait until 'timeout_abstime' for any events in 'mask' to reset.
151-
// If 'timeout_abstime' is NULL, then wait forever.
152156
uint32_t PThreadEvent::WaitForEventsToReset(
153157
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);
184160
}
185161

186162
uint32_t

lldb/tools/debugserver/source/PThreadEvent.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "PThreadMutex.h"
1717
#include <cstdint>
1818
#include <ctime>
19+
#include <functional>
1920

2021
class PThreadEvent {
2122
public:
@@ -53,6 +54,12 @@ class PThreadEvent {
5354
uint32_t m_validBits;
5455
uint32_t m_reset_ack_mask;
5556

57+
uint32_t GetBitsMasked(uint32_t mask) const { return mask & m_bits; }
58+
59+
uint32_t WaitForEventsImpl(const uint32_t mask,
60+
const struct timespec *timeout_abstime,
61+
std::function<bool()> predicate) const;
62+
5663
private:
5764
PThreadEvent(const PThreadEvent &) = delete;
5865
PThreadEvent &operator=(const PThreadEvent &rhs) = delete;

0 commit comments

Comments
 (0)