1 //===-- RNBContext.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Created by Greg Clayton on 12/12/07.
12 //===----------------------------------------------------------------------===//
14 #include "RNBContext.h"
19 #if defined(__APPLE__)
27 #include "RNBRemote.h"
29 //----------------------------------------------------------------------
31 //----------------------------------------------------------------------
32 RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
34 //----------------------------------------------------------------------
35 // RNBContext constructor
36 //----------------------------------------------------------------------
38 const char *RNBContext::EnvironmentAtIndex(size_t index) {
39 if (index < m_env_vec.size())
40 return m_env_vec[index].c_str();
45 const char *RNBContext::ArgumentAtIndex(size_t index) {
46 if (index < m_arg_vec.size())
47 return m_arg_vec[index].c_str();
52 bool RNBContext::SetWorkingDirectory(const char *path) {
53 struct stat working_directory_stat;
54 if (::stat(path, &working_directory_stat) != 0) {
55 m_working_directory.clear();
58 m_working_directory.assign(path);
62 void 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.
68 // Assign our new process ID
71 if (pid != INVALID_NUB_PROCESS) {
72 StartProcessStatusThread();
76 void 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);
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!",
88 DNBLogThreadedIf(LOG_RNB_PROC,
89 "RNBContext::%s thread failed to start: err = %i",
91 m_events.ResetEvents(event_proc_thread_running);
92 m_events.SetEvents(event_proc_thread_exiting);
97 void 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,
106 RNBContext::event_proc_thread_exiting) {
107 DNBLogThreadedIf(LOG_RNB_PROC,
108 "RNBContext::%s thread stopped as requeseted",
111 DNBLogThreadedIf(LOG_RNB_PROC,
112 "RNBContext::%s thread did not stop in 2 seconds...",
114 // Kill the RX thread???
119 //----------------------------------------------------------------------
120 // This thread's sole purpose is to watch for any status changes in the
122 //----------------------------------------------------------------------
123 void *RNBContext::ThreadFunctionProcessStatus(void *arg) {
124 RNBRemoteSP remoteSP(g_remoteSP);
125 RNBRemote *remote = remoteSP.get();
128 RNBContext &ctx = remote->Context();
130 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);
136 #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);
151 DNBLogThreadedIf(LOG_RNB_PROC,
152 "RNBContext::%s calling DNBProcessWaitForEvent(pid, "
153 "eEventProcessRunningStateChanged | "
154 "eEventProcessStoppedStateChanged | eEventStdioAvailable "
155 "| eEventProfileDataAvailable, true)...",
157 nub_event_t pid_status_event = DNBProcessWaitForEvents(
159 eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged |
160 eEventStdioAvailable | eEventProfileDataAvailable,
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);
169 if (pid_status_event == 0) {
170 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back "
171 "from DNBProcessWaitForEvent....",
175 if (pid_status_event & eEventStdioAvailable) {
178 "RNBContext::%s (pid=%4.4x) got stdio available event....",
180 ctx.Events().SetEvents(RNBContext::event_proc_stdio_available);
181 // Wait for the main thread to consume this notification if it requested
183 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
186 if (pid_status_event & eEventProfileDataAvailable) {
189 "RNBContext::%s (pid=%4.4x) got profile data event....",
191 ctx.Events().SetEvents(RNBContext::event_proc_profile_data);
192 // Wait for the main thread to consume this notification if it requested
194 ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data);
197 if (pid_status_event & (eEventProcessRunningStateChanged |
198 eEventProcessStoppedStateChanged)) {
199 nub_state_t pid_state = DNBProcessGetState(pid);
202 "RNBContext::%s (pid=%4.4x) got process state change: %s",
203 __FUNCTION__, pid, DNBStateAsString(pid_state));
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
209 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
225 // Reset any events that we consumed.
226 DNBProcessResetEvents(pid, pid_status_event);
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);
237 const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) {
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 ";
260 const char *RNBContext::LaunchStatusAsString(std::string &s) {
263 const char *err_str = m_launch_status.AsString();
267 char error_num_str[64];
268 snprintf(error_num_str, sizeof(error_num_str), "%u",
269 m_launch_status.Error());
275 bool RNBContext::ProcessStateRunning() const {
276 nub_state_t pid_state = DNBProcessGetState(m_pid);
277 return pid_state == eStateRunning || pid_state == eStateStepping;