blob: 87f24ccf1b9c60568e9cbe32520315ef41a74d49 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- RNBContext.cpp ------------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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 Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Created by Greg Clayton on 12/12/07.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RNBContext.h"
Greg Clayton6779606a2011-01-22 23:43:18 +000014
Greg Clayton6779606a2011-01-22 23:43:18 +000015#include <sstream>
Kate Stoneb9c1b512016-09-06 20:57:50 +000016#include <sys/stat.h>
Greg Clayton6779606a2011-01-22 23:43:18 +000017
Kate Stoneb9c1b512016-09-06 20:57:50 +000018#if defined(__APPLE__)
Jason Molenda36a216e2014-07-24 01:36:24 +000019#include <pthread.h>
20#include <sched.h>
21#endif
22
Kate Stoneb9c1b512016-09-06 20:57:50 +000023#include "CFString.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024#include "DNB.h"
25#include "DNBLog.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000026#include "RNBRemote.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000027
28//----------------------------------------------------------------------
29// Destructor
30//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000031RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000032
33//----------------------------------------------------------------------
34// RNBContext constructor
35//----------------------------------------------------------------------
36
Kate Stoneb9c1b512016-09-06 20:57:50 +000037const 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 Lattner30fdc8d2010-06-08 16:52:24 +000042}
43
Pavel Labathdeb45f22017-12-22 11:09:21 +000044static 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
51void 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 Stoneb9c1b512016-09-06 20:57:50 +000063const 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 Lattner30fdc8d2010-06-08 16:52:24 +000068}
69
Kate Stoneb9c1b512016-09-06 20:57:50 +000070bool 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 Clayton6779606a2011-01-22 23:43:18 +000078}
79
Kate Stoneb9c1b512016-09-06 20:57:50 +000080void 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 Clayton6779606a2011-01-22 23:43:18 +000088
Kate Stoneb9c1b512016-09-06 20:57:50 +000089 if (pid != INVALID_NUB_PROCESS) {
90 StartProcessStatusThread();
91 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +000092}
93
Kate Stoneb9c1b512016-09-06 20:57:50 +000094void 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 Lattner30fdc8d2010-06-08 16:52:24 +0000111 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000113}
114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115void 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 Lattner30fdc8d2010-06-08 16:52:24 +0000133 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000135}
136
137//----------------------------------------------------------------------
138// This thread's sole purpose is to watch for any status changes in the
139// child process.
140//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141void *RNBContext::ThreadFunctionProcessStatus(void *arg) {
142 RNBRemoteSP remoteSP(g_remoteSP);
143 RNBRemote *remote = remoteSP.get();
144 if (remote == NULL)
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000145 return NULL;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 RNBContext &ctx = remote->Context();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 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 Lattner30fdc8d2010-06-08 16:52:24 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154#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 Lattner30fdc8d2010-06-08 16:52:24 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 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 Lattner30fdc8d2010-06-08 16:52:24 +0000186
Kate Stoneb9c1b512016-09-06 20:57:50 +0000187 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 Lattner30fdc8d2010-06-08 16:52:24 +0000245 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 }
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 Lattner30fdc8d2010-06-08 16:52:24 +0000253}
254
Kate Stoneb9c1b512016-09-06 20:57:50 +0000255const 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
278const 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 Turner97206d52017-05-12 04:51:55 +0000287 m_launch_status.Status());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000288 s = error_num_str;
289 }
290 return s.c_str();
291}
292
293bool RNBContext::ProcessStateRunning() const {
294 nub_state_t pid_state = DNBProcessGetState(m_pid);
295 return pid_state == eStateRunning || pid_state == eStateStepping;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000296}