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