RNBContext.cpp revision 3b2c41c9d12bafdad87cc271fadd1f816081b9a8
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//----------------------------------------------------------------------
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:
170                case eStateDetached:
171                    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}
232