X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1a6d6b107198739ad2a65dd4a470f36f60795f7f..a766986f6d443ba1d50e3af25f3306fa56e4518e:/src/unix/utilsunx.cpp diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 8b42a135c0..12d1e9eb06 100644 --- a/src/unix/utilsunx.cpp +++ b/src/unix/utilsunx.cpp @@ -44,6 +44,10 @@ #include "wx/unix/execute.h" #include "wx/unix/private.h" +#ifdef wxHAS_GENERIC_PROCESS_CALLBACK +#include "wx/private/fdiodispatcher.h" +#endif + #include #include // waitpid() @@ -1220,14 +1224,23 @@ bool wxHandleFatalExceptions(bool doit) #if wxUSE_GUI -#if __DARWIN__ +#ifdef __DARWIN__ #include #endif // ---------------------------------------------------------------------------- // wxExecute support // ---------------------------------------------------------------------------- -#define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && (defined(__WXMAC__) || defined(__WXCOCOA__))) +/* + NOTE: If this proves not to work well for wxMac then move back to the old + behavior. If, however, it proves to work just fine, nuke all of the code + for the old behavior. I strongly suggest backporting this to 2.8 as well. + However, beware that while you can nuke the old code here, you cannot + nuke the wxAddProcessCallbackForPid from the 2.8 branch (found in + utilsexc_cf since it's an exported symbol). + */ +// #define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__)) +#define USE_OLD_DARWIN_END_PROCESS_DETECT 0 // wxMac/wxCocoa don't use the same process end detection mechanisms so we don't // need wxExecute-related helpers for them @@ -1383,8 +1396,8 @@ int wxGUIAppTraits::WaitForChild(wxExecuteData& execData) } else // !wxEXEC_NOEVENTS { - // endProcData->pid will be set to 0 from GTK_EndProcessDetector when the - // process terminates + // endProcData->pid will be set to 0 from + // wxHandleProcessTermination when the process terminates while ( endProcData->pid != 0 ) { bool idle = true; @@ -1427,6 +1440,78 @@ int wxGUIAppTraits::WaitForChild(wxExecuteData& execData) } } +#ifdef wxHAS_GENERIC_PROCESS_CALLBACK +struct wxEndProcessFDIOHandler : public wxFDIOHandler +{ + wxEndProcessFDIOHandler(wxEndProcessData *data, int fd) + : m_data(data), m_fd(fd) + {} + + virtual void OnReadWaiting() + { wxFAIL_MSG("this isn't supposed to happen"); } + virtual void OnWriteWaiting() + { wxFAIL_MSG("this isn't supposed to happen"); } + + virtual void OnExceptionWaiting() + { + int pid = (m_data->pid > 0) ? m_data->pid : -(m_data->pid); + int status = 0; + + // has the process really terminated? + int rc = waitpid(pid, &status, WNOHANG); + if ( rc == 0 ) + { + // This can only happen if the child application closes our dummy + // pipe that is used to monitor its lifetime; in that case, our + // best bet is to pretend the process did terminate, because + // otherwise wxExecute() would hang indefinitely + // (OnExceptionWaiting() won't be called again, the descriptor + // is closed now). + wxLogDebug("Child process (PID %i) still alive, even though notification was received that it terminated.", pid); + } + else if ( rc == -1 ) + { + // As above, if waitpid() fails, the best we can do is to log the + // error and pretend the child terminated: + wxLogSysError(_("Failed to check child process' status")); + } + + // set exit code to -1 if something bad happened + m_data->exitcode = (rc > 0 && WIFEXITED(status)) + ? WEXITSTATUS(status) + : -1; + + wxLogTrace("exec", + "Child process (PID %i) terminated with exit code %i", + pid, m_data->exitcode); + + // child exited, end waiting + wxFDIODispatcher::Get()->UnregisterFD(m_fd); + close(m_fd); + + m_data->fdioHandler = NULL; + wxHandleProcessTermination(m_data); + + delete this; + } + + wxEndProcessData *m_data; + int m_fd; +}; + +int wxAddProcessCallback(wxEndProcessData *proc_data, int fd) +{ + proc_data->fdioHandler = new wxEndProcessFDIOHandler(proc_data, fd); + wxFDIODispatcher::Get()->RegisterFD + ( + fd, + proc_data->fdioHandler, + wxFDIO_EXCEPTION + ); + return fd; // unused, but return something unique for the tag +} +#endif // wxHAS_GENERIC_PROCESS_CALLBACK + #endif // wxUSE_GUI #if wxUSE_BASE