Initial checkin of lldb code from internal Apple repo.

llvm-svn: 105619
diff --git a/lldb/tools/debugserver/source/RNBContext.cpp b/lldb/tools/debugserver/source/RNBContext.cpp
new file mode 100644
index 0000000..7ef9d32
--- /dev/null
+++ b/lldb/tools/debugserver/source/RNBContext.cpp
@@ -0,0 +1,230 @@
+//===-- RNBContext.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 12/12/07.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RNBContext.h"
+#include "RNBRemote.h"
+#include "DNB.h"
+#include "DNBLog.h"
+#include "CFString.h"
+#include <sstream>
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RNBContext::~RNBContext()
+{
+    SetProcessID (INVALID_NUB_PROCESS);
+}
+
+//----------------------------------------------------------------------
+// RNBContext constructor
+//----------------------------------------------------------------------
+
+const char *
+RNBContext::EnvironmentAtIndex (int index)
+{
+    if (index < m_env_vec.size())
+        return m_env_vec[index].c_str();
+    else
+        return NULL;
+}
+
+
+const char *
+RNBContext::ArgumentAtIndex (int index)
+{
+    if (index < m_arg_vec.size())
+        return m_arg_vec[index].c_str();
+    else
+        return NULL;
+}
+
+void
+RNBContext::SetProcessID (nub_process_t pid)
+{
+    // Delete and events we created
+    if (m_pid != INVALID_NUB_PROCESS)
+    {
+        StopProcessStatusThread ();
+        // Unregister this context as a client of the process's events.
+    }
+    // Assign our new process ID
+    m_pid = pid;
+
+    if (pid != INVALID_NUB_PROCESS)
+    {
+        StartProcessStatusThread ();
+    }
+}
+
+void
+RNBContext::StartProcessStatusThread()
+{
+    DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
+    if ((m_events.GetEventBits() & event_proc_thread_running) == 0)
+    {
+        int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this);
+        if (err == 0)
+        {
+            // Our thread was successfully kicked off, wait for it to
+            // set the started event so we can safely continue
+            m_events.WaitForSetEvents (event_proc_thread_running);
+            DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__);
+        }
+        else
+        {
+            DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err);
+            m_events.ResetEvents (event_proc_thread_running);
+            m_events.SetEvents (event_proc_thread_exiting);
+        }
+    }
+}
+
+void
+RNBContext::StopProcessStatusThread()
+{
+    DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
+    if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running)
+    {
+        struct timespec timeout_abstime;
+        DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
+        // Wait for 2 seconds for the rx thread to exit
+        if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting)
+        {
+            DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__);
+        }
+        else
+        {
+            DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__);
+            // Kill the RX thread???
+        }
+    }
+}
+
+//----------------------------------------------------------------------
+// This thread's sole purpose is to watch for any status changes in the
+// child process.
+//----------------------------------------------------------------------
+void*
+RNBContext::ThreadFunctionProcessStatus(void *arg)
+{
+    RNBRemoteSP remoteSP(g_remoteSP);
+    RNBRemote* remote = remoteSP.get();
+    if (remote == NULL)
+        return NULL;
+    RNBContext& ctx = remote->Context();
+
+    nub_process_t pid = ctx.ProcessID();
+    DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid);
+    ctx.Events().SetEvents (RNBContext::event_proc_thread_running);
+    bool done = false;
+    while (!done)
+    {
+        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
+        nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
+        DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
+
+        if (pid_status_event == 0)
+        {
+            DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid);
+        //    done = true;
+        }
+        else
+        {
+            if (pid_status_event & eEventStdioAvailable)
+            {
+                DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid);
+                ctx.Events().SetEvents (RNBContext::event_proc_stdio_available);
+                // Wait for the main thread to consume this notification if it requested we wait for it
+                ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
+            }
+
+
+            if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
+            {
+                nub_state_t pid_state = DNBProcessGetState(pid);
+                DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
+
+                // Let the main thread know there is a process state change to see
+                ctx.Events().SetEvents (RNBContext::event_proc_state_changed);
+                // Wait for the main thread to consume this notification if it requested we wait for it
+                ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
+
+                switch (pid_state)
+                {
+                case eStateStopped:
+                    break;
+
+                case eStateInvalid:
+                case eStateExited:
+                    done = true;
+                    break;
+                }
+            }
+
+            // Reset any events that we consumed.
+            DNBProcessResetEvents(pid, pid_status_event);
+
+        }
+    }
+    DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
+    ctx.Events().ResetEvents(event_proc_thread_running);
+    ctx.Events().SetEvents(event_proc_thread_exiting);
+    return NULL;
+}
+
+
+const char*
+RNBContext::EventsAsString (nub_event_t events, std::string& s)
+{
+    s.clear();
+    if (events & event_proc_state_changed)
+        s += "proc_state_changed ";
+    if (events & event_proc_thread_running)
+        s += "proc_thread_running ";
+    if (events & event_proc_thread_exiting)
+        s += "proc_thread_exiting ";
+    if (events & event_proc_stdio_available)
+        s += "proc_stdio_available ";
+    if (events & event_read_packet_available)
+        s += "read_packet_available ";
+    if (events & event_read_thread_running)
+        s += "read_thread_running ";
+    if (events & event_read_thread_running)
+        s += "read_thread_running ";
+    return s.c_str();
+}
+
+const char *
+RNBContext::LaunchStatusAsString (std::string& s)
+{
+    s.clear();
+
+    const char *err_str = m_launch_status.AsString();
+    if (err_str)
+        s = err_str;
+    else
+    {
+        char error_num_str[64];
+        snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
+        s = error_num_str;
+    }
+    return s.c_str();
+}
+
+bool
+RNBContext::ProcessStateRunning() const
+{
+    nub_state_t pid_state = DNBProcessGetState(m_pid);
+    return pid_state == eStateRunning || pid_state == eStateStepping;
+}