Fix wxExecute process end detect behavior for wxCocoa and wxMac. I have no
idea why the current code used for Intel Macs doesn't work but it's not working for me at all. This should probably be backported to 2.8. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@49155 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -223,6 +223,123 @@ int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
|
|||||||
|
|
||||||
#endif // USE_POLLING/!USE_POLLING
|
#endif // USE_POLLING/!USE_POLLING
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// New implementation avoiding mach ports entirely.
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFSocket.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called due to source signal detected by the CFRunLoop.
|
||||||
|
This is nearly identical to the wxGTK equivalent.
|
||||||
|
*/
|
||||||
|
extern "C" void WXCF_EndProcessDetector(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, void const *data, void *info)
|
||||||
|
{
|
||||||
|
wxEndProcessData * const proc_data = static_cast<wxEndProcessData*>(info);
|
||||||
|
|
||||||
|
/// This code could reasonably be shared between wxMac/wxCocoa and wxGTK ///
|
||||||
|
// PID is always positive on UNIX but wx uses the sign bit as a flag.
|
||||||
|
int pid = (proc_data->pid > 0) ? proc_data->pid : -proc_data->pid;
|
||||||
|
int status = 0;
|
||||||
|
int rc = waitpid(pid, &status, WNOHANG);
|
||||||
|
if(rc == 0)
|
||||||
|
{
|
||||||
|
// Keep waiting in case we got a spurious notification
|
||||||
|
// NOTE: In my limited testing, this doesn't happen.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rc == -1)
|
||||||
|
{ // Error.. really shouldn't happen but try to gracefully handle it
|
||||||
|
wxLogLastError(_T("waitpid"));
|
||||||
|
proc_data->exitcode = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Process ended for some reason
|
||||||
|
wxASSERT_MSG(rc == pid, _T("unexpected waitpid() return value"));
|
||||||
|
|
||||||
|
if(WIFEXITED(status))
|
||||||
|
proc_data->exitcode = WEXITSTATUS(status);
|
||||||
|
else if(WIFSIGNALED(status))
|
||||||
|
// wxGTK doesn't do this but why not?
|
||||||
|
proc_data->exitcode = -WTERMSIG(status);
|
||||||
|
else
|
||||||
|
{ // Should NEVER happen according to waitpid docs
|
||||||
|
wxLogError(wxT("waitpid indicates process exited but not due to exiting or signalling"));
|
||||||
|
proc_data->exitcode = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// The above code could reasonably be shared between wxMac/wxCocoa and wxGTK ///
|
||||||
|
|
||||||
|
/*
|
||||||
|
Either waitpid failed or the process ended successfully. Either way,
|
||||||
|
we're done. It's not if waitpid is going to magically succeed when
|
||||||
|
we get fired again. CFSocketInvalidate closes the fd for us and also
|
||||||
|
invalidates the run loop source for us which should cause it to
|
||||||
|
release the CFSocket (thus causing it to be deallocated) and remove
|
||||||
|
itself from the runloop which should release it and cause it to also
|
||||||
|
be deallocated. Of course, it's possible the RunLoop hangs onto
|
||||||
|
one or both of them by retaining/releasing them within its stack
|
||||||
|
frame. However, that shouldn't be depended on. Assume that s is
|
||||||
|
deallocated due to the following call.
|
||||||
|
*/
|
||||||
|
CFSocketInvalidate(s);
|
||||||
|
|
||||||
|
// Now tell wx that the process has ended.
|
||||||
|
wxHandleProcessTermination(proc_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Implements the GUI-specific wxAddProcessCallback for both wxMac and
|
||||||
|
wxCocoa using the CFSocket/CFRunLoop API which is available to both.
|
||||||
|
Takes advantage of the fact that sockets on UNIX are just regular
|
||||||
|
file descriptors and thus even a non-socket file descriptor can
|
||||||
|
apparently be used with CFSocket so long as you only tell CFSocket
|
||||||
|
to do things with it that would be valid for a non-socket fd.
|
||||||
|
*/
|
||||||
|
int wxAddProcessCallback(wxEndProcessData *proc_data, int fd)
|
||||||
|
{
|
||||||
|
static int s_last_tag = 0;
|
||||||
|
CFSocketContext context =
|
||||||
|
{ 0
|
||||||
|
, static_cast<void*>(proc_data)
|
||||||
|
, NULL
|
||||||
|
, NULL
|
||||||
|
, NULL
|
||||||
|
};
|
||||||
|
CFSocketRef cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,fd,kCFSocketReadCallBack,&WXCF_EndProcessDetector,&context);
|
||||||
|
if(cfSocket == NULL)
|
||||||
|
{
|
||||||
|
wxLogError("Failed to create socket for end process detection");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, /*highest priority:*/0);
|
||||||
|
if(runLoopSource == NULL)
|
||||||
|
{
|
||||||
|
wxLogError("Failed to create CFRunLoopSource from CFSocket for end process detection");
|
||||||
|
// closes the fd.. we can't really stop it, nor do we necessarily want to.
|
||||||
|
CFSocketInvalidate(cfSocket);
|
||||||
|
CFRelease(cfSocket);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Now that the run loop source has the socket retained and we no longer
|
||||||
|
// need to refer to it within this method, we can release it.
|
||||||
|
CFRelease(cfSocket);
|
||||||
|
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
|
||||||
|
// Now that the run loop has the source retained we can release it.
|
||||||
|
CFRelease(runLoopSource);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Feed wx some bullshit.. we don't use it since CFSocket helpfully passes
|
||||||
|
itself into our callback and that's enough to be able to
|
||||||
|
CFSocketInvalidate it which is all we need to do to get everything we
|
||||||
|
just created to be deallocated.
|
||||||
|
*/
|
||||||
|
return ++s_last_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// NOTE: This doesn't really belong here but this was a handy file to
|
// NOTE: This doesn't really belong here but this was a handy file to
|
||||||
// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
|
// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
|
@@ -1227,7 +1227,16 @@ bool wxHandleFatalExceptions(bool doit)
|
|||||||
// wxExecute support
|
// 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
|
// wxMac/wxCocoa don't use the same process end detection mechanisms so we don't
|
||||||
// need wxExecute-related helpers for them
|
// need wxExecute-related helpers for them
|
||||||
|
Reference in New Issue
Block a user