1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Execution-related utilities
4 // Author: Stefan Csomor
5 // Modified by: David Elliott
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 //#pragma implementation
19 #include "wx/unix/execute.h"
23 #include <mach/mach.h>
25 #include <CoreFoundation/CFMachPort.h>
34 #include "wx/mac/private.h"
35 #include "LaunchServices.h"
37 long wxExecute(const wxString
& command
, int flags
, wxProcess
*WXUNUSED(handler
))
39 wxASSERT_MSG( flags
== wxEXEC_ASYNC
,
40 wxT("wxExecute: Only wxEXEC_ASYNC is supported") );
44 err
= wxMacPathToFSRef( command
, &fsRef
) ;
47 err
= LSOpenFSRef( &fsRef
, NULL
) ;
50 // 0 means execution failed. Returning non-zero is a PID, but not
51 // on Mac where PIDs are 64 bits and won't fit in a long, so we
52 // return a dummy value for now.
53 return ( err
== noErr
) ? -1 : 0;
59 void wxMAC_MachPortEndProcessDetect(CFMachPortRef port
, void *data
)
61 wxEndProcessData
*proc_data
= (wxEndProcessData
*)data
;
62 wxLogDebug(wxT("Wow.. this actually worked!"));
64 int rc
= waitpid(abs(proc_data
->pid
), &status
, WNOHANG
);
67 wxLogDebug(wxT("Mach port was invalidated, but process hasn't terminated!"));
70 if((rc
!= -1) && WIFEXITED(status
))
71 proc_data
->exitcode
= WEXITSTATUS(status
);
73 proc_data
->exitcode
= -1;
74 wxHandleProcessTermination(proc_data
);
77 int wxAddProcessCallbackForPid(wxEndProcessData
*proc_data
, int pid
)
81 kern_return_t kernResult
;
82 mach_port_t taskOfOurProcess
;
83 mach_port_t machPortForProcess
;
84 taskOfOurProcess
= mach_task_self();
85 if(taskOfOurProcess
== MACH_PORT_NULL
)
87 wxLogDebug(wxT("No mach_task_self()"));
90 wxLogDebug(wxT("pid=%d"),pid
);
91 kernResult
= task_for_pid(taskOfOurProcess
,pid
, &machPortForProcess
);
92 if(kernResult
!= KERN_SUCCESS
)
94 wxLogDebug(wxT("no task_for_pid()"));
95 // try seeing if it is already dead or something
96 // FIXME: a better method would be to call the callback function
97 // from idle time until the process terminates. Of course, how
98 // likely is it that it will take more than 0.1 seconds for the
99 // mach terminate event to make its way to the BSD subsystem?
100 usleep(100); // sleep for 0.1 seconds
101 wxMAC_MachPortEndProcessDetect(NULL
, (void*)proc_data
);
104 CFMachPortContext termcb_contextinfo
;
105 termcb_contextinfo
.version
= NULL
;
106 termcb_contextinfo
.info
= (void*)proc_data
;
107 termcb_contextinfo
.retain
= NULL
;
108 termcb_contextinfo
.release
= NULL
;
109 termcb_contextinfo
.copyDescription
= NULL
;
110 CFMachPortRef CFMachPortForProcess
;
111 Boolean ShouldFreePort
;
112 CFMachPortForProcess
= CFMachPortCreateWithPort(NULL
, machPortForProcess
, NULL
, &termcb_contextinfo
, &ShouldFreePort
);
113 if(!CFMachPortForProcess
)
115 wxLogDebug(wxT("No CFMachPortForProcess"));
116 mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
121 kernResult
= mach_port_deallocate(taskOfOurProcess
, machPortForProcess
);
122 if(kernResult
!=KERN_SUCCESS
)
124 wxLogDebug(wxT("Couldn't deallocate mach port"));
128 CFMachPortSetInvalidationCallBack(CFMachPortForProcess
, &wxMAC_MachPortEndProcessDetect
);
129 CFRunLoopSourceRef runloopsource
;
130 runloopsource
= CFMachPortCreateRunLoopSource(NULL
,CFMachPortForProcess
, (CFIndex
)0);
133 wxLogDebug(wxT("Couldn't create runloopsource"));
137 CFRelease(CFMachPortForProcess
);
139 CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource
,kCFRunLoopDefaultMode
);
140 CFRelease(runloopsource
);
141 wxLogDebug(wxT("Successfully added notification to the runloop"));