aboutsummaryrefslogtreecommitdiff
path: root/tools/debugserver/source/RNBContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/debugserver/source/RNBContext.cpp')
-rw-r--r--tools/debugserver/source/RNBContext.cpp279
1 files changed, 279 insertions, 0 deletions
diff --git a/tools/debugserver/source/RNBContext.cpp b/tools/debugserver/source/RNBContext.cpp
new file mode 100644
index 000000000000..74ba5c45cb4b
--- /dev/null
+++ b/tools/debugserver/source/RNBContext.cpp
@@ -0,0 +1,279 @@
+//===-- 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 <sys/stat.h>
+#include <sstream>
+
+#if defined (__APPLE__)
+#include <pthread.h>
+#include <sched.h>
+#endif
+
+#include "RNBRemote.h"
+#include "DNB.h"
+#include "DNBLog.h"
+#include "CFString.h"
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RNBContext::~RNBContext()
+{
+ SetProcessID (INVALID_NUB_PROCESS);
+}
+
+//----------------------------------------------------------------------
+// RNBContext constructor
+//----------------------------------------------------------------------
+
+const char *
+RNBContext::EnvironmentAtIndex (size_t index)
+{
+ if (index < m_env_vec.size())
+ return m_env_vec[index].c_str();
+ else
+ return NULL;
+}
+
+
+const char *
+RNBContext::ArgumentAtIndex (size_t index)
+{
+ if (index < m_arg_vec.size())
+ return m_arg_vec[index].c_str();
+ else
+ return NULL;
+}
+
+bool
+RNBContext::SetWorkingDirectory (const char *path)
+{
+ struct stat working_directory_stat;
+ if (::stat (path, &working_directory_stat) != 0)
+ {
+ m_working_directory.clear();
+ return false;
+ }
+ m_working_directory.assign(path);
+ return true;
+}
+
+
+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);
+
+#if defined (__APPLE__)
+ pthread_setname_np ("child process status watcher thread");
+#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
+ struct sched_param thread_param;
+ int thread_sched_policy;
+ if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0)
+ {
+ thread_param.sched_priority = 47;
+ pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
+ }
+#endif
+#endif
+
+ bool done = false;
+ while (!done)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true)...", __FUNCTION__);
+ nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true, NULL);
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, 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 & eEventProfileDataAvailable)
+ {
+ DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got profile data event....", __FUNCTION__, pid);
+ ctx.Events().SetEvents (RNBContext::event_proc_profile_data);
+ // Wait for the main thread to consume this notification if it requested we wait for it
+ ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data);
+ }
+
+ 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:
+ case eStateDetached:
+ done = true;
+ break;
+ default:
+ 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_proc_profile_data)
+ s += "proc_profile_data ";
+ 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;
+}