1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/corefoundation/utilsexec_cf.cpp
3 // Purpose: Execution-related utilities for Darwin
4 // Author: David Elliott, Ryan Norton (wxMacExecute)
5 // Modified by: Stefan Csomor (added necessary wxT for unicode builds)
8 // Copyright: (c) David Elliott, Ryan Norton
9 // Licence: wxWindows licence
10 // Notes: This code comes from src/mac/carbon/utilsexc.cpp,1.11
11 /////////////////////////////////////////////////////////////////////////////
13 #include "wx/wxprec.h"
17 #endif //ndef WX_PRECOMP
18 #include "wx/unix/execute.h"
19 #include "wx/stdpaths.h"
20 #include "wx/apptrait.h"
21 #include "wx/thread.h"
22 #include "wx/process.h"
26 // Use polling instead of Mach ports, which doesn't work on Intel
27 // due to task_for_pid security issues.
29 // What's a better test for Intel vs PPC?
30 #ifdef WORDS_BIGENDIAN
39 class wxProcessTerminationEventHandler
: public wxEvtHandler
42 wxProcessTerminationEventHandler(wxEndProcessData
* data
)
45 Connect(-1, wxEVT_END_PROCESS
, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate
));
48 void OnTerminate(wxProcessEvent
& event
)
50 Disconnect(-1, wxEVT_END_PROCESS
, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate
));
51 wxHandleProcessTermination(m_data
);
55 wxEndProcessData
* m_data
;
58 class wxProcessTerminationThread
: public wxThread
61 wxProcessTerminationThread(wxEndProcessData
* data
, wxProcessTerminationEventHandler
* handler
): wxThread(wxTHREAD_DETACHED
)
67 virtual void* Entry();
69 wxProcessTerminationEventHandler
* m_handler
;
70 wxEndProcessData
* m_data
;
73 // The problem with this is that we may be examining the
74 // process e.g. in OnIdle at the point this cleans up the process,
75 // so we need to delay until it's safe.
77 void* wxProcessTerminationThread::Entry()
83 int rc
= waitpid(abs(m_data
->pid
), & status
, WNOHANG
);
86 if ((rc
!= -1) && WIFEXITED(status
))
87 m_data
->exitcode
= WEXITSTATUS(status
);
89 m_data
->exitcode
= -1;
92 wxPostEvent(m_handler
, event
);
101 int wxAddProcessCallbackForPid(wxEndProcessData
*proc_data
, int pid
)
106 wxProcessTerminationEventHandler
* handler
= new wxProcessTerminationEventHandler(proc_data
);
107 wxProcessTerminationThread
* thread
= new wxProcessTerminationThread(proc_data
, handler
);
109 if (thread
->Create() != wxTHREAD_NO_ERROR
)
111 wxLogDebug(wxT("Could not create termination detection thread."));
121 #else // !wxUSE_THREADS
122 int wxAddProcessCallbackForPid(wxEndProcessData
*, int)
124 wxLogDebug(wxT("Could not create termination detection thread."));
127 #endif // wxUSE_THREADS/!wxUSE_THREADS
129 #else // !USE_POLLING
131 #include <CoreFoundation/CFMachPort.h>
133 #include <mach/mach.h>
136 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port
, void *data
)
138 wxEndProcessData
*proc_data
= (wxEndProcessData
*)data
;
139 wxLogDebug(wxT("Process ended"));
141 int rc
= waitpid(abs(proc_data
->pid
), &status
, WNOHANG
);
144 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
147 if((rc
!= -1) && WIFEXITED(status
))
148 proc_data
->exitcode
= WEXITSTATUS(status
);
150 proc_data
->exitcode
= -1;
151 wxHandleProcessTermination(proc_data
);
154 int wxAddProcessCallbackForPid(wxEndProcessData
*proc_data
, int pid
)
158 kern_return_t kernResult
;
159 mach_port_t taskOfOurProcess
;
160 mach_port_t machPortForProcess
;
161 taskOfOurProcess
= mach_task_self();
162 if(taskOfOurProcess
== MACH_PORT_NULL
)
164 wxLogDebug(wxT("No mach_task_self()"));
167 wxLogDebug(wxT("pid=%d"),pid
);
168 kernResult
= task_for_pid(taskOfOurProcess
,pid
, &machPortForProcess
);
169 if(kernResult
!= KERN_SUCCESS
)
171 wxLogDebug(wxT("no task_for_pid()"));
172 // try seeing if it is already dead or something
173 // FIXME: a better method would be to call the callback function
174 // from idle time until the process terminates. Of course, how
175 // likely is it that it will take more than 0.1 seconds for the
176 // mach terminate event to make its way to the BSD subsystem?
177 usleep(100); // sleep for 0.1 seconds
178 wxMAC_MachPortEndProcessDetect(NULL
, (void*)proc_data
);
181 CFMachPortContext termcb_contextinfo
;
182 termcb_contextinfo
.version
= 0;
183 termcb_contextinfo
.info
= (void*)proc_data
;
184 termcb_contextinfo
.retain
= NULL
;
185 termcb_contextinfo
.release
= NULL
;
186 termcb_contextinfo
.copyDescription
= NULL
;
187 CFMachPortRef CFMachPortForProcess
;
188 Boolean ShouldFreePort
;
189 CFMachPortForProcess
= CFMachPortCreateWithPort(NULL
, machPortForProcess
, NULL
, &termcb_contextinfo
, &ShouldFreePort
);
190 if(!CFMachPortForProcess
)
192 wxLogDebug(wxT("No CFMachPortForProcess"));
193 mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
198 kernResult
= mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
199 if(kernResult
!=KERN_SUCCESS
)
201 wxLogDebug(wxT("Couldn't deallocate mach port"));
205 CFMachPortSetInvalidationCallBack(CFMachPortForProcess
, &wxMAC_MachPortEndProcessDetect
);
206 CFRunLoopSourceRef runloopsource
;
207 runloopsource
= CFMachPortCreateRunLoopSource(NULL
,CFMachPortForProcess
, (CFIndex
)0);
210 wxLogDebug(wxT("Couldn't create runloopsource"));
214 CFRelease(CFMachPortForProcess
);
216 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource
,kCFRunLoopDefaultMode
);
217 CFRelease(runloopsource
);
218 wxLogDebug(wxT("Successfully added notification to the runloop"));
222 #endif // USE_POLLING/!USE_POLLING
224 // NOTE: This doesn't really belong here but this was a handy file to
225 // put it in because it's already compiled for wxCocoa and wxMac GUI lib.
228 static wxStandardPathsCF gs_stdPaths
;
229 wxStandardPathsBase
& wxGUIAppTraits::GetStandardPaths()