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:
@@ -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__)
|
||||||
|
@@ -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_
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user