130fdc8d8SChris Lattner //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler 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"
15b9c1b51eSKate Stone #include "errno.h"
1630fdc8d8SChris Lattner 
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 
24b9c1b51eSKate Stone PThreadEvent::~PThreadEvent() {
25f343968fSZachary Turner   // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
2630fdc8d8SChris Lattner }
2730fdc8d8SChris Lattner 
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 
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 
48b9c1b51eSKate 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
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 
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
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 //----------------------------------------------------------------------
10930fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in
11030fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
11130fdc8d8SChris Lattner //----------------------------------------------------------------------
11230fdc8d8SChris Lattner uint32_t
113b9c1b51eSKate Stone PThreadEvent::WaitForSetEvents(const uint32_t mask,
114b9c1b51eSKate Stone                                const struct timespec *timeout_abstime) const {
115b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
116b9c1b51eSKate Stone   // __FUNCTION__, mask, timeout_abstime);
11730fdc8d8SChris Lattner   int err = 0;
11830fdc8d8SChris Lattner   // pthread_cond_timedwait() or pthread_cond_wait() will atomically
11930fdc8d8SChris Lattner   // unlock the mutex and wait for the condition to be set. When either
12030fdc8d8SChris Lattner   // function returns, they will re-lock the mutex. We use an auto lock/unlock
12130fdc8d8SChris Lattner   // class (PThreadMutex::Locker) to allow us to return at any point in this
12230fdc8d8SChris Lattner   // function and not have to worry about unlocking the mutex.
12330fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
124b9c1b51eSKate Stone   do {
12530fdc8d8SChris Lattner     // Check our predicate (event bits) in case any are already set
126b9c1b51eSKate Stone     if (mask & m_bits) {
12730fdc8d8SChris Lattner       uint32_t bits_set = mask & m_bits;
12830fdc8d8SChris Lattner       // Our PThreadMutex::Locker will automatically unlock our mutex
12930fdc8d8SChris Lattner       return bits_set;
13030fdc8d8SChris Lattner     }
131b9c1b51eSKate Stone     if (timeout_abstime) {
13230fdc8d8SChris Lattner       // Wait for condition to get broadcast, or for a timeout. If we get
13330fdc8d8SChris Lattner       // a timeout we will drop out of the do loop and return false which
13430fdc8d8SChris Lattner       // is what we want.
135b9c1b51eSKate Stone       err = ::pthread_cond_timedwait(m_set_condition.Condition(),
136b9c1b51eSKate Stone                                      m_mutex.Mutex(), timeout_abstime);
13730fdc8d8SChris Lattner       // Retest our predicate in case of a race condition right at the end
13830fdc8d8SChris Lattner       // of the timeout.
139b9c1b51eSKate Stone       if (err == ETIMEDOUT) {
14030fdc8d8SChris Lattner         uint32_t bits_set = mask & m_bits;
14130fdc8d8SChris Lattner         return bits_set;
14230fdc8d8SChris Lattner       }
143b9c1b51eSKate Stone     } else {
14430fdc8d8SChris Lattner       // Wait for condition to get broadcast. The only error this function
14530fdc8d8SChris Lattner       // should return is if
14630fdc8d8SChris Lattner       err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex());
14730fdc8d8SChris Lattner     }
14830fdc8d8SChris Lattner   } while (err == 0);
14930fdc8d8SChris Lattner   return 0;
15030fdc8d8SChris Lattner }
15130fdc8d8SChris Lattner 
15230fdc8d8SChris Lattner //----------------------------------------------------------------------
15330fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset.
15430fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever.
15530fdc8d8SChris Lattner //----------------------------------------------------------------------
156b9c1b51eSKate Stone uint32_t PThreadEvent::WaitForEventsToReset(
157b9c1b51eSKate Stone     const uint32_t mask, const struct timespec *timeout_abstime) const {
158b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
159b9c1b51eSKate Stone   // __FUNCTION__, mask, timeout_abstime);
16030fdc8d8SChris Lattner   int err = 0;
16130fdc8d8SChris Lattner   // pthread_cond_timedwait() or pthread_cond_wait() will atomically
16230fdc8d8SChris Lattner   // unlock the mutex and wait for the condition to be set. When either
16330fdc8d8SChris Lattner   // function returns, they will re-lock the mutex. We use an auto lock/unlock
16430fdc8d8SChris Lattner   // class (PThreadMutex::Locker) to allow us to return at any point in this
16530fdc8d8SChris Lattner   // function and not have to worry about unlocking the mutex.
16630fdc8d8SChris Lattner   PTHREAD_MUTEX_LOCKER(locker, m_mutex);
167b9c1b51eSKate Stone   do {
16830fdc8d8SChris Lattner     // Check our predicate (event bits) each time through this do loop
169b9c1b51eSKate Stone     if ((mask & m_bits) == 0) {
17030fdc8d8SChris Lattner       // All the bits requested have been reset, return zero indicating
17130fdc8d8SChris Lattner       // which bits from the mask were still set (none of them)
17230fdc8d8SChris Lattner       return 0;
17330fdc8d8SChris Lattner     }
174b9c1b51eSKate Stone     if (timeout_abstime) {
17530fdc8d8SChris Lattner       // Wait for condition to get broadcast, or for a timeout. If we get
17630fdc8d8SChris Lattner       // a timeout we will drop out of the do loop and return false which
17730fdc8d8SChris Lattner       // is what we want.
178b9c1b51eSKate Stone       err = ::pthread_cond_timedwait(m_reset_condition.Condition(),
179b9c1b51eSKate Stone                                      m_mutex.Mutex(), timeout_abstime);
180b9c1b51eSKate Stone     } else {
18130fdc8d8SChris Lattner       // Wait for condition to get broadcast. The only error this function
18230fdc8d8SChris Lattner       // should return is if
18330fdc8d8SChris Lattner       err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex());
18430fdc8d8SChris Lattner     }
18530fdc8d8SChris Lattner   } while (err == 0);
18630fdc8d8SChris Lattner   // Return a mask indicating which bits (if any) were still set
18730fdc8d8SChris Lattner   return mask & m_bits;
18830fdc8d8SChris Lattner }
18930fdc8d8SChris Lattner 
19030fdc8d8SChris Lattner uint32_t
191b9c1b51eSKate Stone PThreadEvent::WaitForResetAck(const uint32_t mask,
192b9c1b51eSKate Stone                               const struct timespec *timeout_abstime) const {
193b9c1b51eSKate Stone   if (mask & m_reset_ack_mask) {
194b9c1b51eSKate Stone     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
195b9c1b51eSKate Stone     // __FUNCTION__, mask, timeout_abstime);
19630fdc8d8SChris Lattner     return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime);
19730fdc8d8SChris Lattner   }
19830fdc8d8SChris Lattner   return 0;
19930fdc8d8SChris Lattner }
200