]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/utilsexc_cf.cpp
Final fix for Bug #1472688 'wxString::Trim() is broken'
[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
110ffa16
JS
24// Use polling instead of Mach ports, which doesn't work on Intel
25// due to task_for_pid security issues.
62705a27 26
110ffa16
JS
27// What's a better test for Intel vs PPC?
28#ifdef WORDS_BIGENDIAN
29#define USE_POLLING 0
30#else
31#define USE_POLLING 1
32#endif
33
34#if USE_POLLING
35
36class wxProcessTerminationEventHandler: public wxEvtHandler
37{
38 public:
39 wxProcessTerminationEventHandler(wxEndProcessData* data)
40 {
41 m_data = data;
42 Connect(-1, wxEVT_END_PROCESS, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate));
43 }
44
45 void OnTerminate(wxProcessEvent& event)
46 {
47 Disconnect(-1, wxEVT_END_PROCESS, wxProcessEventHandler(wxProcessTerminationEventHandler::OnTerminate));
48 wxHandleProcessTermination(m_data);
49 delete this;
50 }
51
52 wxEndProcessData* m_data;
53};
54
55class wxProcessTerminationThread: public wxThread
56{
57 public:
58 wxProcessTerminationThread(wxEndProcessData* data, wxProcessTerminationEventHandler* handler): wxThread(wxTHREAD_DETACHED)
59 {
60 m_data = data;
61 m_handler = handler;
62 }
63
64 virtual void* Entry();
65
66 wxProcessTerminationEventHandler* m_handler;
67 wxEndProcessData* m_data;
68};
69
70// The problem with this is that we may be examining the
71// process e.g. in OnIdle at the point this cleans up the process,
72// so we need to delay until it's safe.
73
74void* wxProcessTerminationThread::Entry()
75{
76 while (true)
77 {
78 usleep(100);
79 int status = 0;
80 int rc = waitpid(abs(m_data->pid), & status, WNOHANG);
81 if (rc != 0)
82 {
83 if ((rc != -1) && WIFEXITED(status))
84 m_data->exitcode = WEXITSTATUS(status);
85 else
86 m_data->exitcode = -1;
87
88 wxProcessEvent event;
89 wxPostEvent(m_handler, event);
90
91 break;
92 }
93 }
94
95 return NULL;
96}
97
98int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
99{
100 if (pid < 1)
101 return -1;
102
103 wxProcessTerminationEventHandler* handler = new wxProcessTerminationEventHandler(proc_data);
104 wxProcessTerminationThread* thread = new wxProcessTerminationThread(proc_data, handler);
105
106 if (thread->Create() != wxTHREAD_NO_ERROR)
107 {
108 wxLogDebug(wxT("Could not create termination detection thread."));
109 delete thread;
110 delete handler;
111 return -1;
112 }
113
114 thread->Run();
115
116 return 0;
117}
118
119#else
62705a27 120
5d553c56
DE
121#include <CoreFoundation/CFMachPort.h>
122#include <sys/wait.h>
123extern "C" {
124#include <mach/mach.h>
125}
126
127void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data)
128{
24498521 129 wxEndProcessData *proc_data = (wxEndProcessData*)data;
3bdb628b 130 wxLogDebug(wxT("Process ended"));
24498521
DE
131 int status = 0;
132 int rc = waitpid(abs(proc_data->pid), &status, WNOHANG);
133 if(!rc)
134 {
135 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
136 return;
137 }
138 if((rc != -1) && WIFEXITED(status))
139 proc_data->exitcode = WEXITSTATUS(status);
140 else
141 proc_data->exitcode = -1;
142 wxHandleProcessTermination(proc_data);
5d553c56
DE
143}
144
145int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid)
146{
147 if(pid < 1)
148 return -1;
149 kern_return_t kernResult;
150 mach_port_t taskOfOurProcess;
151 mach_port_t machPortForProcess;
152 taskOfOurProcess = mach_task_self();
153 if(taskOfOurProcess == MACH_PORT_NULL)
154 {
155 wxLogDebug(wxT("No mach_task_self()"));
156 return -1;
157 }
158 wxLogDebug(wxT("pid=%d"),pid);
159 kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess);
160 if(kernResult != KERN_SUCCESS)
161 {
162 wxLogDebug(wxT("no task_for_pid()"));
163 // try seeing if it is already dead or something
164 // FIXME: a better method would be to call the callback function
165 // from idle time until the process terminates. Of course, how
166 // likely is it that it will take more than 0.1 seconds for the
167 // mach terminate event to make its way to the BSD subsystem?
168 usleep(100); // sleep for 0.1 seconds
169 wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data);
170 return -1;
171 }
172 CFMachPortContext termcb_contextinfo;
b409fa19 173 termcb_contextinfo.version = 0;
5d553c56
DE
174 termcb_contextinfo.info = (void*)proc_data;
175 termcb_contextinfo.retain = NULL;
176 termcb_contextinfo.release = NULL;
177 termcb_contextinfo.copyDescription = NULL;
178 CFMachPortRef CFMachPortForProcess;
179 Boolean ShouldFreePort;
180 CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort);
181 if(!CFMachPortForProcess)
182 {
183 wxLogDebug(wxT("No CFMachPortForProcess"));
184 mach_port_deallocate(taskOfOurProcess, machPortForProcess);
185 return -1;
186 }
187 if(ShouldFreePort)
188 {
189 kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess);
190 if(kernResult!=KERN_SUCCESS)
191 {
192 wxLogDebug(wxT("Couldn't deallocate mach port"));
193 return -1;
194 }
195 }
196 CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect);
197 CFRunLoopSourceRef runloopsource;
198 runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0);
199 if(!runloopsource)
200 {
201 wxLogDebug(wxT("Couldn't create runloopsource"));
202 return -1;
203 }
204
205 CFRelease(CFMachPortForProcess);
206
207 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode);
208 CFRelease(runloopsource);
209 wxLogDebug(wxT("Successfully added notification to the runloop"));
210 return 0;
211}
212
110ffa16
JS
213#endif
214 // USE_POLLING
215
fc480dc1
DE
216// NOTE: This doens't really belong here but this was a handy file to
217// put it in because it's already compiled for wxCocoa and wxMac GUI lib.
218static wxStandardPathsCF gs_stdPaths;
219wxStandardPathsBase& wxGUIAppTraits::GetStandardPaths()
220{
221 return gs_stdPaths;
222}
223