Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 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" |
Greg Clayton | 6779606a | 2011-01-22 23:43:18 +0000 | [diff] [blame] | 15 | |
Greg Clayton | 6779606a | 2011-01-22 23:43:18 +0000 | [diff] [blame] | 16 | #include <sstream> |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 17 | #include <sys/stat.h> |
Greg Clayton | 6779606a | 2011-01-22 23:43:18 +0000 | [diff] [blame] | 18 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 19 | #if defined(__APPLE__) |
Jason Molenda | 36a216e | 2014-07-24 01:36:24 +0000 | [diff] [blame] | 20 | #include <pthread.h> |
| 21 | #include <sched.h> |
| 22 | #endif |
| 23 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 24 | #include "CFString.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 25 | #include "DNB.h" |
| 26 | #include "DNBLog.h" |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 27 | #include "RNBRemote.h" |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 28 | |
| 29 | //---------------------------------------------------------------------- |
| 30 | // Destructor |
| 31 | //---------------------------------------------------------------------- |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 32 | RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 33 | |
| 34 | //---------------------------------------------------------------------- |
| 35 | // RNBContext constructor |
| 36 | //---------------------------------------------------------------------- |
| 37 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 38 | const char *RNBContext::EnvironmentAtIndex(size_t index) { |
| 39 | if (index < m_env_vec.size()) |
| 40 | return m_env_vec[index].c_str(); |
| 41 | else |
| 42 | return NULL; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 43 | } |
| 44 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 45 | const char *RNBContext::ArgumentAtIndex(size_t index) { |
| 46 | if (index < m_arg_vec.size()) |
| 47 | return m_arg_vec[index].c_str(); |
| 48 | else |
| 49 | return NULL; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 50 | } |
| 51 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 52 | bool RNBContext::SetWorkingDirectory(const char *path) { |
| 53 | struct stat working_directory_stat; |
| 54 | if (::stat(path, &working_directory_stat) != 0) { |
| 55 | m_working_directory.clear(); |
| 56 | return false; |
| 57 | } |
| 58 | m_working_directory.assign(path); |
| 59 | return true; |
Greg Clayton | 6779606a | 2011-01-22 23:43:18 +0000 | [diff] [blame] | 60 | } |
| 61 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 62 | void RNBContext::SetProcessID(nub_process_t pid) { |
| 63 | // Delete and events we created |
| 64 | if (m_pid != INVALID_NUB_PROCESS) { |
| 65 | StopProcessStatusThread(); |
| 66 | // Unregister this context as a client of the process's events. |
| 67 | } |
| 68 | // Assign our new process ID |
| 69 | m_pid = pid; |
Greg Clayton | 6779606a | 2011-01-22 23:43:18 +0000 | [diff] [blame] | 70 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 71 | if (pid != INVALID_NUB_PROCESS) { |
| 72 | StartProcessStatusThread(); |
| 73 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 74 | } |
| 75 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 76 | void RNBContext::StartProcessStatusThread() { |
| 77 | DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); |
| 78 | if ((m_events.GetEventBits() & event_proc_thread_running) == 0) { |
| 79 | int err = ::pthread_create(&m_pid_pthread, NULL, |
| 80 | ThreadFunctionProcessStatus, this); |
| 81 | if (err == 0) { |
| 82 | // Our thread was successfully kicked off, wait for it to |
| 83 | // set the started event so we can safely continue |
| 84 | m_events.WaitForSetEvents(event_proc_thread_running); |
| 85 | DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", |
| 86 | __FUNCTION__); |
| 87 | } else { |
| 88 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 89 | "RNBContext::%s thread failed to start: err = %i", |
| 90 | __FUNCTION__, err); |
| 91 | m_events.ResetEvents(event_proc_thread_running); |
| 92 | m_events.SetEvents(event_proc_thread_exiting); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 93 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 94 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 95 | } |
| 96 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 97 | void RNBContext::StopProcessStatusThread() { |
| 98 | DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); |
| 99 | if ((m_events.GetEventBits() & event_proc_thread_running) == |
| 100 | event_proc_thread_running) { |
| 101 | struct timespec timeout_abstime; |
| 102 | DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); |
| 103 | // Wait for 2 seconds for the rx thread to exit |
| 104 | if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, |
| 105 | &timeout_abstime) == |
| 106 | RNBContext::event_proc_thread_exiting) { |
| 107 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 108 | "RNBContext::%s thread stopped as requeseted", |
| 109 | __FUNCTION__); |
| 110 | } else { |
| 111 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 112 | "RNBContext::%s thread did not stop in 2 seconds...", |
| 113 | __FUNCTION__); |
| 114 | // Kill the RX thread??? |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 115 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 116 | } |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | //---------------------------------------------------------------------- |
| 120 | // This thread's sole purpose is to watch for any status changes in the |
| 121 | // child process. |
| 122 | //---------------------------------------------------------------------- |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 123 | void *RNBContext::ThreadFunctionProcessStatus(void *arg) { |
| 124 | RNBRemoteSP remoteSP(g_remoteSP); |
| 125 | RNBRemote *remote = remoteSP.get(); |
| 126 | if (remote == NULL) |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 127 | return NULL; |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 128 | RNBContext &ctx = remote->Context(); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 129 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 130 | nub_process_t pid = ctx.ProcessID(); |
| 131 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 132 | "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", |
| 133 | __FUNCTION__, arg, pid); |
| 134 | ctx.Events().SetEvents(RNBContext::event_proc_thread_running); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 135 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 136 | #if defined(__APPLE__) |
| 137 | pthread_setname_np("child process status watcher thread"); |
| 138 | #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) |
| 139 | struct sched_param thread_param; |
| 140 | int thread_sched_policy; |
| 141 | if (pthread_getschedparam(pthread_self(), &thread_sched_policy, |
| 142 | &thread_param) == 0) { |
| 143 | thread_param.sched_priority = 47; |
| 144 | pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); |
| 145 | } |
| 146 | #endif |
| 147 | #endif |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 148 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 149 | bool done = false; |
| 150 | while (!done) { |
| 151 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 152 | "RNBContext::%s calling DNBProcessWaitForEvent(pid, " |
| 153 | "eEventProcessRunningStateChanged | " |
| 154 | "eEventProcessStoppedStateChanged | eEventStdioAvailable " |
| 155 | "| eEventProfileDataAvailable, true)...", |
| 156 | __FUNCTION__); |
| 157 | nub_event_t pid_status_event = DNBProcessWaitForEvents( |
| 158 | pid, |
| 159 | eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | |
| 160 | eEventStdioAvailable | eEventProfileDataAvailable, |
| 161 | true, NULL); |
| 162 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 163 | "RNBContext::%s calling DNBProcessWaitForEvent(pid, " |
| 164 | "eEventProcessRunningStateChanged | " |
| 165 | "eEventProcessStoppedStateChanged | eEventStdioAvailable " |
| 166 | "| eEventProfileDataAvailable, true) => 0x%8.8x", |
| 167 | __FUNCTION__, pid_status_event); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 168 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 169 | if (pid_status_event == 0) { |
| 170 | DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back " |
| 171 | "from DNBProcessWaitForEvent....", |
| 172 | __FUNCTION__, pid); |
| 173 | // done = true; |
| 174 | } else { |
| 175 | if (pid_status_event & eEventStdioAvailable) { |
| 176 | DNBLogThreadedIf( |
| 177 | LOG_RNB_PROC, |
| 178 | "RNBContext::%s (pid=%4.4x) got stdio available event....", |
| 179 | __FUNCTION__, pid); |
| 180 | ctx.Events().SetEvents(RNBContext::event_proc_stdio_available); |
| 181 | // Wait for the main thread to consume this notification if it requested |
| 182 | // we wait for it |
| 183 | ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available); |
| 184 | } |
| 185 | |
| 186 | if (pid_status_event & eEventProfileDataAvailable) { |
| 187 | DNBLogThreadedIf( |
| 188 | LOG_RNB_PROC, |
| 189 | "RNBContext::%s (pid=%4.4x) got profile data event....", |
| 190 | __FUNCTION__, pid); |
| 191 | ctx.Events().SetEvents(RNBContext::event_proc_profile_data); |
| 192 | // Wait for the main thread to consume this notification if it requested |
| 193 | // we wait for it |
| 194 | ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data); |
| 195 | } |
| 196 | |
| 197 | if (pid_status_event & (eEventProcessRunningStateChanged | |
| 198 | eEventProcessStoppedStateChanged)) { |
| 199 | nub_state_t pid_state = DNBProcessGetState(pid); |
| 200 | DNBLogThreadedIf( |
| 201 | LOG_RNB_PROC, |
| 202 | "RNBContext::%s (pid=%4.4x) got process state change: %s", |
| 203 | __FUNCTION__, pid, DNBStateAsString(pid_state)); |
| 204 | |
| 205 | // Let the main thread know there is a process state change to see |
| 206 | ctx.Events().SetEvents(RNBContext::event_proc_state_changed); |
| 207 | // Wait for the main thread to consume this notification if it requested |
| 208 | // we wait for it |
| 209 | ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed); |
| 210 | |
| 211 | switch (pid_state) { |
| 212 | case eStateStopped: |
| 213 | break; |
| 214 | |
| 215 | case eStateInvalid: |
| 216 | case eStateExited: |
| 217 | case eStateDetached: |
| 218 | done = true; |
| 219 | break; |
| 220 | default: |
| 221 | break; |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | // Reset any events that we consumed. |
| 226 | DNBProcessResetEvents(pid, pid_status_event); |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 227 | } |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 228 | } |
| 229 | DNBLogThreadedIf(LOG_RNB_PROC, |
| 230 | "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", |
| 231 | __FUNCTION__, arg, pid); |
| 232 | ctx.Events().ResetEvents(event_proc_thread_running); |
| 233 | ctx.Events().SetEvents(event_proc_thread_exiting); |
| 234 | return NULL; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 235 | } |
| 236 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 237 | const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) { |
| 238 | s.clear(); |
| 239 | if (events & event_proc_state_changed) |
| 240 | s += "proc_state_changed "; |
| 241 | if (events & event_proc_thread_running) |
| 242 | s += "proc_thread_running "; |
| 243 | if (events & event_proc_thread_exiting) |
| 244 | s += "proc_thread_exiting "; |
| 245 | if (events & event_proc_stdio_available) |
| 246 | s += "proc_stdio_available "; |
| 247 | if (events & event_proc_profile_data) |
| 248 | s += "proc_profile_data "; |
| 249 | if (events & event_darwin_log_data_available) |
| 250 | s += "darwin_log_data_available "; |
| 251 | if (events & event_read_packet_available) |
| 252 | s += "read_packet_available "; |
| 253 | if (events & event_read_thread_running) |
| 254 | s += "read_thread_running "; |
| 255 | if (events & event_read_thread_running) |
| 256 | s += "read_thread_running "; |
| 257 | return s.c_str(); |
| 258 | } |
| 259 | |
| 260 | const char *RNBContext::LaunchStatusAsString(std::string &s) { |
| 261 | s.clear(); |
| 262 | |
| 263 | const char *err_str = m_launch_status.AsString(); |
| 264 | if (err_str) |
| 265 | s = err_str; |
| 266 | else { |
| 267 | char error_num_str[64]; |
| 268 | snprintf(error_num_str, sizeof(error_num_str), "%u", |
Zachary Turner | 97206d5 | 2017-05-12 04:51:55 +0000 | [diff] [blame^] | 269 | m_launch_status.Status()); |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 270 | s = error_num_str; |
| 271 | } |
| 272 | return s.c_str(); |
| 273 | } |
| 274 | |
| 275 | bool RNBContext::ProcessStateRunning() const { |
| 276 | nub_state_t pid_state = DNBProcessGetState(m_pid); |
| 277 | return pid_state == eStateRunning || pid_state == eStateStepping; |
Chris Lattner | 30fdc8d | 2010-06-08 16:52:24 +0000 | [diff] [blame] | 278 | } |