forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			232 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- RNBContext.cpp ------------------------------------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| //  Created by Greg Clayton on 12/12/07.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "RNBContext.h"
 | |
| #include "RNBRemote.h"
 | |
| #include "DNB.h"
 | |
| #include "DNBLog.h"
 | |
| #include "CFString.h"
 | |
| #include <sstream>
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // Destructor
 | |
| //----------------------------------------------------------------------
 | |
| RNBContext::~RNBContext()
 | |
| {
 | |
|     SetProcessID (INVALID_NUB_PROCESS);
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // RNBContext constructor
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| const char *
 | |
| RNBContext::EnvironmentAtIndex (int index)
 | |
| {
 | |
|     if (index < m_env_vec.size())
 | |
|         return m_env_vec[index].c_str();
 | |
|     else
 | |
|         return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| const char *
 | |
| RNBContext::ArgumentAtIndex (int index)
 | |
| {
 | |
|     if (index < m_arg_vec.size())
 | |
|         return m_arg_vec[index].c_str();
 | |
|     else
 | |
|         return NULL;
 | |
| }
 | |
| 
 | |
| void
 | |
| RNBContext::SetProcessID (nub_process_t pid)
 | |
| {
 | |
|     // Delete and events we created
 | |
|     if (m_pid != INVALID_NUB_PROCESS)
 | |
|     {
 | |
|         StopProcessStatusThread ();
 | |
|         // Unregister this context as a client of the process's events.
 | |
|     }
 | |
|     // Assign our new process ID
 | |
|     m_pid = pid;
 | |
| 
 | |
|     if (pid != INVALID_NUB_PROCESS)
 | |
|     {
 | |
|         StartProcessStatusThread ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| RNBContext::StartProcessStatusThread()
 | |
| {
 | |
|     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
 | |
|     if ((m_events.GetEventBits() & event_proc_thread_running) == 0)
 | |
|     {
 | |
|         int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this);
 | |
|         if (err == 0)
 | |
|         {
 | |
|             // Our thread was successfully kicked off, wait for it to
 | |
|             // set the started event so we can safely continue
 | |
|             m_events.WaitForSetEvents (event_proc_thread_running);
 | |
|             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err);
 | |
|             m_events.ResetEvents (event_proc_thread_running);
 | |
|             m_events.SetEvents (event_proc_thread_exiting);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| RNBContext::StopProcessStatusThread()
 | |
| {
 | |
|     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);
 | |
|     if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running)
 | |
|     {
 | |
|         struct timespec timeout_abstime;
 | |
|         DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);
 | |
|         // Wait for 2 seconds for the rx thread to exit
 | |
|         if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting)
 | |
|         {
 | |
|             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__);
 | |
|             // Kill the RX thread???
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| // This thread's sole purpose is to watch for any status changes in the
 | |
| // child process.
 | |
| //----------------------------------------------------------------------
 | |
| void*
 | |
| RNBContext::ThreadFunctionProcessStatus(void *arg)
 | |
| {
 | |
|     RNBRemoteSP remoteSP(g_remoteSP);
 | |
|     RNBRemote* remote = remoteSP.get();
 | |
|     if (remote == NULL)
 | |
|         return NULL;
 | |
|     RNBContext& ctx = remote->Context();
 | |
| 
 | |
|     nub_process_t pid = ctx.ProcessID();
 | |
|     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid);
 | |
|     ctx.Events().SetEvents (RNBContext::event_proc_thread_running);
 | |
|     bool done = false;
 | |
|     while (!done)
 | |
|     {
 | |
|         DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true)...", __FUNCTION__);
 | |
|         nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true, NULL);
 | |
|         DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event);
 | |
| 
 | |
|         if (pid_status_event == 0)
 | |
|         {
 | |
|             DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid);
 | |
|         //    done = true;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if (pid_status_event & eEventStdioAvailable)
 | |
|             {
 | |
|                 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid);
 | |
|                 ctx.Events().SetEvents (RNBContext::event_proc_stdio_available);
 | |
|                 // Wait for the main thread to consume this notification if it requested we wait for it
 | |
|                 ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);
 | |
|             }
 | |
| 
 | |
| 
 | |
|             if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged))
 | |
|             {
 | |
|                 nub_state_t pid_state = DNBProcessGetState(pid);
 | |
|                 DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state));
 | |
| 
 | |
|                 // Let the main thread know there is a process state change to see
 | |
|                 ctx.Events().SetEvents (RNBContext::event_proc_state_changed);
 | |
|                 // Wait for the main thread to consume this notification if it requested we wait for it
 | |
|                 ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);
 | |
| 
 | |
|                 switch (pid_state)
 | |
|                 {
 | |
|                 case eStateStopped:
 | |
|                     break;
 | |
| 
 | |
|                 case eStateInvalid:
 | |
|                 case eStateExited:
 | |
|                 case eStateDetached:
 | |
|                     done = true;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Reset any events that we consumed.
 | |
|             DNBProcessResetEvents(pid, pid_status_event);
 | |
| 
 | |
|         }
 | |
|     }
 | |
|     DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid);
 | |
|     ctx.Events().ResetEvents(event_proc_thread_running);
 | |
|     ctx.Events().SetEvents(event_proc_thread_exiting);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| const char*
 | |
| RNBContext::EventsAsString (nub_event_t events, std::string& s)
 | |
| {
 | |
|     s.clear();
 | |
|     if (events & event_proc_state_changed)
 | |
|         s += "proc_state_changed ";
 | |
|     if (events & event_proc_thread_running)
 | |
|         s += "proc_thread_running ";
 | |
|     if (events & event_proc_thread_exiting)
 | |
|         s += "proc_thread_exiting ";
 | |
|     if (events & event_proc_stdio_available)
 | |
|         s += "proc_stdio_available ";
 | |
|     if (events & event_read_packet_available)
 | |
|         s += "read_packet_available ";
 | |
|     if (events & event_read_thread_running)
 | |
|         s += "read_thread_running ";
 | |
|     if (events & event_read_thread_running)
 | |
|         s += "read_thread_running ";
 | |
|     return s.c_str();
 | |
| }
 | |
| 
 | |
| const char *
 | |
| RNBContext::LaunchStatusAsString (std::string& s)
 | |
| {
 | |
|     s.clear();
 | |
| 
 | |
|     const char *err_str = m_launch_status.AsString();
 | |
|     if (err_str)
 | |
|         s = err_str;
 | |
|     else
 | |
|     {
 | |
|         char error_num_str[64];
 | |
|         snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error());
 | |
|         s = error_num_str;
 | |
|     }
 | |
|     return s.c_str();
 | |
| }
 | |
| 
 | |
| bool
 | |
| RNBContext::ProcessStateRunning() const
 | |
| {
 | |
|     nub_state_t pid_state = DNBProcessGetState(m_pid);
 | |
|     return pid_state == eStateRunning || pid_state == eStateStepping;
 | |
| }
 |