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