RNBContext.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
1//===-- RNBContext.cpp ------------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Created by Greg Clayton on 12/12/07. 11// 12//===----------------------------------------------------------------------===// 13 14#include "RNBContext.h" 15#include "RNBRemote.h" 16#include "DNB.h" 17#include "DNBLog.h" 18#include "CFString.h" 19#include <sstream> 20 21//---------------------------------------------------------------------- 22// Destructor 23//---------------------------------------------------------------------- 24RNBContext::~RNBContext() 25{ 26 SetProcessID (INVALID_NUB_PROCESS); 27} 28 29//---------------------------------------------------------------------- 30// RNBContext constructor 31//---------------------------------------------------------------------- 32 33const char * 34RNBContext::EnvironmentAtIndex (int index) 35{ 36 if (index < m_env_vec.size()) 37 return m_env_vec[index].c_str(); 38 else 39 return NULL; 40} 41 42 43const char * 44RNBContext::ArgumentAtIndex (int index) 45{ 46 if (index < m_arg_vec.size()) 47 return m_arg_vec[index].c_str(); 48 else 49 return NULL; 50} 51 52void 53RNBContext::SetProcessID (nub_process_t pid) 54{ 55 // Delete and events we created 56 if (m_pid != INVALID_NUB_PROCESS) 57 { 58 StopProcessStatusThread (); 59 // Unregister this context as a client of the process's events. 60 } 61 // Assign our new process ID 62 m_pid = pid; 63 64 if (pid != INVALID_NUB_PROCESS) 65 { 66 StartProcessStatusThread (); 67 } 68} 69 70void 71RNBContext::StartProcessStatusThread() 72{ 73 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); 74 if ((m_events.GetEventBits() & event_proc_thread_running) == 0) 75 { 76 int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this); 77 if (err == 0) 78 { 79 // Our thread was successfully kicked off, wait for it to 80 // set the started event so we can safely continue 81 m_events.WaitForSetEvents (event_proc_thread_running); 82 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__); 83 } 84 else 85 { 86 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err); 87 m_events.ResetEvents (event_proc_thread_running); 88 m_events.SetEvents (event_proc_thread_exiting); 89 } 90 } 91} 92 93void 94RNBContext::StopProcessStatusThread() 95{ 96 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); 97 if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running) 98 { 99 struct timespec timeout_abstime; 100 DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); 101 // Wait for 2 seconds for the rx thread to exit 102 if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting) 103 { 104 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__); 105 } 106 else 107 { 108 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__); 109 // Kill the RX thread??? 110 } 111 } 112} 113 114//---------------------------------------------------------------------- 115// This thread's sole purpose is to watch for any status changes in the 116// child process. 117//---------------------------------------------------------------------- 118void* 119RNBContext::ThreadFunctionProcessStatus(void *arg) 120{ 121 RNBRemoteSP remoteSP(g_remoteSP); 122 RNBRemote* remote = remoteSP.get(); 123 if (remote == NULL) 124 return NULL; 125 RNBContext& ctx = remote->Context(); 126 127 nub_process_t pid = ctx.ProcessID(); 128 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid); 129 ctx.Events().SetEvents (RNBContext::event_proc_thread_running); 130 bool done = false; 131 while (!done) 132 { 133 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__); 134 nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL); 135 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event); 136 137 if (pid_status_event == 0) 138 { 139 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid); 140 // done = true; 141 } 142 else 143 { 144 if (pid_status_event & eEventStdioAvailable) 145 { 146 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid); 147 ctx.Events().SetEvents (RNBContext::event_proc_stdio_available); 148 // Wait for the main thread to consume this notification if it requested we wait for it 149 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available); 150 } 151 152 153 if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) 154 { 155 nub_state_t pid_state = DNBProcessGetState(pid); 156 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state)); 157 158 // Let the main thread know there is a process state change to see 159 ctx.Events().SetEvents (RNBContext::event_proc_state_changed); 160 // Wait for the main thread to consume this notification if it requested we wait for it 161 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed); 162 163 switch (pid_state) 164 { 165 case eStateStopped: 166 break; 167 168 case eStateInvalid: 169 case eStateExited: 170 done = true; 171 break; 172 } 173 } 174 175 // Reset any events that we consumed. 176 DNBProcessResetEvents(pid, pid_status_event); 177 178 } 179 } 180 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid); 181 ctx.Events().ResetEvents(event_proc_thread_running); 182 ctx.Events().SetEvents(event_proc_thread_exiting); 183 return NULL; 184} 185 186 187const char* 188RNBContext::EventsAsString (nub_event_t events, std::string& s) 189{ 190 s.clear(); 191 if (events & event_proc_state_changed) 192 s += "proc_state_changed "; 193 if (events & event_proc_thread_running) 194 s += "proc_thread_running "; 195 if (events & event_proc_thread_exiting) 196 s += "proc_thread_exiting "; 197 if (events & event_proc_stdio_available) 198 s += "proc_stdio_available "; 199 if (events & event_read_packet_available) 200 s += "read_packet_available "; 201 if (events & event_read_thread_running) 202 s += "read_thread_running "; 203 if (events & event_read_thread_running) 204 s += "read_thread_running "; 205 return s.c_str(); 206} 207 208const char * 209RNBContext::LaunchStatusAsString (std::string& s) 210{ 211 s.clear(); 212 213 const char *err_str = m_launch_status.AsString(); 214 if (err_str) 215 s = err_str; 216 else 217 { 218 char error_num_str[64]; 219 snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error()); 220 s = error_num_str; 221 } 222 return s.c_str(); 223} 224 225bool 226RNBContext::ProcessStateRunning() const 227{ 228 nub_state_t pid_state = DNBProcessGetState(m_pid); 229 return pid_state == eStateRunning || pid_state == eStateStepping; 230} 231