forked from OSchip/llvm-project
252 lines
8.3 KiB
C++
252 lines
8.3 KiB
C++
//===-- 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>
|
|
|
|
#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 (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;
|
|
}
|
|
|
|
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);
|
|
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:
|
|
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_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;
|
|
}
|