blob: de850dba409be289855cabef4f13966f10764e17 [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"
15#include "RNBRemote.h"
16#include "DNB.h"
17#include "DNBLog.h"
18#include "CFString.h"
19#include <sstream>
20
21//----------------------------------------------------------------------
22// Destructor
23//----------------------------------------------------------------------
24RNBContext::~RNBContext()
25{
26 SetProcessID (INVALID_NUB_PROCESS);
27}
28
29//----------------------------------------------------------------------
30// RNBContext constructor
31//----------------------------------------------------------------------
32
33const char *
34RNBContext::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
43const char *
44RNBContext::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
52void
53RNBContext::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
70void
71RNBContext::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
93void
94RNBContext::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//----------------------------------------------------------------------
118void*
119RNBContext::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:
Greg Clayton58d1c9a2010-10-18 04:14:23 +0000170 case eStateDetached:
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000171 done = true;
172 break;
173 }
174 }
175
176 // Reset any events that we consumed.
177 DNBProcessResetEvents(pid, pid_status_event);
178
179 }
180 }
181 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
182 ctx.Events().ResetEvents(event_proc_thread_running);
183 ctx.Events().SetEvents(event_proc_thread_exiting);
184 return NULL;
185}
186
187
188const char*
189RNBContext::EventsAsString (nub_event_t events, std::string& s)
190{
191 s.clear();
192 if (events & event_proc_state_changed)
193 s += "proc_state_changed ";
194 if (events & event_proc_thread_running)
195 s += "proc_thread_running ";
196 if (events & event_proc_thread_exiting)
197 s += "proc_thread_exiting ";
198 if (events & event_proc_stdio_available)
199 s += "proc_stdio_available ";
200 if (events & event_read_packet_available)
201 s += "read_packet_available ";
202 if (events & event_read_thread_running)
203 s += "read_thread_running ";
204 if (events & event_read_thread_running)
205 s += "read_thread_running ";
206 return s.c_str();
207}
208
209const char *
210RNBContext::LaunchStatusAsString (std::string& s)
211{
212 s.clear();
213
214 const char *err_str = m_launch_status.AsString();
215 if (err_str)
216 s = err_str;
217 else
218 {
219 char error_num_str[64];
220 snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
221 s = error_num_str;
222 }
223 return s.c_str();
224}
225
226bool
227RNBContext::ProcessStateRunning() const
228{
229 nub_state_t pid_state = DNBProcessGetState(m_pid);
230 return pid_state == eStateRunning || pid_state == eStateStepping;
231}