blob: c1319af023228726f250c3be927cf6509443fbe8 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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 Clayton6779606a2011-01-22 23:43:18 +000015
Greg Clayton6779606a2011-01-22 23:43:18 +000016#include <sstream>
Kate Stoneb9c1b512016-09-06 20:57:50 +000017#include <sys/stat.h>
Greg Clayton6779606a2011-01-22 23:43:18 +000018
Kate Stoneb9c1b512016-09-06 20:57:50 +000019#if defined(__APPLE__)
Jason Molenda36a216e2014-07-24 01:36:24 +000020#include <pthread.h>
21#include <sched.h>
22#endif
23
Kate Stoneb9c1b512016-09-06 20:57:50 +000024#include "CFString.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000025#include "DNB.h"
26#include "DNBLog.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000027#include "RNBRemote.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000028
29//----------------------------------------------------------------------
30// Destructor
31//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000032RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000033
34//----------------------------------------------------------------------
35// RNBContext constructor
36//----------------------------------------------------------------------
37
Kate Stoneb9c1b512016-09-06 20:57:50 +000038const 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 Lattner30fdc8d2010-06-08 16:52:24 +000043}
44
Kate Stoneb9c1b512016-09-06 20:57:50 +000045const 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 Lattner30fdc8d2010-06-08 16:52:24 +000050}
51
Kate Stoneb9c1b512016-09-06 20:57:50 +000052bool 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 Clayton6779606a2011-01-22 23:43:18 +000060}
61
Kate Stoneb9c1b512016-09-06 20:57:50 +000062void 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 Clayton6779606a2011-01-22 23:43:18 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 if (pid != INVALID_NUB_PROCESS) {
72 StartProcessStatusThread();
73 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000074}
75
Kate Stoneb9c1b512016-09-06 20:57:50 +000076void 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 Lattner30fdc8d2010-06-08 16:52:24 +000093 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000095}
96
Kate Stoneb9c1b512016-09-06 20:57:50 +000097void 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 Lattner30fdc8d2010-06-08 16:52:24 +0000115 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000117}
118
119//----------------------------------------------------------------------
120// This thread's sole purpose is to watch for any status changes in the
121// child process.
122//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123void *RNBContext::ThreadFunctionProcessStatus(void *arg) {
124 RNBRemoteSP remoteSP(g_remoteSP);
125 RNBRemote *remote = remoteSP.get();
126 if (remote == NULL)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127 return NULL;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 RNBContext &ctx = remote->Context();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000129
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130 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 Lattner30fdc8d2010-06-08 16:52:24 +0000135
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136#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 Lattner30fdc8d2010-06-08 16:52:24 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 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 Lattner30fdc8d2010-06-08 16:52:24 +0000168
Kate Stoneb9c1b512016-09-06 20:57:50 +0000169 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 Lattner30fdc8d2010-06-08 16:52:24 +0000227 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 }
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 Lattner30fdc8d2010-06-08 16:52:24 +0000235}
236
Kate Stoneb9c1b512016-09-06 20:57:50 +0000237const 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
260const 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 Turner97206d52017-05-12 04:51:55 +0000269 m_launch_status.Status());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000270 s = error_num_str;
271 }
272 return s.c_str();
273}
274
275bool RNBContext::ProcessStateRunning() const {
276 nub_state_t pid_state = DNBProcessGetState(m_pid);
277 return pid_state == eStateRunning || pid_state == eStateStepping;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000278}