1 //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Created by Greg Clayton on 6/16/07.
11 //===----------------------------------------------------------------------===//
13 #include "PThreadEvent.h"
17 PThreadEvent::PThreadEvent(uint32_t bits
, uint32_t validBits
)
18 : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits
),
19 m_validBits(validBits
), m_reset_ack_mask(0) {
20 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)",
21 // this, __FUNCTION__, bits, validBits);
24 PThreadEvent::~PThreadEvent() {
25 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
28 uint32_t PThreadEvent::NewEventBit() {
29 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
30 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
32 while (mask
& m_validBits
)
38 void PThreadEvent::FreeEventBits(const uint32_t mask
) {
39 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
40 // __FUNCTION__, mask);
42 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
48 uint32_t PThreadEvent::GetEventBits() const {
49 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
50 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
51 uint32_t bits
= m_bits
;
55 // Replace the event bits with a new bitmask value
56 void PThreadEvent::ReplaceEventBits(const uint32_t bits
) {
57 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
58 // __FUNCTION__, bits);
59 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
60 // Make sure we have some bits and that they aren't already set...
62 // Figure out which bits are changing
63 uint32_t changed_bits
= m_bits
^ bits
;
64 // Set the new bit values
66 // If any new bits are set, then broadcast
67 if (changed_bits
& m_bits
)
68 m_set_condition
.Broadcast();
72 // Set one or more event bits and broadcast if any new event bits get set
73 // that weren't already set.
75 void PThreadEvent::SetEvents(const uint32_t mask
) {
76 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
77 // __FUNCTION__, mask);
78 // Make sure we have some bits to set
80 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
81 // Save the old event bit state so we can tell if things change
82 uint32_t old
= m_bits
;
83 // Set the all event bits that are set in 'mask'
85 // Broadcast only if any extra bits got set.
87 m_set_condition
.Broadcast();
91 // Reset one or more event bits
92 void PThreadEvent::ResetEvents(const uint32_t mask
) {
93 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
94 // __FUNCTION__, mask);
96 PTHREAD_MUTEX_LOCKER(locker
, m_mutex
);
98 // Save the old event bit state so we can tell if things change
99 uint32_t old
= m_bits
;
100 // Clear the all event bits that are set in 'mask'
102 // Broadcast only if any extra bits got reset.
104 m_reset_condition
.Broadcast();
108 // Wait until 'timeout_abstime' for any events that are set in
109 // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
111 PThreadEvent::WaitForEventsImpl(const uint32_t mask
,
112 const struct timespec
*timeout_abstime
,
113 std::function
<bool()> predicate
) const {
114 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
115 // __FUNCTION__, mask, timeout_abstime);
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
);
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 if (timeout_abstime
) {
130 // Wait for condition to get broadcast, or for a timeout. If we get
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
134 err
= ::pthread_cond_timedwait(m_set_condition
.Condition(),
135 m_mutex
.Mutex(), timeout_abstime
);
137 // Wait for condition to get broadcast.
138 err
= ::pthread_cond_wait(m_set_condition
.Condition(), m_mutex
.Mutex());
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
146 return GetBitsMasked(mask
);
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
);
156 uint32_t PThreadEvent::WaitForEventsToReset(
157 const uint32_t mask
, const struct timespec
*timeout_abstime
) const {
158 auto predicate
= [&]() -> uint32_t { return GetBitsMasked(mask
) == 0; };
159 return WaitForEventsImpl(mask
, timeout_abstime
, predicate
);
163 PThreadEvent::WaitForResetAck(const uint32_t mask
,
164 const struct timespec
*timeout_abstime
) const {
165 if (mask
& m_reset_ack_mask
) {
166 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
167 // __FUNCTION__, mask, timeout_abstime);
168 return WaitForEventsToReset(mask
& m_reset_ack_mask
, timeout_abstime
);