]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/debugserver/source/RNBContext.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / tools / debugserver / source / RNBContext.cpp
1 //===-- 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"
15
16 #include <sstream>
17 #include <sys/stat.h>
18
19 #if defined(__APPLE__)
20 #include <pthread.h>
21 #include <sched.h>
22 #endif
23
24 #include "CFString.h"
25 #include "DNB.h"
26 #include "DNBLog.h"
27 #include "RNBRemote.h"
28
29 //----------------------------------------------------------------------
30 // Destructor
31 //----------------------------------------------------------------------
32 RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }
33
34 //----------------------------------------------------------------------
35 // RNBContext constructor
36 //----------------------------------------------------------------------
37
38 const 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;
43 }
44
45 const 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;
50 }
51
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();
56     return false;
57   }
58   m_working_directory.assign(path);
59   return true;
60 }
61
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.
67   }
68   // Assign our new process ID
69   m_pid = pid;
70
71   if (pid != INVALID_NUB_PROCESS) {
72     StartProcessStatusThread();
73   }
74 }
75
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);
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);
93     }
94   }
95 }
96
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,
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???
115     }
116   }
117 }
118
119 //----------------------------------------------------------------------
120 // This thread's sole purpose is to watch for any status changes in the
121 // child process.
122 //----------------------------------------------------------------------
123 void *RNBContext::ThreadFunctionProcessStatus(void *arg) {
124   RNBRemoteSP remoteSP(g_remoteSP);
125   RNBRemote *remote = remoteSP.get();
126   if (remote == NULL)
127     return NULL;
128   RNBContext &ctx = remote->Context();
129
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);
135
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);
145   }
146 #endif
147 #endif
148
149   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);
168
169     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);
227     }
228   }
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;
235 }
236
237 const 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
260 const 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",
269              m_launch_status.Error());
270     s = error_num_str;
271   }
272   return s.c_str();
273 }
274
275 bool RNBContext::ProcessStateRunning() const {
276   nub_state_t pid_state = DNBProcessGetState(m_pid);
277   return pid_state == eStateRunning || pid_state == eStateStepping;
278 }