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
This commit is contained in:
Václav Slavík
2007-12-19 18:52:55 +00:00
parent 93254327a1
commit 46c7e1a120
6 changed files with 102 additions and 69 deletions

View File

@@ -15,15 +15,27 @@
class WXDLLIMPEXP_FWD_BASE wxProcess; class WXDLLIMPEXP_FWD_BASE wxProcess;
class wxStreamTempInputBuffer; 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 // 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 // executed when the process terminates, if pid < 0, the execution is
// synchronous and the caller (wxExecute) frees the data // synchronous and the caller (wxExecute) frees the data
struct wxEndProcessData struct wxEndProcessData
{ {
int pid, // pid of the process int pid; // pid of the process
tag; // port dependent value int tag; // port dependent value
wxProcess *process; // if !NULL: notified on process termination wxProcess *process; // if !NULL: notified on process termination
int exitcode; // the exit code int exitcode; // the exit code
#ifdef wxHAS_GENERIC_PROCESS_CALLBACK
wxEndProcessFDIOHandler *fdioHandler;
#endif
}; };
// struct in which information is passed from wxExecute() to wxAppTraits // 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) // callback function and is common to all ports (src/unix/utilsunx.cpp)
extern WXDLLIMPEXP_BASE void wxHandleProcessTermination(wxEndProcessData *proc_data); 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. // 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); extern WXDLLIMPEXP_CORE int wxAddProcessCallback(wxEndProcessData *proc_data, int fd);
#if defined(__WXMAC__) || defined(__WXCOCOA__) #if defined(__WXMAC__) || defined(__WXCOCOA__)

View File

@@ -80,9 +80,5 @@ extern Window wxGetWindowParent(Window window);
bool wxSetWMDecorations(Window w, long style); bool wxSetWMDecorations(Window w, long style);
bool wxMWMIsRunning(Window w); bool wxMWMIsRunning(Window w);
// Checks if any of our children are finished.
// implemented in src/x11/utils.cpp
void wxCheckForFinishedChildren();
#endif #endif
// _WX_PRIVATE_H_ // _WX_PRIVATE_H_

View File

@@ -128,9 +128,3 @@ bool wxGetKeyState(wxKeyCode key)
void wxBell() void wxBell()
{ {
} }
int wxAddProcessCallback(wxEndProcessData *proc_data, int fd)
{
wxFAIL_MSG( "wxAddProcessCallback not implemented" );
return 0;
}

View File

@@ -44,6 +44,10 @@
#include "wx/unix/execute.h" #include "wx/unix/execute.h"
#include "wx/unix/private.h" #include "wx/unix/private.h"
#ifdef wxHAS_GENERIC_PROCESS_CALLBACK
#include "wx/private/fdiodispatcher.h"
#endif
#include <pwd.h> #include <pwd.h>
#include <sys/wait.h> // waitpid() #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 #endif // wxUSE_GUI
#if wxUSE_BASE #if wxUSE_BASE

View File

@@ -190,9 +190,6 @@ bool wxGUIEventLoop::Dispatch()
{ {
XEvent event; XEvent event;
// Start off by checking if any of our child processes have finished.
wxCheckForFinishedChildren();
// TODO allowing for threads, as per e.g. wxMSW // TODO allowing for threads, as per e.g. wxMSW
// This now waits until either an X event is received, // This now waits until either an X event is received,

View File

@@ -89,59 +89,6 @@ bool wxCheckForInterrupt(wxWindow *WXUNUSED(wnd))
return false; 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 // misc
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------