]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/utilsexc_cf.cpp
corrected version in the libraries names: it's only 2 digits even in development...
[wxWidgets.git] / src / mac / corefoundation / utilsexc_cf.cpp
CommitLineData
5d553c56
DE
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/mac/corefoundation/utilsexec_cf.cpp
3// Purpose: Execution-related utilities for Darwin
62705a27 4// Author: David Elliott, Ryan Norton (wxMacExecute)
5d553c56
DE
5// Modified by: Stefan Csomor (added necessary wxT for unicode builds)
6// Created: 2004-11-04
7// RCS-ID: $Id$
62705a27 8// Copyright: (c) David Elliott, Ryan Norton
24498521 9// Licence: wxWindows licence
5d553c56
DE
10// Notes: This code comes from src/mac/carbon/utilsexc.cpp,1.11
11/////////////////////////////////////////////////////////////////////////////
12
13#include "wx/wxprec.h"
14#ifndef WX_PRECOMP
15 #include "wx/log.h"
16 #include "wx/utils.h"
17#endif //ndef WX_PRECOMP
18#include "wx/unix/execute.h"
fc480dc1
DE
19#include "wx/stdpaths.h"
20#include "wx/apptrait.h"
110ffa16
JS
21#include "wx/thread.h"
22#include "wx/process.h"
5d553c56 23
f523d7ce
VZ
24#include <sys/wait.h>
25
110ffa16
JS
26// Use polling instead of Mach ports, which doesn't work on Intel
27// due to task_for_pid security issues.
62705a27 28
110ffa16
JS
29// What's a better test for Intel vs PPC?
30#ifdef WORDS_BIGENDIAN
31#define USE_POLLING 0
32#else
33#define USE_POLLING 1
34#endif
35
36#if USE_POLLING
37
4fa167e6 38#if wxUSE_THREADS
110ffa16
JS
39class wxProcessTerminationEventHandler: public wxEvtHandler
40{
41 public:
42 wxProcessTerminationEventHandler(wxEndProcessData* data)
43 {
44 m_data = data;
45 Connect(-1, wxEVT_END_PROCESS, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate));
46 }
47
48 void OnTerminate(wxProcessEvent& event)
49 {
50 Disconnect(-1, wxEVT_END_PROCESS, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate));
51 wxHandleProcessTermination(m_data);
52 delete this;
53 }
54
55 wxEndProcessData* m_data;
56};
57
58class wxProcessTerminationThread: public wxThread
59{
60 public:
61 wxProcessTerminationThread(wxEndProcessData* data, wxProcessTerminationEventHandler* handler): wxThread(wxTHREAD_DETACHED)
62 {
63 m_data = data;
64 m_handler = handler;
65 }
66
67 virtual void* Entry();
68
69 wxProcessTerminationEventHandler* m_handler;
70 wxEndProcessData* m_data;
71};
72
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.
76
77void* wxProcessTerminationThread::Entry()
78{
79 while (true)
80 {
81 usleep(100);
82 int status = 0;
83 int rc = waitpid(abs(m_data->pid), & status, WNOHANG);
84 if (rc != 0)
85 {
86 if ((rc != -1) && WIFEXITED(status))
87 m_data->exitcode = WEXITSTATUS(status);
88 else
89 m_data->exitcode = -1;
90
91 wxProcessEvent event;
92 wxPostEvent(m_handler, event);
93
94 break;
95 }
96 }
9e34f56b 97
110ffa16
JS
98 return NULL;
99}
100
101int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
102{
103 if (pid < 1)
104 return -1;
105
9e34f56b 106 wxProcessTerminationEventHandler* handler = new wxProcessTerminationEventHandler(proc_data);
110ffa16 107 wxProcessTerminationThread* thread = new wxProcessTerminationThread(proc_data, handler);
9e34f56b 108
110ffa16
JS
109 if (thread->Create() != wxTHREAD_NO_ERROR)
110 {
111 wxLogDebug(wxT("Could not create termination detection thread."));
112 delete thread;
113 delete handler;
114 return -1;
115 }
116
117 thread->Run();
9e34f56b 118
110ffa16
JS
119 return 0;
120}
4fa167e6
PC
121#else // !wxUSE_THREADS
122int wxAddProcessCallbackForPid(wxEndProcessData*, int)
123{
124 wxLogDebug(wxT("Could not create termination detection thread."));
125 return -1;
126}
127#endif // wxUSE_THREADS/!wxUSE_THREADS
110ffa16 128
f523d7ce 129#else // !USE_POLLING
62705a27 130
5d553c56 131#include <CoreFoundation/CFMachPort.h>
5d553c56
DE
132extern "C" {
133#include <mach/mach.h>
134}
135
136void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
137{
24498521 138 wxEndProcessData *proc_data = (wxEndProcessData*)data;
3bdb628b 139 wxLogDebug(wxT("Process ended"));
24498521
DE
140 int status = 0;
141 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
142 if(!rc)
143 {
f523d7ce
VZ
144 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
145 return;
24498521
DE
146 }
147 if((rc != -1) && WIFEXITED(status))
f523d7ce 148 proc_data->exitcode = WEXITSTATUS(status);
24498521 149 else
f523d7ce 150 proc_data->exitcode = -1;
24498521 151 wxHandleProcessTermination(proc_data);
5d553c56
DE
152}
153
154int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
155{
156 if(pid < 1)
157 return -1;
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)
163 {
164 wxLogDebug(wxT("No mach_task_self()"));
165 return -1;
166 }
167 wxLogDebug(wxT("pid=%d"),pid);
168 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
169 if(kernResult != KERN_SUCCESS)
170 {
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);
179 return -1;
180 }
181 CFMachPortContext termcb_contextinfo;
b409fa19 182 termcb_contextinfo.version = 0;
5d553c56
DE
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)
191 {
192 wxLogDebug(wxT("No CFMachPortForProcess"));
193 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
194 return -1;
195 }
196 if(ShouldFreePort)
197 {
198 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
199 if(kernResult!=KERN_SUCCESS)
200 {
201 wxLogDebug(wxT("Couldn't deallocate mach port"));
202 return -1;
203 }
204 }
205 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
206 CFRunLoopSourceRef runloopsource;
207 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
208 if(!runloopsource)
209 {
210 wxLogDebug(wxT("Couldn't create runloopsource"));
211 return -1;
212 }
9e34f56b 213
5d553c56
DE
214 CFRelease(CFMachPortForProcess);
215
216 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
217 CFRelease(runloopsource);
218 wxLogDebug(wxT("Successfully added notification to the runloop"));
219 return 0;
220}
221
f523d7ce 222#endif // USE_POLLING/!USE_POLLING
110ffa16 223
9e34f56b 224// NOTE: This doesn't really belong here but this was a handy file to
fc480dc1 225// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
9e34f56b
VZ
226#if wxUSE_GUI
227
fc480dc1
DE
228static wxStandardPathsCF gs_stdPaths;
229wxStandardPathsBase& wxGUIAppTraits::GetStandardPaths()
230{
231 return gs_stdPaths;
232}
233
9e34f56b
VZ
234#endif // wxUSE_GUI
235