Initial checkin of lldb code from internal Apple repo.

llvm-svn: 105619
diff --git a/lldb/tools/debugserver/source/PThreadEvent.cpp b/lldb/tools/debugserver/source/PThreadEvent.cpp
new file mode 100644
index 0000000..b087bfc
--- /dev/null
+++ b/lldb/tools/debugserver/source/PThreadEvent.cpp
@@ -0,0 +1,227 @@
+//===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Created by Greg Clayton on 6/16/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PThreadEvent.h"
+#include "errno.h"
+#include "DNBLog.h"
+
+PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) :
+    m_mutex(),
+    m_set_condition(),
+    m_reset_condition(),
+    m_bits(bits),
+    m_validBits(validBits),
+    m_reset_ack_mask(0)
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits);
+}
+
+PThreadEvent::~PThreadEvent()
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+}
+
+
+uint32_t
+PThreadEvent::NewEventBit()
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+    uint32_t mask = 1;
+    while (mask & m_validBits)
+        mask <<= 1;
+    m_validBits |= mask;
+    return mask;
+}
+
+void
+PThreadEvent::FreeEventBits(const uint32_t mask)
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+    if (mask)
+    {
+        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+        m_bits &= ~mask;
+        m_validBits &= ~mask;
+    }
+}
+
+
+uint32_t
+PThreadEvent::GetEventBits() const
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, __PRETTY_FUNCTION__);
+    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+    uint32_t bits = m_bits;
+    return bits;
+}
+
+// Replace the event bits with a new bitmask value
+void
+PThreadEvent::ReplaceEventBits(const uint32_t bits)
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits);
+    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+    // Make sure we have some bits and that they aren't already set...
+    if (m_bits != bits)
+    {
+        // Figure out which bits are changing
+        uint32_t changed_bits = m_bits ^ bits;
+        // Set the new bit values
+        m_bits = bits;
+        // If any new bits are set, then broadcast
+        if (changed_bits & m_bits)
+            m_set_condition.Broadcast();
+    }
+}
+
+// Set one or more event bits and broadcast if any new event bits get set
+// that weren't already set.
+
+void
+PThreadEvent::SetEvents(const uint32_t mask)
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+    // Make sure we have some bits to set
+    if (mask)
+    {
+        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+        // Save the old event bit state so we can tell if things change
+        uint32_t old = m_bits;
+        // Set the all event bits that are set in 'mask'
+        m_bits |= mask;
+        // Broadcast only if any extra bits got set.
+        if (old != m_bits)
+            m_set_condition.Broadcast();
+    }
+}
+
+// Reset one or more event bits
+void
+PThreadEvent::ResetEvents(const uint32_t mask)
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask);
+    if (mask)
+    {
+        PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+
+        // Save the old event bit state so we can tell if things change
+        uint32_t old = m_bits;
+        // Clear the all event bits that are set in 'mask'
+        m_bits &= ~mask;
+        // Broadcast only if any extra bits got reset.
+        if (old != m_bits)
+            m_reset_condition.Broadcast();
+    }
+}
+
+//----------------------------------------------------------------------
+// Wait until 'timeout_abstime' for any events that are set in
+// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
+//----------------------------------------------------------------------
+uint32_t
+PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+    int err = 0;
+    // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+    // unlock the mutex and wait for the condition to be set. When either
+    // function returns, they will re-lock the mutex. We use an auto lock/unlock
+    // class (PThreadMutex::Locker) to allow us to return at any point in this
+    // function and not have to worry about unlocking the mutex.
+    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+    do
+    {
+        // Check our predicate (event bits) in case any are already set
+        if (mask & m_bits)
+        {
+            uint32_t bits_set = mask & m_bits;
+            // Our PThreadMutex::Locker will automatically unlock our mutex
+            return bits_set;
+        }
+        if (timeout_abstime)
+        {
+            // Wait for condition to get broadcast, or for a timeout. If we get
+            // a timeout we will drop out of the do loop and return false which
+            // is what we want.
+            err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
+            // Retest our predicate in case of a race condition right at the end
+            // of the timeout.
+            if (err == ETIMEDOUT)
+            {
+                uint32_t bits_set = mask & m_bits;
+                return bits_set;
+            }
+        }
+        else
+        {
+            // Wait for condition to get broadcast. The only error this function
+            // should return is if
+            err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex());
+        }
+    } while (err == 0);
+    return 0;
+}
+
+//----------------------------------------------------------------------
+// Wait until 'timeout_abstime' for any events in 'mask' to reset.
+// If 'timeout_abstime' is NULL, then wait forever.
+//----------------------------------------------------------------------
+uint32_t
+PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+    // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+    int err = 0;
+    // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+    // unlock the mutex and wait for the condition to be set. When either
+    // function returns, they will re-lock the mutex. We use an auto lock/unlock
+    // class (PThreadMutex::Locker) to allow us to return at any point in this
+    // function and not have to worry about unlocking the mutex.
+    PTHREAD_MUTEX_LOCKER (locker, m_mutex);
+    do
+    {
+        // Check our predicate (event bits) each time through this do loop
+        if ((mask & m_bits) == 0)
+        {
+            // All the bits requested have been reset, return zero indicating
+            // which bits from the mask were still set (none of them)
+            return 0;
+        }
+        if (timeout_abstime)
+        {
+            // Wait for condition to get broadcast, or for a timeout. If we get
+            // a timeout we will drop out of the do loop and return false which
+            // is what we want.
+            err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime);
+        }
+        else
+        {
+            // Wait for condition to get broadcast. The only error this function
+            // should return is if
+            err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex());
+        }
+    } while (err == 0);
+    // Return a mask indicating which bits (if any) were still set
+    return mask & m_bits;
+}
+
+uint32_t
+PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const
+{
+    if (mask & m_reset_ack_mask)
+    {
+        // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime);
+        return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime);
+    }
+    return 0;
+}