blob: c86511c6e226073eeeab888f7e99ff82789b986e [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
Pavel Labathdeb45f22017-12-22 11:09:21 +000045static std::string GetEnvironmentKey(const std::string &env) {
46 std::string key = env.substr(0, env.find('='));
47 if (!key.empty() && key.back() == '=')
48 key.pop_back();
49 return key;
50}
51
52void RNBContext::PushEnvironmentIfNeeded(const char *arg) {
53 if (!arg)
54 return;
55 std::string arg_key = GetEnvironmentKey(arg);
56
57 for (const std::string &entry: m_env_vec) {
58 if (arg_key == GetEnvironmentKey(entry))
59 return;
60 }
61 m_env_vec.push_back(arg);
62}
63
Kate Stoneb9c1b512016-09-06 20:57:50 +000064const char *RNBContext::ArgumentAtIndex(size_t index) {
65 if (index < m_arg_vec.size())
66 return m_arg_vec[index].c_str();
67 else
68 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069}
70
Kate Stoneb9c1b512016-09-06 20:57:50 +000071bool RNBContext::SetWorkingDirectory(const char *path) {
72 struct stat working_directory_stat;
73 if (::stat(path, &working_directory_stat) != 0) {
74 m_working_directory.clear();
75 return false;
76 }
77 m_working_directory.assign(path);
78 return true;
Greg Clayton6779606a2011-01-22 23:43:18 +000079}
80
Kate Stoneb9c1b512016-09-06 20:57:50 +000081void RNBContext::SetProcessID(nub_process_t pid) {
82 // Delete and events we created
83 if (m_pid != INVALID_NUB_PROCESS) {
84 StopProcessStatusThread();
85 // Unregister this context as a client of the process's events.
86 }
87 // Assign our new process ID
88 m_pid = pid;
Greg Clayton6779606a2011-01-22 23:43:18 +000089
Kate Stoneb9c1b512016-09-06 20:57:50 +000090 if (pid != INVALID_NUB_PROCESS) {
91 StartProcessStatusThread();
92 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000093}
94
Kate Stoneb9c1b512016-09-06 20:57:50 +000095void RNBContext::StartProcessStatusThread() {
96 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
97 if ((m_events.GetEventBits() & event_proc_thread_running) == 0) {
98 int err = ::pthread_create(&m_pid_pthread, NULL,
99 ThreadFunctionProcessStatus, this);
100 if (err == 0) {
101 // Our thread was successfully kicked off, wait for it to
102 // set the started event so we can safely continue
103 m_events.WaitForSetEvents(event_proc_thread_running);
104 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!",
105 __FUNCTION__);
106 } else {
107 DNBLogThreadedIf(LOG_RNB_PROC,
108 "RNBContext::%s thread failed to start: err = %i",
109 __FUNCTION__, err);
110 m_events.ResetEvents(event_proc_thread_running);
111 m_events.SetEvents(event_proc_thread_exiting);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000112 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000114}
115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116void RNBContext::StopProcessStatusThread() {
117 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
118 if ((m_events.GetEventBits() & event_proc_thread_running) ==
119 event_proc_thread_running) {
120 struct timespec timeout_abstime;
121 DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
122 // Wait for 2 seconds for the rx thread to exit
123 if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting,
124 &timeout_abstime) ==
125 RNBContext::event_proc_thread_exiting) {
126 DNBLogThreadedIf(LOG_RNB_PROC,
127 "RNBContext::%s thread stopped as requeseted",
128 __FUNCTION__);
129 } else {
130 DNBLogThreadedIf(LOG_RNB_PROC,
131 "RNBContext::%s thread did not stop in 2 seconds...",
132 __FUNCTION__);
133 // Kill the RX thread???
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000134 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000136}
137
138//----------------------------------------------------------------------
139// This thread's sole purpose is to watch for any status changes in the
140// child process.
141//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142void *RNBContext::ThreadFunctionProcessStatus(void *arg) {
143 RNBRemoteSP remoteSP(g_remoteSP);
144 RNBRemote *remote = remoteSP.get();
145 if (remote == NULL)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000146 return NULL;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 RNBContext &ctx = remote->Context();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 nub_process_t pid = ctx.ProcessID();
150 DNBLogThreadedIf(LOG_RNB_PROC,
151 "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...",
152 __FUNCTION__, arg, pid);
153 ctx.Events().SetEvents(RNBContext::event_proc_thread_running);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000154
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155#if defined(__APPLE__)
156 pthread_setname_np("child process status watcher thread");
157#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
158 struct sched_param thread_param;
159 int thread_sched_policy;
160 if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
161 &thread_param) == 0) {
162 thread_param.sched_priority = 47;
163 pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);
164 }
165#endif
166#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000167
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 bool done = false;
169 while (!done) {
170 DNBLogThreadedIf(LOG_RNB_PROC,
171 "RNBContext::%s calling DNBProcessWaitForEvent(pid, "
172 "eEventProcessRunningStateChanged | "
173 "eEventProcessStoppedStateChanged | eEventStdioAvailable "
174 "| eEventProfileDataAvailable, true)...",
175 __FUNCTION__);
176 nub_event_t pid_status_event = DNBProcessWaitForEvents(
177 pid,
178 eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged |
179 eEventStdioAvailable | eEventProfileDataAvailable,
180 true, NULL);
181 DNBLogThreadedIf(LOG_RNB_PROC,
182 "RNBContext::%s calling DNBProcessWaitForEvent(pid, "
183 "eEventProcessRunningStateChanged | "
184 "eEventProcessStoppedStateChanged | eEventStdioAvailable "
185 "| eEventProfileDataAvailable, true) => 0x%8.8x",
186 __FUNCTION__, pid_status_event);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000187
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 if (pid_status_event == 0) {
189 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back "
190 "from DNBProcessWaitForEvent....",
191 __FUNCTION__, pid);
192 // done = true;
193 } else {
194 if (pid_status_event & eEventStdioAvailable) {
195 DNBLogThreadedIf(
196 LOG_RNB_PROC,
197 "RNBContext::%s (pid=%4.4x) got stdio available event....",
198 __FUNCTION__, pid);
199 ctx.Events().SetEvents(RNBContext::event_proc_stdio_available);
200 // Wait for the main thread to consume this notification if it requested
201 // we wait for it
202 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
203 }
204
205 if (pid_status_event & eEventProfileDataAvailable) {
206 DNBLogThreadedIf(
207 LOG_RNB_PROC,
208 "RNBContext::%s (pid=%4.4x) got profile data event....",
209 __FUNCTION__, pid);
210 ctx.Events().SetEvents(RNBContext::event_proc_profile_data);
211 // Wait for the main thread to consume this notification if it requested
212 // we wait for it
213 ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data);
214 }
215
216 if (pid_status_event & (eEventProcessRunningStateChanged |
217 eEventProcessStoppedStateChanged)) {
218 nub_state_t pid_state = DNBProcessGetState(pid);
219 DNBLogThreadedIf(
220 LOG_RNB_PROC,
221 "RNBContext::%s (pid=%4.4x) got process state change: %s",
222 __FUNCTION__, pid, DNBStateAsString(pid_state));
223
224 // Let the main thread know there is a process state change to see
225 ctx.Events().SetEvents(RNBContext::event_proc_state_changed);
226 // Wait for the main thread to consume this notification if it requested
227 // we wait for it
228 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
229
230 switch (pid_state) {
231 case eStateStopped:
232 break;
233
234 case eStateInvalid:
235 case eStateExited:
236 case eStateDetached:
237 done = true;
238 break;
239 default:
240 break;
241 }
242 }
243
244 // Reset any events that we consumed.
245 DNBProcessResetEvents(pid, pid_status_event);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000246 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247 }
248 DNBLogThreadedIf(LOG_RNB_PROC,
249 "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...",
250 __FUNCTION__, arg, pid);
251 ctx.Events().ResetEvents(event_proc_thread_running);
252 ctx.Events().SetEvents(event_proc_thread_exiting);
253 return NULL;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000254}
255
Kate Stoneb9c1b512016-09-06 20:57:50 +0000256const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) {
257 s.clear();
258 if (events & event_proc_state_changed)
259 s += "proc_state_changed ";
260 if (events & event_proc_thread_running)
261 s += "proc_thread_running ";
262 if (events & event_proc_thread_exiting)
263 s += "proc_thread_exiting ";
264 if (events & event_proc_stdio_available)
265 s += "proc_stdio_available ";
266 if (events & event_proc_profile_data)
267 s += "proc_profile_data ";
268 if (events & event_darwin_log_data_available)
269 s += "darwin_log_data_available ";
270 if (events & event_read_packet_available)
271 s += "read_packet_available ";
272 if (events & event_read_thread_running)
273 s += "read_thread_running ";
274 if (events & event_read_thread_running)
275 s += "read_thread_running ";
276 return s.c_str();
277}
278
279const char *RNBContext::LaunchStatusAsString(std::string &s) {
280 s.clear();
281
282 const char *err_str = m_launch_status.AsString();
283 if (err_str)
284 s = err_str;
285 else {
286 char error_num_str[64];
287 snprintf(error_num_str, sizeof(error_num_str), "%u",
Zachary Turner97206d52017-05-12 04:51:55 +0000288 m_launch_status.Status());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000289 s = error_num_str;
290 }
291 return s.c_str();
292}
293
294bool RNBContext::ProcessStateRunning() const {
295 nub_state_t pid_state = DNBProcessGetState(m_pid);
296 return pid_state == eStateRunning || pid_state == eStateStepping;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000297}