this repo has no description
at fixPythonPipStalling 145 lines 4.6 kB view raw
1/** 2 * IPC.c - System Starter IPC routines 3 * Wilfredo Sanchez | wsanchez@opensource.apple.com 4 * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu 5 * $Apple$ 6 ** 7 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved. 8 * 9 * @APPLE_APACHE_LICENSE_HEADER_START@ 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); 12 * you may not use this file except in compliance with the License. 13 * You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * 23 * @APPLE_APACHE_LICENSE_HEADER_END@ 24 **/ 25 26#include <sys/wait.h> 27#include <mach/mach.h> 28#include <mach/message.h> 29#include <mach/mach_error.h> 30#include <CoreFoundation/CoreFoundation.h> 31#include <syslog.h> 32 33#include "bootstrap.h" 34 35#include "IPC.h" 36#include "StartupItems.h" 37#include "SystemStarter.h" 38#include "SystemStarterIPC.h" 39 40/* Structure to pass StartupContext and anItem to the termination handler. */ 41typedef struct TerminationContextStorage { 42 StartupContext aStartupContext; 43 CFMutableDictionaryRef anItem; 44} *TerminationContext; 45 46/** 47 * A CFMachPort invalidation callback that records the termination of 48 * a startup item task. Stops the current run loop to give system_starter 49 * another go at running items. 50 **/ 51static void 52startupItemTerminated(CFMachPortRef aMachPort, void *anInfo) 53{ 54 TerminationContext aTerminationContext = (TerminationContext) anInfo; 55 56 if (aMachPort) { 57 mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort)); 58 } 59 if (aTerminationContext && aTerminationContext->anItem) { 60 pid_t aPID = 0; 61 pid_t rPID = 0; 62 int aStatus = 0; 63 CFMutableDictionaryRef anItem = aTerminationContext->anItem; 64 StartupContext aStartupContext = aTerminationContext->aStartupContext; 65 66 /* Get the exit status */ 67 if (anItem) { 68 aPID = StartupItemGetPID(anItem); 69 if (aPID > 0) 70 rPID = waitpid(aPID, &aStatus, 0); 71 } 72 if (aStartupContext) { 73 --aStartupContext->aRunningCount; 74 75 /* Record the item's status */ 76 if (aStartupContext->aStatusDict) { 77 StartupItemExit(aStartupContext->aStatusDict, anItem, (WIFEXITED(aStatus) && WEXITSTATUS(aStatus) == 0)); 78 if (aStatus) { 79 CF_syslog(LOG_WARNING, CFSTR("%@ (%d) did not complete successfully"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); 80 } else { 81 CF_syslog(LOG_DEBUG, CFSTR("Finished %@ (%d)"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID); 82 } 83 } 84 /* 85 * If the item failed to start, then add it to the 86 * failed list 87 */ 88 if (WEXITSTATUS(aStatus) || WTERMSIG(aStatus) || WCOREDUMP(aStatus)) { 89 CFDictionarySetValue(anItem, kErrorKey, kErrorReturnNonZero); 90 AddItemToFailedList(aStartupContext, anItem); 91 } 92 /* 93 * Remove the item from the waiting list regardless 94 * if it was successful or it failed. 95 */ 96 RemoveItemFromWaitingList(aStartupContext, anItem); 97 } 98 } 99 if (aTerminationContext) 100 free(aTerminationContext); 101} 102 103void 104MonitorStartupItem(StartupContext aStartupContext, CFMutableDictionaryRef anItem) 105{ 106 pid_t aPID = StartupItemGetPID(anItem); 107 if (anItem && aPID > 0) { 108 mach_port_t aPort; 109 kern_return_t aResult; 110 CFMachPortContext aContext; 111 CFMachPortRef aMachPort; 112 CFRunLoopSourceRef aSource; 113 TerminationContext aTerminationContext = (TerminationContext) malloc(sizeof(struct TerminationContextStorage)); 114 115 aTerminationContext->aStartupContext = aStartupContext; 116 aTerminationContext->anItem = anItem; 117 118 aContext.version = 0; 119 aContext.info = aTerminationContext; 120 aContext.retain = 0; 121 aContext.release = 0; 122 123 if ((aResult = task_name_for_pid(mach_task_self(), aPID, &aPort)) != KERN_SUCCESS) 124 goto out_bad; 125 126 if (!(aMachPort = CFMachPortCreateWithPort(NULL, aPort, NULL, &aContext, NULL))) 127 goto out_bad; 128 129 if (!(aSource = CFMachPortCreateRunLoopSource(NULL, aMachPort, 0))) { 130 CFRelease(aMachPort); 131 goto out_bad; 132 } 133 CFMachPortSetInvalidationCallBack(aMachPort, startupItemTerminated); 134 CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, kCFRunLoopCommonModes); 135 CFRelease(aSource); 136 CFRelease(aMachPort); 137 return; 138out_bad: 139 /* 140 * The assumption is something failed, the task already 141 * terminated. 142 */ 143 startupItemTerminated(NULL, aTerminationContext); 144 } 145}