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
|
#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
|
||||||
|
@@ -1177,7 +1177,33 @@ bool wxHandleFatalExceptions(bool doit)
|
|||||||
// wxExecute support
|
// 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 (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
|
// wxMac doesn't use the same process end detection mechanisms so we don't
|
||||||
// need wxExecute-related helpers for it.
|
// need wxExecute-related helpers for it.
|
||||||
|
Reference in New Issue
Block a user