Home | History | Annotate | Download | only in source
      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 
     16 #include <sys/stat.h>
     17 #include <sstream>
     18 
     19 #include "RNBRemote.h"
     20 #include "DNB.h"
     21 #include "DNBLog.h"
     22 #include "CFString.h"
     23 
     24 
     25 //----------------------------------------------------------------------
     26 // Destructor
     27 //----------------------------------------------------------------------
     28 RNBContext::~RNBContext()
     29 {
     30     SetProcessID (INVALID_NUB_PROCESS);
     31 }
     32 
     33 //----------------------------------------------------------------------
     34 // RNBContext constructor
     35 //----------------------------------------------------------------------
     36 
     37 const char *
     38 RNBContext::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 
     47 const char *
     48 RNBContext::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 
     56 bool
     57 RNBContext::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 
     70 void
     71 RNBContext::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 
     88 void
     89 RNBContext::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 
    111 void
    112 RNBContext::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 //----------------------------------------------------------------------
    136 void*
    137 RNBContext::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 | 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);
    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             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             }
    177 
    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:
    195                 case eStateDetached:
    196                     done = true;
    197                     break;
    198                 default:
    199                     break;
    200                 }
    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 
    215 const char*
    216 RNBContext::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 ";
    227     if (events & event_proc_profile_data)
    228         s += "proc_profile_data ";
    229     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 
    238 const char *
    239 RNBContext::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 
    255 bool
    256 RNBContext::ProcessStateRunning() const
    257 {
    258     nub_state_t pid_state = DNBProcessGetState(m_pid);
    259     return pid_state == eStateRunning || pid_state == eStateStepping;
    260 }
    261