1061da546Spatrick //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick // Created by Greg Clayton on 6/16/07.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick
13061da546Spatrick #include "PThreadEvent.h"
14061da546Spatrick #include "DNBLog.h"
15*be691f3bSpatrick #include <cerrno>
16061da546Spatrick
PThreadEvent(uint32_t bits,uint32_t validBits)17061da546Spatrick PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits)
18061da546Spatrick : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits),
19061da546Spatrick m_validBits(validBits), m_reset_ack_mask(0) {
20061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)",
21061da546Spatrick // this, __FUNCTION__, bits, validBits);
22061da546Spatrick }
23061da546Spatrick
~PThreadEvent()24061da546Spatrick PThreadEvent::~PThreadEvent() {
25061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
26061da546Spatrick }
27061da546Spatrick
NewEventBit()28061da546Spatrick uint32_t PThreadEvent::NewEventBit() {
29061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
30061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
31061da546Spatrick uint32_t mask = 1;
32061da546Spatrick while (mask & m_validBits)
33061da546Spatrick mask <<= 1;
34061da546Spatrick m_validBits |= mask;
35061da546Spatrick return mask;
36061da546Spatrick }
37061da546Spatrick
FreeEventBits(const uint32_t mask)38061da546Spatrick void PThreadEvent::FreeEventBits(const uint32_t mask) {
39061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
40061da546Spatrick // __FUNCTION__, mask);
41061da546Spatrick if (mask) {
42061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
43061da546Spatrick m_bits &= ~mask;
44061da546Spatrick m_validBits &= ~mask;
45061da546Spatrick }
46061da546Spatrick }
47061da546Spatrick
GetEventBits() const48061da546Spatrick uint32_t PThreadEvent::GetEventBits() const {
49061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
50061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
51061da546Spatrick uint32_t bits = m_bits;
52061da546Spatrick return bits;
53061da546Spatrick }
54061da546Spatrick
55061da546Spatrick // Replace the event bits with a new bitmask value
ReplaceEventBits(const uint32_t bits)56061da546Spatrick void PThreadEvent::ReplaceEventBits(const uint32_t bits) {
57061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
58061da546Spatrick // __FUNCTION__, bits);
59061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
60061da546Spatrick // Make sure we have some bits and that they aren't already set...
61061da546Spatrick if (m_bits != bits) {
62061da546Spatrick // Figure out which bits are changing
63061da546Spatrick uint32_t changed_bits = m_bits ^ bits;
64061da546Spatrick // Set the new bit values
65061da546Spatrick m_bits = bits;
66061da546Spatrick // If any new bits are set, then broadcast
67061da546Spatrick if (changed_bits & m_bits)
68061da546Spatrick m_set_condition.Broadcast();
69061da546Spatrick }
70061da546Spatrick }
71061da546Spatrick
72061da546Spatrick // Set one or more event bits and broadcast if any new event bits get set
73061da546Spatrick // that weren't already set.
74061da546Spatrick
SetEvents(const uint32_t mask)75061da546Spatrick void PThreadEvent::SetEvents(const uint32_t mask) {
76061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
77061da546Spatrick // __FUNCTION__, mask);
78061da546Spatrick // Make sure we have some bits to set
79061da546Spatrick if (mask) {
80061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
81061da546Spatrick // Save the old event bit state so we can tell if things change
82061da546Spatrick uint32_t old = m_bits;
83061da546Spatrick // Set the all event bits that are set in 'mask'
84061da546Spatrick m_bits |= mask;
85061da546Spatrick // Broadcast only if any extra bits got set.
86061da546Spatrick if (old != m_bits)
87061da546Spatrick m_set_condition.Broadcast();
88061da546Spatrick }
89061da546Spatrick }
90061da546Spatrick
91061da546Spatrick // Reset one or more event bits
ResetEvents(const uint32_t mask)92061da546Spatrick void PThreadEvent::ResetEvents(const uint32_t mask) {
93061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
94061da546Spatrick // __FUNCTION__, mask);
95061da546Spatrick if (mask) {
96061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
97061da546Spatrick
98061da546Spatrick // Save the old event bit state so we can tell if things change
99061da546Spatrick uint32_t old = m_bits;
100061da546Spatrick // Clear the all event bits that are set in 'mask'
101061da546Spatrick m_bits &= ~mask;
102061da546Spatrick // Broadcast only if any extra bits got reset.
103061da546Spatrick if (old != m_bits)
104061da546Spatrick m_reset_condition.Broadcast();
105061da546Spatrick }
106061da546Spatrick }
107061da546Spatrick
108061da546Spatrick // Wait until 'timeout_abstime' for any events that are set in
109061da546Spatrick // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
110061da546Spatrick uint32_t
WaitForSetEvents(const uint32_t mask,const struct timespec * timeout_abstime) const111061da546Spatrick PThreadEvent::WaitForSetEvents(const uint32_t mask,
112061da546Spatrick const struct timespec *timeout_abstime) const {
113061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
114061da546Spatrick // __FUNCTION__, mask, timeout_abstime);
115061da546Spatrick int err = 0;
116061da546Spatrick // pthread_cond_timedwait() or pthread_cond_wait() will atomically
117061da546Spatrick // unlock the mutex and wait for the condition to be set. When either
118061da546Spatrick // function returns, they will re-lock the mutex. We use an auto lock/unlock
119061da546Spatrick // class (PThreadMutex::Locker) to allow us to return at any point in this
120061da546Spatrick // function and not have to worry about unlocking the mutex.
121061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
122061da546Spatrick do {
123061da546Spatrick // Check our predicate (event bits) in case any are already set
124061da546Spatrick if (mask & m_bits) {
125061da546Spatrick uint32_t bits_set = mask & m_bits;
126061da546Spatrick // Our PThreadMutex::Locker will automatically unlock our mutex
127061da546Spatrick return bits_set;
128061da546Spatrick }
129061da546Spatrick if (timeout_abstime) {
130061da546Spatrick // Wait for condition to get broadcast, or for a timeout. If we get
131061da546Spatrick // a timeout we will drop out of the do loop and return false which
132061da546Spatrick // is what we want.
133061da546Spatrick err = ::pthread_cond_timedwait(m_set_condition.Condition(),
134061da546Spatrick m_mutex.Mutex(), timeout_abstime);
135061da546Spatrick // Retest our predicate in case of a race condition right at the end
136061da546Spatrick // of the timeout.
137061da546Spatrick if (err == ETIMEDOUT) {
138061da546Spatrick uint32_t bits_set = mask & m_bits;
139061da546Spatrick return bits_set;
140061da546Spatrick }
141061da546Spatrick } else {
142061da546Spatrick // Wait for condition to get broadcast. The only error this function
143061da546Spatrick // should return is if
144061da546Spatrick err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex());
145061da546Spatrick }
146061da546Spatrick } while (err == 0);
147061da546Spatrick return 0;
148061da546Spatrick }
149061da546Spatrick
150061da546Spatrick // Wait until 'timeout_abstime' for any events in 'mask' to reset.
151061da546Spatrick // If 'timeout_abstime' is NULL, then wait forever.
WaitForEventsToReset(const uint32_t mask,const struct timespec * timeout_abstime) const152061da546Spatrick uint32_t PThreadEvent::WaitForEventsToReset(
153061da546Spatrick const uint32_t mask, const struct timespec *timeout_abstime) const {
154061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
155061da546Spatrick // __FUNCTION__, mask, timeout_abstime);
156061da546Spatrick int err = 0;
157061da546Spatrick // pthread_cond_timedwait() or pthread_cond_wait() will atomically
158061da546Spatrick // unlock the mutex and wait for the condition to be set. When either
159061da546Spatrick // function returns, they will re-lock the mutex. We use an auto lock/unlock
160061da546Spatrick // class (PThreadMutex::Locker) to allow us to return at any point in this
161061da546Spatrick // function and not have to worry about unlocking the mutex.
162061da546Spatrick PTHREAD_MUTEX_LOCKER(locker, m_mutex);
163061da546Spatrick do {
164061da546Spatrick // Check our predicate (event bits) each time through this do loop
165061da546Spatrick if ((mask & m_bits) == 0) {
166061da546Spatrick // All the bits requested have been reset, return zero indicating
167061da546Spatrick // which bits from the mask were still set (none of them)
168061da546Spatrick return 0;
169061da546Spatrick }
170061da546Spatrick if (timeout_abstime) {
171061da546Spatrick // Wait for condition to get broadcast, or for a timeout. If we get
172061da546Spatrick // a timeout we will drop out of the do loop and return false which
173061da546Spatrick // is what we want.
174061da546Spatrick err = ::pthread_cond_timedwait(m_reset_condition.Condition(),
175061da546Spatrick m_mutex.Mutex(), timeout_abstime);
176061da546Spatrick } else {
177061da546Spatrick // Wait for condition to get broadcast. The only error this function
178061da546Spatrick // should return is if
179061da546Spatrick err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex());
180061da546Spatrick }
181061da546Spatrick } while (err == 0);
182061da546Spatrick // Return a mask indicating which bits (if any) were still set
183061da546Spatrick return mask & m_bits;
184061da546Spatrick }
185061da546Spatrick
186061da546Spatrick uint32_t
WaitForResetAck(const uint32_t mask,const struct timespec * timeout_abstime) const187061da546Spatrick PThreadEvent::WaitForResetAck(const uint32_t mask,
188061da546Spatrick const struct timespec *timeout_abstime) const {
189061da546Spatrick if (mask & m_reset_ack_mask) {
190061da546Spatrick // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
191061da546Spatrick // __FUNCTION__, mask, timeout_abstime);
192061da546Spatrick return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime);
193061da546Spatrick }
194061da546Spatrick return 0;
195061da546Spatrick }
196