From 46c7e1a1203acb8c85b2f1b0243574634c2afb16 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Wed, 19 Dec 2007 18:52:55 +0000 Subject: [PATCH] implemented wxExecute() for wxDFB; share the implementation with wxX11 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50834 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/unix/execute.h | 29 +++++++++++++-- include/wx/x11/private.h | 4 --- src/dfb/utils.cpp | 6 ---- src/unix/utilsunx.cpp | 76 +++++++++++++++++++++++++++++++++++++++ src/x11/evtloop.cpp | 3 -- src/x11/utils.cpp | 53 --------------------------- 6 files changed, 102 insertions(+), 69 deletions(-) diff --git a/include/wx/unix/execute.h b/include/wx/unix/execute.h index 5f9c4f497d..25376c0cdd 100644 --- a/include/wx/unix/execute.h +++ b/include/wx/unix/execute.h @@ -15,15 +15,27 @@ class WXDLLIMPEXP_FWD_BASE wxProcess; class wxStreamTempInputBuffer; +#if defined(__WXDFB__) || defined(__WXX11__) + #define wxHAS_GENERIC_PROCESS_CALLBACK 1 +#endif + +#ifdef wxHAS_GENERIC_PROCESS_CALLBACK +struct wxEndProcessFDIOHandler; +#endif + // if pid > 0, the execution is async and the data is freed in the callback // executed when the process terminates, if pid < 0, the execution is // synchronous and the caller (wxExecute) frees the data struct wxEndProcessData { - int pid, // pid of the process - tag; // port dependent value + int pid; // pid of the process + int tag; // port dependent value wxProcess *process; // if !NULL: notified on process termination int exitcode; // the exit code + +#ifdef wxHAS_GENERIC_PROCESS_CALLBACK + wxEndProcessFDIOHandler *fdioHandler; +#endif }; // struct in which information is passed from wxExecute() to wxAppTraits @@ -67,8 +79,19 @@ struct wxExecuteData // callback function and is common to all ports (src/unix/utilsunx.cpp) extern WXDLLIMPEXP_BASE void wxHandleProcessTermination(wxEndProcessData *proc_data); -// this function is called to associate the port-specific callback with the +// This function is called to associate the port-specific callback with the // child process. The return valus is port-specific. +// +// The file descriptor 'fd' is descriptor of a dummy pipe opened between the +// parent and the child. No data are written to or read from this pipe, its +// sole purpose is that the child process will close it when it terminates and +// the parent will be notified about it if it looks at 'fd' (e.g. using +// select()). +// +// wxAddProcessCallback() does whatever is necessary to ensure that 'fd' is +// periodically (typically every event loop iteration) checked for its status +// and that wxHandleProcessTermination() is called once 'fd' indicates the +// child terminated. extern WXDLLIMPEXP_CORE int wxAddProcessCallback(wxEndProcessData *proc_data, int fd); #if defined(__WXMAC__) || defined(__WXCOCOA__) diff --git a/include/wx/x11/private.h b/include/wx/x11/private.h index 955152cb34..6422308b63 100644 --- a/include/wx/x11/private.h +++ b/include/wx/x11/private.h @@ -80,9 +80,5 @@ extern Window wxGetWindowParent(Window window); bool wxSetWMDecorations(Window w, long style); bool wxMWMIsRunning(Window w); -// Checks if any of our children are finished. -// implemented in src/x11/utils.cpp -void wxCheckForFinishedChildren(); - #endif // _WX_PRIVATE_H_ diff --git a/src/dfb/utils.cpp b/src/dfb/utils.cpp index 3e201ae40c..df106bdad3 100644 --- a/src/dfb/utils.cpp +++ b/src/dfb/utils.cpp @@ -128,9 +128,3 @@ bool wxGetKeyState(wxKeyCode key) void wxBell() { } - -int wxAddProcessCallback(wxEndProcessData *proc_data, int fd) -{ - wxFAIL_MSG( "wxAddProcessCallback not implemented" ); - return 0; -} diff --git a/src/unix/utilsunx.cpp b/src/unix/utilsunx.cpp index 669ed53a18..589abf242a 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() @@ -1436,6 +1440,78 @@ int wxGUIAppTraits::WaitForChild(wxExecuteData& execData) } } +#if 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 diff --git a/src/x11/evtloop.cpp b/src/x11/evtloop.cpp index 71dc27b0eb..eab9042841 100644 --- a/src/x11/evtloop.cpp +++ b/src/x11/evtloop.cpp @@ -190,9 +190,6 @@ bool wxGUIEventLoop::Dispatch() { XEvent event; - // Start off by checking if any of our child processes have finished. - wxCheckForFinishedChildren(); - // TODO allowing for threads, as per e.g. wxMSW // This now waits until either an X event is received, diff --git a/src/x11/utils.cpp b/src/x11/utils.cpp index 0bcfe8818a..92c6b4c4e3 100644 --- a/src/x11/utils.cpp +++ b/src/x11/utils.cpp @@ -89,59 +89,6 @@ bool wxCheckForInterrupt(wxWindow *WXUNUSED(wnd)) return false; } -// ---------------------------------------------------------------------------- -// wxExecute stuff -// ---------------------------------------------------------------------------- - -WX_DECLARE_HASH_MAP( int, wxEndProcessData*, wxIntegerHash, wxIntegerEqual, wxProcMap ); - -static wxProcMap *gs_procmap; - -int wxAddProcessCallback(wxEndProcessData *proc_data, int fd) -{ - if (!gs_procmap) gs_procmap = new wxProcMap(); - (*gs_procmap)[fd] = proc_data; - return 1; -} - -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; - } -} - // ---------------------------------------------------------------------------- // misc // ---------------------------------------------------------------------------- -- 2.47.2