| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: utilsexec.cpp |
| 3 | // Purpose: Execution-related utilities |
| 4 | // Author: Stefan Csomor |
| 5 | // Modified by: David Elliott |
| 6 | // Created: 1998-01-01 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) Stefan Csomor |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | #ifdef __GNUG__ |
| 13 | #pragma implementation |
| 14 | #endif |
| 15 | |
| 16 | #include "wx/log.h" |
| 17 | #include "wx/utils.h" |
| 18 | #ifdef __DARWIN__ |
| 19 | #include "wx/unix/execute.h" |
| 20 | #include <unistd.h> |
| 21 | #include <sys/wait.h> |
| 22 | #include <mach/mach.h> |
| 23 | #include <CoreFoundation/CFMachPort.h> |
| 24 | #endif |
| 25 | |
| 26 | #include <stdio.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <string.h> |
| 29 | |
| 30 | #ifndef __DARWIN__ |
| 31 | #define wxEXECUTE_WIN_MESSAGE 10000 |
| 32 | |
| 33 | long wxExecute(const wxString& command, int flags, wxProcess *handler) |
| 34 | { |
| 35 | // TODO |
| 36 | wxFAIL_MSG( _T("wxExecute() not yet implemented") ); |
| 37 | return 0; |
| 38 | } |
| 39 | #endif |
| 40 | |
| 41 | #ifdef __DARWIN__ |
| 42 | void wxMAC_MachPortEndProcessDetect(CFMachPortRef port, void *data) |
| 43 | { |
| 44 | wxEndProcessData *proc_data = (wxEndProcessData*)data; |
| 45 | wxLogDebug("Wow.. this actually worked!"); |
| 46 | int status = 0; |
| 47 | int rc = waitpid(abs(proc_data->pid), &status, WNOHANG); |
| 48 | if(!rc) |
| 49 | { |
| 50 | wxLogDebug("Mach port was invalidated, but process hasn't terminated!"); |
| 51 | return; |
| 52 | } |
| 53 | if((rc != -1) && WIFEXITED(status)) |
| 54 | proc_data->exitcode = WEXITSTATUS(status); |
| 55 | else |
| 56 | proc_data->exitcode = -1; |
| 57 | wxHandleProcessTermination(proc_data); |
| 58 | } |
| 59 | |
| 60 | int wxAddProcessCallbackForPid(wxEndProcessData *proc_data, int pid) |
| 61 | { |
| 62 | if(pid < 1) |
| 63 | return -1; |
| 64 | kern_return_t kernResult; |
| 65 | mach_port_t taskOfOurProcess; |
| 66 | mach_port_t machPortForProcess; |
| 67 | taskOfOurProcess = mach_task_self(); |
| 68 | if(taskOfOurProcess == MACH_PORT_NULL) |
| 69 | { |
| 70 | wxLogDebug("No mach_task_self()"); |
| 71 | return -1; |
| 72 | } |
| 73 | wxLogDebug("pid=%d",pid); |
| 74 | kernResult = task_for_pid(taskOfOurProcess,pid, &machPortForProcess); |
| 75 | if(kernResult != KERN_SUCCESS) |
| 76 | { |
| 77 | wxLogDebug("no task_for_pid()"); |
| 78 | // try seeing if it is already dead or something |
| 79 | // FIXME: a better method would be to call the callback function |
| 80 | // from idle time until the process terminates. Of course, how |
| 81 | // likely is it that it will take more than 0.1 seconds for the |
| 82 | // mach terminate event to make its way to the BSD subsystem? |
| 83 | usleep(100); // sleep for 0.1 seconds |
| 84 | wxMAC_MachPortEndProcessDetect(NULL, (void*)proc_data); |
| 85 | return -1; |
| 86 | } |
| 87 | CFMachPortContext termcb_contextinfo; |
| 88 | termcb_contextinfo.version = NULL; |
| 89 | termcb_contextinfo.info = (void*)proc_data; |
| 90 | termcb_contextinfo.retain = NULL; |
| 91 | termcb_contextinfo.release = NULL; |
| 92 | termcb_contextinfo.copyDescription = NULL; |
| 93 | CFMachPortRef CFMachPortForProcess; |
| 94 | Boolean ShouldFreePort; |
| 95 | CFMachPortForProcess = CFMachPortCreateWithPort(NULL, machPortForProcess, NULL, &termcb_contextinfo, &ShouldFreePort); |
| 96 | if(!CFMachPortForProcess) |
| 97 | { |
| 98 | wxLogDebug("No CFMachPortForProcess"); |
| 99 | mach_port_deallocate(taskOfOurProcess, machPortForProcess); |
| 100 | return -1; |
| 101 | } |
| 102 | if(ShouldFreePort) |
| 103 | { |
| 104 | kernResult = mach_port_deallocate(taskOfOurProcess, machPortForProcess); |
| 105 | if(kernResult!=KERN_SUCCESS) |
| 106 | { |
| 107 | wxLogDebug("Couldn't deallocate mach port"); |
| 108 | return -1; |
| 109 | } |
| 110 | } |
| 111 | CFMachPortSetInvalidationCallBack(CFMachPortForProcess, &wxMAC_MachPortEndProcessDetect); |
| 112 | CFRunLoopSourceRef runloopsource; |
| 113 | runloopsource = CFMachPortCreateRunLoopSource(NULL,CFMachPortForProcess, (CFIndex)0); |
| 114 | if(!runloopsource) |
| 115 | { |
| 116 | wxLogDebug("Couldn't create runloopsource"); |
| 117 | return -1; |
| 118 | } |
| 119 | |
| 120 | CFRelease(CFMachPortForProcess); |
| 121 | |
| 122 | CFRunLoopAddSource(CFRunLoopGetCurrent(),runloopsource,kCFRunLoopDefaultMode); |
| 123 | CFRelease(runloopsource); |
| 124 | wxLogDebug("Successfully added notification to the runloop"); |
| 125 | return 0; |
| 126 | } |
| 127 | #endif |