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 //---------------------------------------------------------------------- 24 RNBContext::~RNBContext() 25 { 26 SetProcessID (INVALID_NUB_PROCESS); 27 } 28 29 //---------------------------------------------------------------------- 30 // RNBContext constructor 31 //---------------------------------------------------------------------- 32 33 const char * 34 RNBContext::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 43 const char * 44 RNBContext::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 52 void 53 RNBContext::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 70 void 71 RNBContext::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 93 void 94 RNBContext::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 //---------------------------------------------------------------------- 118 void* 119 RNBContext::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 case eStateDetached: 171 done = true; 172 break; 173 } 174 } 175 176 // Reset any events that we consumed. 177 DNBProcessResetEvents(pid, pid_status_event); 178 179 } 180 } 181 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid); 182 ctx.Events().ResetEvents(event_proc_thread_running); 183 ctx.Events().SetEvents(event_proc_thread_exiting); 184 return NULL; 185 } 186 187 188 const char* 189 RNBContext::EventsAsString (nub_event_t events, std::string& s) 190 { 191 s.clear(); 192 if (events & event_proc_state_changed) 193 s += "proc_state_changed "; 194 if (events & event_proc_thread_running) 195 s += "proc_thread_running "; 196 if (events & event_proc_thread_exiting) 197 s += "proc_thread_exiting "; 198 if (events & event_proc_stdio_available) 199 s += "proc_stdio_available "; 200 if (events & event_read_packet_available) 201 s += "read_packet_available "; 202 if (events & event_read_thread_running) 203 s += "read_thread_running "; 204 if (events & event_read_thread_running) 205 s += "read_thread_running "; 206 return s.c_str(); 207 } 208 209 const char * 210 RNBContext::LaunchStatusAsString (std::string& s) 211 { 212 s.clear(); 213 214 const char *err_str = m_launch_status.AsString(); 215 if (err_str) 216 s = err_str; 217 else 218 { 219 char error_num_str[64]; 220 snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error()); 221 s = error_num_str; 222 } 223 return s.c_str(); 224 } 225 226 bool 227 RNBContext::ProcessStateRunning() const 228 { 229 nub_state_t pid_state = DNBProcessGetState(m_pid); 230 return pid_state == eStateRunning || pid_state == eStateStepping; 231 } 232