blob: 29bc6388e2a5a54f84fe662e79cbee5bc83063fc [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 {
151 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
152 nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
153 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
154
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
170
171 if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
172 {
173 nub_state_t pid_state = DNBProcessGetState(pid);
174 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
175
176 // Let the main thread know there is a process state change to see
177 ctx.Events().SetEvents (RNBContext::event_proc_state_changed);
178 // Wait for the main thread to consume this notification if it requested we wait for it
179 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
180
181 switch (pid_state)
182 {
183 case eStateStopped:
184 break;
185
186 case eStateInvalid:
187 case eStateExited:
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000188 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000189 done = true;
190 break;
191 }
192 }
193
194 // Reset any events that we consumed.
195 DNBProcessResetEvents(pid, pid_status_event);
196
197 }
198 }
199 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
200 ctx.Events().ResetEvents(event_proc_thread_running);
201 ctx.Events().SetEvents(event_proc_thread_exiting);
202 return NULL;
203}
204
205
206const char*
207RNBContext::EventsAsString (nub_event_t events, std::string& s)
208{
209 s.clear();
210 if (events & event_proc_state_changed)
211 s += "proc_state_changed ";
212 if (events & event_proc_thread_running)
213 s += "proc_thread_running ";
214 if (events & event_proc_thread_exiting)
215 s += "proc_thread_exiting ";
216 if (events & event_proc_stdio_available)
217 s += "proc_stdio_available ";
218 if (events & event_read_packet_available)
219 s += "read_packet_available ";
220 if (events & event_read_thread_running)
221 s += "read_thread_running ";
222 if (events & event_read_thread_running)
223 s += "read_thread_running ";
224 return s.c_str();
225}
226
227const char *
228RNBContext::LaunchStatusAsString (std::string& s)
229{
230 s.clear();
231
232 const char *err_str = m_launch_status.AsString();
233 if (err_str)
234 s = err_str;
235 else
236 {
237 char error_num_str[64];
238 snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
239 s = error_num_str;
240 }
241 return s.c_str();
242}
243
244bool
245RNBContext::ProcessStateRunning() const
246{
247 nub_state_t pid_state = DNBProcessGetState(m_pid);
248 return pid_state == eStateRunning || pid_state == eStateStepping;
249}