Add wxAddProcessCallback for both wxMac and wxCocoa and use it for wxCocoa.
It can be turned on for wxMac if desired. See utilsunx.cpp comment. NOTE: I can't add the symbol to version-script.in because other platforms have had this symbol even though wxMac/wxCocoa have not. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@49239 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -231,6 +231,123 @@ int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
|
||||
|
||||
#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
|
||||
// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
|
||||
#if wxUSE_GUI
|
||||
|
@@ -1177,7 +1177,33 @@ bool wxHandleFatalExceptions(bool doit)
|
||||
// wxExecute support
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
NOTE: The original code shipped in 2.8 used __DARWIN__ && __WXMAC__ to wrap
|
||||
the wxGUIAppTraits differences but __DARWIN__ && (__WXMAC__ || __WXCOCOA__)
|
||||
to decide whether to call wxAddProcessCallbackForPid instead of
|
||||
wxAddProcessCallback. This define normalizes things so the two match.
|
||||
|
||||
Since wxCocoa was already creating the pipes in its wxGUIAppTraits I
|
||||
decided to leave that as is and implement wxAddProcessCallback in the
|
||||
utilsexec_cf.cpp file. I didn't see a reason to wrap that in a __WXCOCOA__
|
||||
check since it's valid for both wxMac and wxCocoa.
|
||||
|
||||
Since the existing code is working for wxMac I've left it as is although
|
||||
do note that the old task_for_pid method still used on PPC machines is
|
||||
expected to fail in Leopard PPC and theoretically already fails if you run
|
||||
your PPC app under Rosetta.
|
||||
|
||||
You thus have two choices if you find end process detect broken:
|
||||
1) Change the define below such that the new code is used for wxMac.
|
||||
This is theoretically ABI compatible since the old code still remains
|
||||
in utilsexec_cf.cpp it's just no longer used by this code.
|
||||
2) Change the USE_POLLING define in utilsexc_cf.cpp to 1 unconditionally
|
||||
This is theoretically not compatible since it removes the
|
||||
wxMAC_MachPortEndProcessDetect helper function. Though in practice
|
||||
this shouldn't be a problem since it wasn't prototyped anywhere.
|
||||
*/
|
||||
#define USE_OLD_DARWIN_END_PROCESS_DETECT (defined(__DARWIN__) && defined(__WXMAC__))
|
||||
// #define USE_OLD_DARWIN_END_PROCESS_DETECT 0
|
||||
|
||||
// wxMac doesn't use the same process end detection mechanisms so we don't
|
||||
// need wxExecute-related helpers for it.
|
||||
|
Reference in New Issue
Block a user