130fdc8d8SChris Lattner //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner //
930fdc8d8SChris Lattner // Created by Greg Clayton on 6/16/07.
1030fdc8d8SChris Lattner //
1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1230fdc8d8SChris Lattner
1330fdc8d8SChris Lattner #include "PThreadEvent.h"
1430fdc8d8SChris Lattner #include "DNBLog.h"
15*76e47d48SRaphael Isemann #include <cerrno>
1630fdc8d8SChris Lattner
PThreadEvent(uint32_t bits,uint32_t validBits)17b9c1b51eSKate Stone PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits)
18b9c1b51eSKate Stone : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits),
19b9c1b51eSKate Stone m_validBits(validBits), m_reset_ack_mask(0) {
20b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)",
21b9c1b51eSKate Stone // this, __FUNCTION__, bits, validBits);
2230fdc8d8SChris Lattner }
2330fdc8d8SChris Lattner
~PThreadEvent()24b9c1b51eSKate Stone PThreadEvent::~PThreadEvent() {
25f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
2630fdc8d8SChris Lattner }
2730fdc8d8SChris Lattner
NewEventBit()28b9c1b51eSKate Stone uint32_t PThreadEvent::NewEventBit() {
29f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
3030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
3130fdc8d8SChris Lattner uint32_t mask = 1;
3230fdc8d8SChris Lattner while (mask & m_validBits)
3330fdc8d8SChris Lattner mask <<= 1;
3430fdc8d8SChris Lattner m_validBits |= mask;
3530fdc8d8SChris Lattner return mask;
3630fdc8d8SChris Lattner }
3730fdc8d8SChris Lattner
FreeEventBits(const uint32_t mask)38b9c1b51eSKate Stone void PThreadEvent::FreeEventBits(const uint32_t mask) {
39b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
40b9c1b51eSKate Stone // __FUNCTION__, mask);
41b9c1b51eSKate Stone if (mask) {
4230fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
4330fdc8d8SChris Lattner m_bits &= ~mask;
4430fdc8d8SChris Lattner m_validBits &= ~mask;
4530fdc8d8SChris Lattner }
4630fdc8d8SChris Lattner }
4730fdc8d8SChris Lattner
GetEventBits() const48b9c1b51eSKate Stone uint32_t PThreadEvent::GetEventBits() const {
49f343968fSZachary Turner // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
5030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
5130fdc8d8SChris Lattner uint32_t bits = m_bits;
5230fdc8d8SChris Lattner return bits;
5330fdc8d8SChris Lattner }
5430fdc8d8SChris Lattner
5530fdc8d8SChris Lattner // Replace the event bits with a new bitmask value
ReplaceEventBits(const uint32_t bits)56b9c1b51eSKate Stone void PThreadEvent::ReplaceEventBits(const uint32_t bits) {
57b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
58b9c1b51eSKate Stone // __FUNCTION__, bits);
5930fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
6030fdc8d8SChris Lattner // Make sure we have some bits and that they aren't already set...
61b9c1b51eSKate Stone if (m_bits != bits) {
6230fdc8d8SChris Lattner // Figure out which bits are changing
6330fdc8d8SChris Lattner uint32_t changed_bits = m_bits ^ bits;
6430fdc8d8SChris Lattner // Set the new bit values
6530fdc8d8SChris Lattner m_bits = bits;
6630fdc8d8SChris Lattner // If any new bits are set, then broadcast
6730fdc8d8SChris Lattner if (changed_bits & m_bits)
6830fdc8d8SChris Lattner m_set_condition.Broadcast();
6930fdc8d8SChris Lattner }
7030fdc8d8SChris Lattner }
7130fdc8d8SChris Lattner
7230fdc8d8SChris Lattner // Set one or more event bits and broadcast if any new event bits get set
7330fdc8d8SChris Lattner // that weren't already set.
7430fdc8d8SChris Lattner
SetEvents(const uint32_t mask)75b9c1b51eSKate Stone void PThreadEvent::SetEvents(const uint32_t mask) {
76b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
77b9c1b51eSKate Stone // __FUNCTION__, mask);
7830fdc8d8SChris Lattner // Make sure we have some bits to set
79b9c1b51eSKate Stone if (mask) {
8030fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
8130fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change
8230fdc8d8SChris Lattner uint32_t old = m_bits;
8330fdc8d8SChris Lattner // Set the all event bits that are set in 'mask'
8430fdc8d8SChris Lattner m_bits |= mask;
8530fdc8d8SChris Lattner // Broadcast only if any extra bits got set.
8630fdc8d8SChris Lattner if (old != m_bits)
8730fdc8d8SChris Lattner m_set_condition.Broadcast();
8830fdc8d8SChris Lattner }
8930fdc8d8SChris Lattner }
9030fdc8d8SChris Lattner
9130fdc8d8SChris Lattner // Reset one or more event bits
ResetEvents(const uint32_t mask)92b9c1b51eSKate Stone void PThreadEvent::ResetEvents(const uint32_t mask) {
93b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
94b9c1b51eSKate Stone // __FUNCTION__, mask);
95b9c1b51eSKate Stone if (mask) {
9630fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
9730fdc8d8SChris Lattner
9830fdc8d8SChris Lattner // Save the old event bit state so we can tell if things change
9930fdc8d8SChris Lattner uint32_t old = m_bits;
10030fdc8d8SChris Lattner // Clear the all event bits that are set in 'mask'
10130fdc8d8SChris Lattner m_bits &= ~mask;
10230fdc8d8SChris Lattner // Broadcast only if any extra bits got reset.
10330fdc8d8SChris Lattner if (old != m_bits)
10430fdc8d8SChris Lattner m_reset_condition.Broadcast();
10530fdc8d8SChris Lattner }
10630fdc8d8SChris Lattner }
10730fdc8d8SChris Lattner
10830fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in
10930fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
11030fdc8d8SChris Lattner uint32_t
WaitForSetEvents(const uint32_t mask,const struct timespec * timeout_abstime) const111b9c1b51eSKate Stone PThreadEvent::WaitForSetEvents(const uint32_t mask,
112b9c1b51eSKate Stone const struct timespec *timeout_abstime) const {
113b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
114b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime);
11530fdc8d8SChris Lattner int err = 0;
11630fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically
11730fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either
11830fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock
11930fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this
12030fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex.
12130fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
122b9c1b51eSKate Stone do {
12330fdc8d8SChris Lattner // Check our predicate (event bits) in case any are already set
124b9c1b51eSKate Stone if (mask & m_bits) {
12530fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits;
12630fdc8d8SChris Lattner // Our PThreadMutex::Locker will automatically unlock our mutex
12730fdc8d8SChris Lattner return bits_set;
12830fdc8d8SChris Lattner }
129b9c1b51eSKate Stone if (timeout_abstime) {
13030fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get
13130fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which
13230fdc8d8SChris Lattner // is what we want.
133b9c1b51eSKate Stone err = ::pthread_cond_timedwait(m_set_condition.Condition(),
134b9c1b51eSKate Stone m_mutex.Mutex(), timeout_abstime);
13530fdc8d8SChris Lattner // Retest our predicate in case of a race condition right at the end
13630fdc8d8SChris Lattner // of the timeout.
137b9c1b51eSKate Stone if (err == ETIMEDOUT) {
13830fdc8d8SChris Lattner uint32_t bits_set = mask & m_bits;
13930fdc8d8SChris Lattner return bits_set;
14030fdc8d8SChris Lattner }
141b9c1b51eSKate Stone } else {
14230fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function
14330fdc8d8SChris Lattner // should return is if
14430fdc8d8SChris Lattner err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex());
14530fdc8d8SChris Lattner }
14630fdc8d8SChris Lattner } while (err == 0);
14730fdc8d8SChris Lattner return 0;
14830fdc8d8SChris Lattner }
14930fdc8d8SChris Lattner
15030fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset.
15130fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever.
WaitForEventsToReset(const uint32_t mask,const struct timespec * timeout_abstime) const152b9c1b51eSKate Stone uint32_t PThreadEvent::WaitForEventsToReset(
153b9c1b51eSKate Stone const uint32_t mask, const struct timespec *timeout_abstime) const {
154b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
155b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime);
15630fdc8d8SChris Lattner int err = 0;
15730fdc8d8SChris Lattner // pthread_cond_timedwait() or pthread_cond_wait() will atomically
15830fdc8d8SChris Lattner // unlock the mutex and wait for the condition to be set. When either
15930fdc8d8SChris Lattner // function returns, they will re-lock the mutex. We use an auto lock/unlock
16030fdc8d8SChris Lattner // class (PThreadMutex::Locker) to allow us to return at any point in this
16130fdc8d8SChris Lattner // function and not have to worry about unlocking the mutex.
16230fdc8d8SChris Lattner PTHREAD_MUTEX_LOCKER(locker, m_mutex);
163b9c1b51eSKate Stone do {
16430fdc8d8SChris Lattner // Check our predicate (event bits) each time through this do loop
165b9c1b51eSKate Stone if ((mask & m_bits) == 0) {
16630fdc8d8SChris Lattner // All the bits requested have been reset, return zero indicating
16730fdc8d8SChris Lattner // which bits from the mask were still set (none of them)
16830fdc8d8SChris Lattner return 0;
16930fdc8d8SChris Lattner }
170b9c1b51eSKate Stone if (timeout_abstime) {
17130fdc8d8SChris Lattner // Wait for condition to get broadcast, or for a timeout. If we get
17230fdc8d8SChris Lattner // a timeout we will drop out of the do loop and return false which
17330fdc8d8SChris Lattner // is what we want.
174b9c1b51eSKate Stone err = ::pthread_cond_timedwait(m_reset_condition.Condition(),
175b9c1b51eSKate Stone m_mutex.Mutex(), timeout_abstime);
176b9c1b51eSKate Stone } else {
17730fdc8d8SChris Lattner // Wait for condition to get broadcast. The only error this function
17830fdc8d8SChris Lattner // should return is if
17930fdc8d8SChris Lattner err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex());
18030fdc8d8SChris Lattner }
18130fdc8d8SChris Lattner } while (err == 0);
18230fdc8d8SChris Lattner // Return a mask indicating which bits (if any) were still set
18330fdc8d8SChris Lattner return mask & m_bits;
18430fdc8d8SChris Lattner }
18530fdc8d8SChris Lattner
18630fdc8d8SChris Lattner uint32_t
WaitForResetAck(const uint32_t mask,const struct timespec * timeout_abstime) const187b9c1b51eSKate Stone PThreadEvent::WaitForResetAck(const uint32_t mask,
188b9c1b51eSKate Stone const struct timespec *timeout_abstime) const {
189b9c1b51eSKate Stone if (mask & m_reset_ack_mask) {
190b9c1b51eSKate Stone // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
191b9c1b51eSKate Stone // __FUNCTION__, mask, timeout_abstime);
19230fdc8d8SChris Lattner return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime);
19330fdc8d8SChris Lattner }
19430fdc8d8SChris Lattner return 0;
19530fdc8d8SChris Lattner }
196