]> git.saurik.com Git - wxWidgets.git/commitdiff
implemented wxExecute() for wxDFB; share the implementation with wxX11
authorVáclav Slavík <vslavik@fastmail.fm>
Wed, 19 Dec 2007 18:52:55 +0000 (18:52 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Wed, 19 Dec 2007 18:52:55 +0000 (18:52 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@50834 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/unix/execute.h
include/wx/x11/private.h
src/dfb/utils.cpp
src/unix/utilsunx.cpp
src/x11/evtloop.cpp
src/x11/utils.cpp

index 5f9c4f497dcecec28b54dc0813dfc2b7f6b40a89..25376c0cddf04e68aad3a2168f452d20d73c7b53 100644 (file)
 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__)
index 955152cb3424aba1a5c9ca78086c9bec01fc2e5b..6422308b6381b59e621344ae3423725e85446960 100644 (file)
@@ -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_
index 3e201ae40ccb626b4f26a5790b323a4532ce1fab..df106bdad30cebbae716b17e7e3e719c24d7e32f 100644 (file)
@@ -128,9 +128,3 @@ bool wxGetKeyState(wxKeyCode key)
 void wxBell()
 {
 }
-
-int wxAddProcessCallback(wxEndProcessData *proc_data, int fd)
-{
-    wxFAIL_MSG( "wxAddProcessCallback not implemented" );
-    return 0;
-}
index 669ed53a1851c08126849705f1c1713fdfe37d7d..589abf242a947155371db38fc23acf45198e7103 100644 (file)
 #include "wx/unix/execute.h"
 #include "wx/unix/private.h"
 
+#ifdef wxHAS_GENERIC_PROCESS_CALLBACK
+#include "wx/private/fdiodispatcher.h"
+#endif
+
 #include <pwd.h>
 #include <sys/wait.h>       // 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
 
index 71dc27b0eb35b7e9250ddbf41798c424fda8d66c..eab9042841002696f901b3471fe326e8d5b77c4e 100644 (file)
@@ -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,
index 0bcfe8818a3937e3b3aa1c111a86d40e2013e788..92c6b4c4e3e6f6c4975d6058cd407ea6deb65d41 100644 (file)
@@ -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
 // ----------------------------------------------------------------------------