void OnSignalChildHandler(int /*signal*/, siginfo_t *siginfo, void * /*ucontext*/) { // Build the log message wxString msg; msg << wxT("OnSignalChildHandler() has been called for child process with pid `") << siginfo->si_pid << wxT("'. "); // Make sure we leave no zombies by calling waitpid() int status = 0; pid_t result = AmuleWaitPid(siginfo->si_pid, &status, WNOHANG, &msg); if (result != 1 && result != 0 && (WIFEXITED(status) || WIFSIGNALED(status))) { // Fetch the wxEndProcessData structure corresponding to this pid EndProcessDataMap::iterator it = endProcDataMap.find(siginfo->si_pid); if (it != endProcDataMap.end()) { wxEndProcessData *endProcData = it->second; // Remove this entry from the process map endProcDataMap.erase(siginfo->si_pid); // Save the exit code for the wxProcess object to read later endProcData->exitcode = result != -1 && WIFEXITED(status) ? WEXITSTATUS(status) : -1; // Make things work as in wxGUI wxHandleProcessTermination(endProcData); // wxHandleProcessTermination() will "delete endProcData;" // So we do not delete it again, ok? Do not uncomment this line. //delete endProcData; } else { msg << wxT(" Error: the child process pid is not on the pid map."); } } // Log our passage here AddDebugLogLineN(logGeneral, msg); }
static void GTK_EndProcessDetector(gpointer data, gint source, GdkInputCondition WXUNUSED(condition) ) { wxEndProcessData *proc_data = (wxEndProcessData *)data; // has the process really terminated? unfortunately GDK (or GLib) seem to // generate G_IO_HUP notification even when it simply tries to read from a // closed fd and hasn't terminated at all int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid); int status = 0; int rc = waitpid(pid, &status, WNOHANG); if ( rc == 0 ) { // no, it didn't exit yet, continue waiting return; } // set exit code to -1 if something bad happened proc_data->exitcode = rc != -1 && WIFEXITED(status) ? WEXITSTATUS(status) : -1; // child exited, end waiting close(source); // don't call us again! gdk_input_remove(proc_data->tag); wxHandleProcessTermination(proc_data); }
virtual void OnReadWaiting() { wxFDIODispatcher::Get()->UnregisterFD(m_fd); close(m_fd); wxHandleProcessTermination(m_data); delete this; }
/*! Called due to source signal detected by the CFRunLoop. This is nearly identical to the wxGTK equivalent. */ extern "C" void WXCF_EndProcessDetector(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, void const *data, void *info) { wxEndProcessData * const proc_data = static_cast<wxEndProcessData*>(info); /// This code could reasonably be shared between wxMac/wxCocoa and wxGTK /// // PID is always positive on UNIX but wx uses the sign bit as a flag. int pid = (proc_data->pid > 0) ? proc_data->pid : -proc_data->pid; int status = 0; int rc = waitpid(pid, &status, WNOHANG); if(rc == 0) { // Keep waiting in case we got a spurious notification // NOTE: In my limited testing, this doesn't happen. return; } if(rc == -1) { // Error.. really shouldn't happen but try to gracefully handle it wxLogLastError(_T("waitpid")); proc_data->exitcode = -1; } else { // Process ended for some reason wxASSERT_MSG(rc == pid, _T("unexpected waitpid() return value")); if(WIFEXITED(status)) proc_data->exitcode = WEXITSTATUS(status); else if(WIFSIGNALED(status)) // wxGTK doesn't do this but why not? proc_data->exitcode = -WTERMSIG(status); else { // Should NEVER happen according to waitpid docs wxLogError(wxT("waitpid indicates process exited but not due to exiting or signalling")); proc_data->exitcode = -1; } } /// The above code could reasonably be shared between wxMac/wxCocoa and wxGTK /// /* Either waitpid failed or the process ended successfully. Either way, we're done. It's not if waitpid is going to magically succeed when we get fired again. CFSocketInvalidate closes the fd for us and also invalidates the run loop source for us which should cause it to release the CFSocket (thus causing it to be deallocated) and remove itself from the runloop which should release it and cause it to also be deallocated. Of course, it's possible the RunLoop hangs onto one or both of them by retaining/releasing them within its stack frame. However, that shouldn't be depended on. Assume that s is deallocated due to the following call. */ CFSocketInvalidate(s); // Now tell wx that the process has ended. wxHandleProcessTermination(proc_data); }
static void xt_notify_end_process(XtPointer data, int *WXUNUSED(fid), XtInputId *id) { wxEndProcessData *proc_data = (wxEndProcessData *)data; wxHandleProcessTermination(proc_data); // VZ: I think they should be the same... wxASSERT( (int)*id == proc_data->tag ); XtRemoveInput(*id); }
static gboolean EndProcessDetector(GIOChannel* source, GIOCondition, void* data) { wxEndProcessData * const proc_data = static_cast<wxEndProcessData *>(data); // child exited, end waiting close(g_io_channel_unix_get_fd(source)); wxHandleProcessTermination(proc_data); // don't call us again! return false; }
void OnTerminate(wxProcessEvent& event) { Disconnect(-1, wxEVT_END_PROCESS, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate)); wxHandleProcessTermination(m_data); // NOTE: We don't use this to delay destruction until the next idle run but rather to // avoid killing ourselves while our caller (which is our wxEvtHandler superclass // ProcessPendingEvents) still needs our m_eventsLocker to be valid. // Since we're in the GUI library we can guarantee that ScheduleForDestroy is using // the GUI implementation which delays destruction and not the base implementation // which does it immediately. wxTheApp->GetTraits()->ScheduleForDestroy(this); }
static void GTK_EndProcessDetector(gpointer data, gint source, GdkInputCondition WXUNUSED(condition)) { wxEndProcessData * const proc_data = static_cast<wxEndProcessData *>(data); // child exited, end waiting close(source); // don't call us again! gdk_input_remove(proc_data->tag); wxHandleProcessTermination(proc_data); }
void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data) { wxEndProcessData *proc_data = (wxEndProcessData*)data; wxLogDebug(wxT("Process ended")); int status = 0; int rc = waitpid(abs(proc_data->pid), &status, WNOHANG); if(!rc) { wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!")); return; } if((rc != -1) && WIFEXITED(status)) proc_data->exitcode = WEXITSTATUS(status); else proc_data->exitcode = -1; wxHandleProcessTermination(proc_data); }
/*! Called due to source signal detected by the CFRunLoop. This is nearly identical to the wxGTK equivalent. */ extern "C" void WXCF_EndProcessDetector(CFSocketRef s, CFSocketCallBackType WXUNUSED(callbackType), CFDataRef WXUNUSED(address), void const *WXUNUSED(data), void *info) { /* Either our pipe was closed or the process ended successfully. Either way, we're done. It's not if waitpid is going to magically succeed when we get fired again. CFSocketInvalidate closes the fd for us and also invalidates the run loop source for us which should cause it to release the CFSocket (thus causing it to be deallocated) and remove itself from the runloop which should release it and cause it to also be deallocated. Of course, it's possible the RunLoop hangs onto one or both of them by retaining/releasing them within its stack frame. However, that shouldn't be depended on. Assume that s is deallocated due to the following call. */ CFSocketInvalidate(s); // Now tell wx that the process has ended. wxHandleProcessTermination(static_cast<wxEndProcessData *>(info)); }
void wxCheckForFinishedChildren() { wxProcMap::iterator it; if (!gs_procmap) return; if (gs_procmap->size() == 0) { // Map empty, delete it. delete gs_procmap; gs_procmap = NULL; return; } for (it = gs_procmap->begin();it != gs_procmap->end(); ++it) { wxEndProcessData *proc_data = it->second; int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid); int status = 0; // has the process really terminated? int rc = waitpid(pid, &status, WNOHANG); if (rc == 0) continue; // no, it didn't exit yet, continue waiting // set exit code to -1 if something bad happened proc_data->exitcode = rc != -1 && WIFEXITED(status) ? WEXITSTATUS(status) : -1; // child exited, end waiting close(it->first); // don't call us again! gs_procmap->erase(it->first); wxHandleProcessTermination(proc_data); // Iterator is invalid. Handle any further children in subsequent // calls. break; } }