xref: /llvm-project/lldb/tools/debugserver/source/RNBContext.cpp (revision 30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c)
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 #include "RNBRemote.h"
16 #include "DNB.h"
17 #include "DNBLog.h"
18 #include "CFString.h"
19 #include <sstream>
20 
21 //----------------------------------------------------------------------
22 // Destructor
23 //----------------------------------------------------------------------
24 RNBContext::~RNBContext()
25 {
26     SetProcessID (INVALID_NUB_PROCESS);
27 }
28 
29 //----------------------------------------------------------------------
30 // RNBContext constructor
31 //----------------------------------------------------------------------
32 
33 const char *
34 RNBContext::EnvironmentAtIndex (int index)
35 {
36     if (index < m_env_vec.size())
37         return m_env_vec[index].c_str();
38     else
39         return NULL;
40 }
41 
42 
43 const char *
44 RNBContext::ArgumentAtIndex (int index)
45 {
46     if (index < m_arg_vec.size())
47         return m_arg_vec[index].c_str();
48     else
49         return NULL;
50 }
51 
52 void
53 RNBContext::SetProcessID (nub_process_t pid)
54 {
55     // Delete and events we created
56     if (m_pid != INVALID_NUB_PROCESS)
57     {
58         StopProcessStatusThread ();
59         // Unregister this context as a client of the process's events.
60     }
61     // Assign our new process ID
62     m_pid = pid;
63 
64     if (pid != INVALID_NUB_PROCESS)
65     {
66         StartProcessStatusThread ();
67     }
68 }
69 
70 void
71 RNBContext::StartProcessStatusThread()
72 {
73     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
74     if ((m_events.GetEventBits() & event_proc_thread_running) == 0)
75     {
76         int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this);
77         if (err == 0)
78         {
79             // Our thread was successfully kicked off, wait for it to
80             // set the started event so we can safely continue
81             m_events.WaitForSetEvents (event_proc_thread_running);
82             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__);
83         }
84         else
85         {
86             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err);
87             m_events.ResetEvents (event_proc_thread_running);
88             m_events.SetEvents (event_proc_thread_exiting);
89         }
90     }
91 }
92 
93 void
94 RNBContext::StopProcessStatusThread()
95 {
96     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
97     if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running)
98     {
99         struct timespec timeout_abstime;
100         DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
101         // Wait for 2 seconds for the rx thread to exit
102         if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting)
103         {
104             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__);
105         }
106         else
107         {
108             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__);
109             // Kill the RX thread???
110         }
111     }
112 }
113 
114 //----------------------------------------------------------------------
115 // This thread's sole purpose is to watch for any status changes in the
116 // child process.
117 //----------------------------------------------------------------------
118 void*
119 RNBContext::ThreadFunctionProcessStatus(void *arg)
120 {
121     RNBRemoteSP remoteSP(g_remoteSP);
122     RNBRemote* remote = remoteSP.get();
123     if (remote == NULL)
124         return NULL;
125     RNBContext& ctx = remote->Context();
126 
127     nub_process_t pid = ctx.ProcessID();
128     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid);
129     ctx.Events().SetEvents (RNBContext::event_proc_thread_running);
130     bool done = false;
131     while (!done)
132     {
133         DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
134         nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
135         DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
136 
137         if (pid_status_event == 0)
138         {
139             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid);
140         //    done = true;
141         }
142         else
143         {
144             if (pid_status_event & eEventStdioAvailable)
145             {
146                 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid);
147                 ctx.Events().SetEvents (RNBContext::event_proc_stdio_available);
148                 // Wait for the main thread to consume this notification if it requested we wait for it
149                 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
150             }
151 
152 
153             if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
154             {
155                 nub_state_t pid_state = DNBProcessGetState(pid);
156                 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
157 
158                 // Let the main thread know there is a process state change to see
159                 ctx.Events().SetEvents (RNBContext::event_proc_state_changed);
160                 // Wait for the main thread to consume this notification if it requested we wait for it
161                 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
162 
163                 switch (pid_state)
164                 {
165                 case eStateStopped:
166                     break;
167 
168                 case eStateInvalid:
169                 case eStateExited:
170                     done = true;
171                     break;
172                 }
173             }
174 
175             // Reset any events that we consumed.
176             DNBProcessResetEvents(pid, pid_status_event);
177 
178         }
179     }
180     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
181     ctx.Events().ResetEvents(event_proc_thread_running);
182     ctx.Events().SetEvents(event_proc_thread_exiting);
183     return NULL;
184 }
185 
186 
187 const char*
188 RNBContext::EventsAsString (nub_event_t events, std::string& s)
189 {
190     s.clear();
191     if (events & event_proc_state_changed)
192         s += "proc_state_changed ";
193     if (events & event_proc_thread_running)
194         s += "proc_thread_running ";
195     if (events & event_proc_thread_exiting)
196         s += "proc_thread_exiting ";
197     if (events & event_proc_stdio_available)
198         s += "proc_stdio_available ";
199     if (events & event_read_packet_available)
200         s += "read_packet_available ";
201     if (events & event_read_thread_running)
202         s += "read_thread_running ";
203     if (events & event_read_thread_running)
204         s += "read_thread_running ";
205     return s.c_str();
206 }
207 
208 const char *
209 RNBContext::LaunchStatusAsString (std::string& s)
210 {
211     s.clear();
212 
213     const char *err_str = m_launch_status.AsString();
214     if (err_str)
215         s = err_str;
216     else
217     {
218         char error_num_str[64];
219         snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
220         s = error_num_str;
221     }
222     return s.c_str();
223 }
224 
225 bool
226 RNBContext::ProcessStateRunning() const
227 {
228     nub_state_t pid_state = DNBProcessGetState(m_pid);
229     return pid_state == eStateRunning || pid_state == eStateStepping;
230 }
231