//---------------------------------------------------------------------- // 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; default: 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; }
void MachThread::SetState(nub_state_t state) { PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); m_state = state; DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id); }
//---------------------------------------------------------------------- // 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); #if defined(__APPLE__) pthread_setname_np("child process status watcher thread"); #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) struct sched_param thread_param; int thread_sched_policy; if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) { thread_param.sched_priority = 47; pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); } #endif #endif bool done = false; while (!done) { DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, " "eEventProcessRunningStateChanged | " "eEventProcessStoppedStateChanged | eEventStdioAvailable " "| eEventProfileDataAvailable, true)...", __FUNCTION__); nub_event_t pid_status_event = DNBProcessWaitForEvents( pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true, NULL); DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, " "eEventProcessRunningStateChanged | " "eEventProcessStoppedStateChanged | eEventStdioAvailable " "| eEventProfileDataAvailable, 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 & eEventProfileDataAvailable) { DNBLogThreadedIf( LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got profile data event....", __FUNCTION__, pid); ctx.Events().SetEvents(RNBContext::event_proc_profile_data); // Wait for the main thread to consume this notification if it requested // we wait for it ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data); } 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; default: 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; }
// Return the new run loop mode based off of the current process state RNBRunLoopMode HandleProcessStateChange (RNBRemoteSP &remote, bool initialize) { RNBContext& ctx = remote->Context(); nub_process_t pid = ctx.ProcessID(); if (pid == INVALID_NUB_PROCESS) { DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); return eRNBRunLoopModeExit; } nub_state_t pid_state = DNBProcessGetState (pid); DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); switch (pid_state) { case eStateInvalid: case eStateUnloaded: // Something bad happened return eRNBRunLoopModeExit; break; case eStateAttaching: case eStateLaunching: return eRNBRunLoopModeInferiorExecuting; case eStateSuspended: case eStateCrashed: case eStateStopped: if (initialize == false) { // Compare the last stop count to our current notion of a stop count // to make sure we don't notify more than once for a given stop. nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); if (pid_stop_count_changed) { remote->FlushSTDIO(); if (ctx.GetProcessStopCount() == 1) { DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); } else { DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); remote->NotifyThatProcessStopped (); } } else { DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); } } return eRNBRunLoopModeInferiorExecuting; case eStateStepping: case eStateRunning: return eRNBRunLoopModeInferiorExecuting; case eStateExited: remote->HandlePacket_last_signal(NULL); return eRNBRunLoopModeExit; case eStateDetached: return eRNBRunLoopModeExit; } // Catch all... return eRNBRunLoopModeExit; }