blob: 960d6d99c9d015f08acee1bd440547be6a334b66 [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
16#include <sys/stat.h>
17#include <sstream>
18
Jason Molenda36a216e2014-07-24 01:36:24 +000019#if defined (__APPLE__)
20#include <pthread.h>
21#include <sched.h>
22#endif
23
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024#include "RNBRemote.h"
25#include "DNB.h"
26#include "DNBLog.h"
27#include "CFString.h"
Greg Clayton6779606a2011-01-22 23:43:18 +000028
Chris Lattner30fdc8d2010-06-08 16:52:24 +000029
30//----------------------------------------------------------------------
31// Destructor
32//----------------------------------------------------------------------
33RNBContext::~RNBContext()
34{
35 SetProcessID (INVALID_NUB_PROCESS);
36}
37
38//----------------------------------------------------------------------
39// RNBContext constructor
40//----------------------------------------------------------------------
41
42const char *
43RNBContext::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
52const char *
53RNBContext::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 Clayton6779606a2011-01-22 23:43:18 +000061bool
62RNBContext::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 Lattner30fdc8d2010-06-08 16:52:24 +000075void
76RNBContext::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
93void
94RNBContext::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
116void
117RNBContext::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//----------------------------------------------------------------------
141void*
142RNBContext::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 Molenda36a216e2014-07-24 01:36:24 +0000153
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 Lattner30fdc8d2010-06-08 16:52:24 +0000167 bool done = false;
168 while (!done)
169 {
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000170 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 Lattner30fdc8d2010-06-08 16:52:24 +0000173
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 Ongab3b8b22012-11-17 00:21:04 +0000189 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 Lattner30fdc8d2010-06-08 16:52:24 +0000196
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 Clayton58d1c9a2010-10-18 04:14:23 +0000214 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000215 done = true;
216 break;
Greg Claytoneffe5c92011-05-03 22:09:39 +0000217 default:
218 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000219 }
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
234const char*
235RNBContext::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 Ongab3b8b22012-11-17 00:21:04 +0000246 if (events & event_proc_profile_data)
247 s += "proc_profile_data ";
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000248 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
257const char *
258RNBContext::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
274bool
275RNBContext::ProcessStateRunning() const
276{
277 nub_state_t pid_state = DNBProcessGetState(m_pid);
278 return pid_state == eStateRunning || pid_state == eStateStepping;
279}