130fdc8d8SChris Lattner //===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner //
1030fdc8d8SChris Lattner //  Created by Greg Clayton on 6/16/07.
1130fdc8d8SChris Lattner //
1230fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner #include "PThreadEvent.h"
1530fdc8d8SChris Lattner #include "errno.h"
1630fdc8d8SChris Lattner #include "DNBLog.h"
1730fdc8d8SChris Lattner 
1830fdc8d8SChris Lattner PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) :
1930fdc8d8SChris Lattner     m_mutex(),
2030fdc8d8SChris Lattner     m_set_condition(),
2130fdc8d8SChris Lattner     m_reset_condition(),
2230fdc8d8SChris Lattner     m_bits(bits),
2330fdc8d8SChris Lattner     m_validBits(validBits),
2430fdc8d8SChris Lattner     m_reset_ack_mask(0)
2530fdc8d8SChris Lattner {
2630fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits);
2730fdc8d8SChris Lattner }
2830fdc8d8SChris Lattner 
2930fdc8d8SChris Lattner PThreadEvent::~PThreadEvent()
3030fdc8d8SChris Lattner {
31*f343968fSZachary Turner     // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
3230fdc8d8SChris Lattner }
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner 
3530fdc8d8SChris Lattner uint32_t
3630fdc8d8SChris Lattner PThreadEvent::NewEventBit()
3730fdc8d8SChris Lattner {
38*f343968fSZachary Turner     // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
3930fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_mutex);
4030fdc8d8SChris Lattner     uint32_t mask = 1;
4130fdc8d8SChris Lattner     while (mask & m_validBits)
4230fdc8d8SChris Lattner         mask <<= 1;
4330fdc8d8SChris Lattner     m_validBits |= mask;
4430fdc8d8SChris Lattner     return mask;
4530fdc8d8SChris Lattner }
4630fdc8d8SChris Lattner 
4730fdc8d8SChris Lattner void
4830fdc8d8SChris Lattner PThreadEvent::FreeEventBits(const uint32_t mask)
4930fdc8d8SChris Lattner {
5030fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
5130fdc8d8SChris Lattner     if (mask)
5230fdc8d8SChris Lattner     {
5330fdc8d8SChris Lattner         PTHREAD_MUTEX_LOCKER (locker, m_mutex);
5430fdc8d8SChris Lattner         m_bits &= ~mask;
5530fdc8d8SChris Lattner         m_validBits &= ~mask;
5630fdc8d8SChris Lattner     }
5730fdc8d8SChris Lattner }
5830fdc8d8SChris Lattner 
5930fdc8d8SChris Lattner 
6030fdc8d8SChris Lattner uint32_t
6130fdc8d8SChris Lattner PThreadEvent::GetEventBits() const
6230fdc8d8SChris Lattner {
63*f343968fSZachary Turner     // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
6430fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_mutex);
6530fdc8d8SChris Lattner     uint32_t bits = m_bits;
6630fdc8d8SChris Lattner     return bits;
6730fdc8d8SChris Lattner }
6830fdc8d8SChris Lattner 
6930fdc8d8SChris Lattner // Replace the event bits with a new bitmask value
7030fdc8d8SChris Lattner void
7130fdc8d8SChris Lattner PThreadEvent::ReplaceEventBits(const uint32_t bits)
7230fdc8d8SChris Lattner {
7330fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits);
7430fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_mutex);
7530fdc8d8SChris Lattner     // Make sure we have some bits and that they aren't already set...
7630fdc8d8SChris Lattner     if (m_bits != bits)
7730fdc8d8SChris Lattner     {
7830fdc8d8SChris Lattner         // Figure out which bits are changing
7930fdc8d8SChris Lattner         uint32_t changed_bits = m_bits ^ bits;
8030fdc8d8SChris Lattner         // Set the new bit values
8130fdc8d8SChris Lattner         m_bits = bits;
8230fdc8d8SChris Lattner         // If any new bits are set, then broadcast
8330fdc8d8SChris Lattner         if (changed_bits & m_bits)
8430fdc8d8SChris Lattner             m_set_condition.Broadcast();
8530fdc8d8SChris Lattner     }
8630fdc8d8SChris Lattner }
8730fdc8d8SChris Lattner 
8830fdc8d8SChris Lattner // Set one or more event bits and broadcast if any new event bits get set
8930fdc8d8SChris Lattner // that weren't already set.
9030fdc8d8SChris Lattner 
9130fdc8d8SChris Lattner void
9230fdc8d8SChris Lattner PThreadEvent::SetEvents(const uint32_t mask)
9330fdc8d8SChris Lattner {
9430fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
9530fdc8d8SChris Lattner     // Make sure we have some bits to set
9630fdc8d8SChris Lattner     if (mask)
9730fdc8d8SChris Lattner     {
9830fdc8d8SChris Lattner         PTHREAD_MUTEX_LOCKER (locker, m_mutex);
9930fdc8d8SChris Lattner         // Save the old event bit state so we can tell if things change
10030fdc8d8SChris Lattner         uint32_t old = m_bits;
10130fdc8d8SChris Lattner         // Set the all event bits that are set in 'mask'
10230fdc8d8SChris Lattner         m_bits |= mask;
10330fdc8d8SChris Lattner         // Broadcast only if any extra bits got set.
10430fdc8d8SChris Lattner         if (old != m_bits)
10530fdc8d8SChris Lattner             m_set_condition.Broadcast();
10630fdc8d8SChris Lattner     }
10730fdc8d8SChris Lattner }
10830fdc8d8SChris Lattner 
10930fdc8d8SChris Lattner // Reset one or more event bits
11030fdc8d8SChris Lattner void
11130fdc8d8SChris Lattner PThreadEvent::ResetEvents(const uint32_t mask)
11230fdc8d8SChris Lattner {
11330fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
11430fdc8d8SChris Lattner     if (mask)
11530fdc8d8SChris Lattner     {
11630fdc8d8SChris Lattner         PTHREAD_MUTEX_LOCKER (locker, m_mutex);
11730fdc8d8SChris Lattner 
11830fdc8d8SChris Lattner         // Save the old event bit state so we can tell if things change
11930fdc8d8SChris Lattner         uint32_t old = m_bits;
12030fdc8d8SChris Lattner         // Clear the all event bits that are set in 'mask'
12130fdc8d8SChris Lattner         m_bits &= ~mask;
12230fdc8d8SChris Lattner         // Broadcast only if any extra bits got reset.
12330fdc8d8SChris Lattner         if (old != m_bits)
12430fdc8d8SChris Lattner             m_reset_condition.Broadcast();
12530fdc8d8SChris Lattner     }
12630fdc8d8SChris Lattner }
12730fdc8d8SChris Lattner 
12830fdc8d8SChris Lattner //----------------------------------------------------------------------
12930fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events that are set in
13030fdc8d8SChris Lattner // 'mask'. If 'timeout_abstime' is NULL, then wait forever.
13130fdc8d8SChris Lattner //----------------------------------------------------------------------
13230fdc8d8SChris Lattner uint32_t
13330fdc8d8SChris Lattner PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const
13430fdc8d8SChris Lattner {
13530fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
13630fdc8d8SChris Lattner     int err = 0;
13730fdc8d8SChris Lattner     // pthread_cond_timedwait() or pthread_cond_wait() will atomically
13830fdc8d8SChris Lattner     // unlock the mutex and wait for the condition to be set. When either
13930fdc8d8SChris Lattner     // function returns, they will re-lock the mutex. We use an auto lock/unlock
14030fdc8d8SChris Lattner     // class (PThreadMutex::Locker) to allow us to return at any point in this
14130fdc8d8SChris Lattner     // function and not have to worry about unlocking the mutex.
14230fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_mutex);
14330fdc8d8SChris Lattner     do
14430fdc8d8SChris Lattner     {
14530fdc8d8SChris Lattner         // Check our predicate (event bits) in case any are already set
14630fdc8d8SChris Lattner         if (mask & m_bits)
14730fdc8d8SChris Lattner         {
14830fdc8d8SChris Lattner             uint32_t bits_set = mask & m_bits;
14930fdc8d8SChris Lattner             // Our PThreadMutex::Locker will automatically unlock our mutex
15030fdc8d8SChris Lattner             return bits_set;
15130fdc8d8SChris Lattner         }
15230fdc8d8SChris Lattner         if (timeout_abstime)
15330fdc8d8SChris Lattner         {
15430fdc8d8SChris Lattner             // Wait for condition to get broadcast, or for a timeout. If we get
15530fdc8d8SChris Lattner             // a timeout we will drop out of the do loop and return false which
15630fdc8d8SChris Lattner             // is what we want.
15730fdc8d8SChris Lattner             err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
15830fdc8d8SChris Lattner             // Retest our predicate in case of a race condition right at the end
15930fdc8d8SChris Lattner             // of the timeout.
16030fdc8d8SChris Lattner             if (err == ETIMEDOUT)
16130fdc8d8SChris Lattner             {
16230fdc8d8SChris Lattner                 uint32_t bits_set = mask & m_bits;
16330fdc8d8SChris Lattner                 return bits_set;
16430fdc8d8SChris Lattner             }
16530fdc8d8SChris Lattner         }
16630fdc8d8SChris Lattner         else
16730fdc8d8SChris Lattner         {
16830fdc8d8SChris Lattner             // Wait for condition to get broadcast. The only error this function
16930fdc8d8SChris Lattner             // should return is if
17030fdc8d8SChris Lattner             err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex());
17130fdc8d8SChris Lattner         }
17230fdc8d8SChris Lattner     } while (err == 0);
17330fdc8d8SChris Lattner     return 0;
17430fdc8d8SChris Lattner }
17530fdc8d8SChris Lattner 
17630fdc8d8SChris Lattner //----------------------------------------------------------------------
17730fdc8d8SChris Lattner // Wait until 'timeout_abstime' for any events in 'mask' to reset.
17830fdc8d8SChris Lattner // If 'timeout_abstime' is NULL, then wait forever.
17930fdc8d8SChris Lattner //----------------------------------------------------------------------
18030fdc8d8SChris Lattner uint32_t
18130fdc8d8SChris Lattner PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const
18230fdc8d8SChris Lattner {
18330fdc8d8SChris Lattner     // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
18430fdc8d8SChris Lattner     int err = 0;
18530fdc8d8SChris Lattner     // pthread_cond_timedwait() or pthread_cond_wait() will atomically
18630fdc8d8SChris Lattner     // unlock the mutex and wait for the condition to be set. When either
18730fdc8d8SChris Lattner     // function returns, they will re-lock the mutex. We use an auto lock/unlock
18830fdc8d8SChris Lattner     // class (PThreadMutex::Locker) to allow us to return at any point in this
18930fdc8d8SChris Lattner     // function and not have to worry about unlocking the mutex.
19030fdc8d8SChris Lattner     PTHREAD_MUTEX_LOCKER (locker, m_mutex);
19130fdc8d8SChris Lattner     do
19230fdc8d8SChris Lattner     {
19330fdc8d8SChris Lattner         // Check our predicate (event bits) each time through this do loop
19430fdc8d8SChris Lattner         if ((mask & m_bits) == 0)
19530fdc8d8SChris Lattner         {
19630fdc8d8SChris Lattner             // All the bits requested have been reset, return zero indicating
19730fdc8d8SChris Lattner             // which bits from the mask were still set (none of them)
19830fdc8d8SChris Lattner             return 0;
19930fdc8d8SChris Lattner         }
20030fdc8d8SChris Lattner         if (timeout_abstime)
20130fdc8d8SChris Lattner         {
20230fdc8d8SChris Lattner             // Wait for condition to get broadcast, or for a timeout. If we get
20330fdc8d8SChris Lattner             // a timeout we will drop out of the do loop and return false which
20430fdc8d8SChris Lattner             // is what we want.
20530fdc8d8SChris Lattner             err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
20630fdc8d8SChris Lattner         }
20730fdc8d8SChris Lattner         else
20830fdc8d8SChris Lattner         {
20930fdc8d8SChris Lattner             // Wait for condition to get broadcast. The only error this function
21030fdc8d8SChris Lattner             // should return is if
21130fdc8d8SChris Lattner             err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex());
21230fdc8d8SChris Lattner         }
21330fdc8d8SChris Lattner     } while (err == 0);
21430fdc8d8SChris Lattner     // Return a mask indicating which bits (if any) were still set
21530fdc8d8SChris Lattner     return mask & m_bits;
21630fdc8d8SChris Lattner }
21730fdc8d8SChris Lattner 
21830fdc8d8SChris Lattner uint32_t
21930fdc8d8SChris Lattner PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const
22030fdc8d8SChris Lattner {
22130fdc8d8SChris Lattner     if (mask & m_reset_ack_mask)
22230fdc8d8SChris Lattner     {
22330fdc8d8SChris Lattner         // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
22430fdc8d8SChris Lattner         return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime);
22530fdc8d8SChris Lattner     }
22630fdc8d8SChris Lattner     return 0;
22730fdc8d8SChris Lattner }
228