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