this repo has no description
at fixPythonPipStalling 214 lines 6.1 kB view raw
1/* 2 * Copyright (c) 2000, 2001, 2004, 2006, 2009-2011, 2015-2017, 2019 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * June 1, 2001 Allan Nathanson <ajn@apple.com> 28 * - public API conversion 29 * 30 * March 31, 2000 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34#include "SCDynamicStoreInternal.h" 35#include "config.h" /* MiG generated file */ 36#include <mach/mach_error.h> 37 38 39static mach_msg_id_t 40waitForMachMessage(mach_port_t port) 41{ 42 union { 43 u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; 44 mach_msg_empty_rcv_t msg; 45 } notify_msg; 46 kern_return_t status; 47 48 status = mach_msg(&notify_msg.msg.header, /* msg */ 49 MACH_RCV_MSG, /* options */ 50 0, /* send_size */ 51 sizeof(notify_msg), /* rcv_size */ 52 port, /* rcv_name */ 53 MACH_MSG_TIMEOUT_NONE, /* timeout */ 54 MACH_PORT_NULL); /* notify */ 55 if (status != KERN_SUCCESS) { 56 SC_log(LOG_NOTICE, "mach_msg() failed: %s", mach_error_string(status)); 57 return -1; 58 } 59 60 return notify_msg.msg.header.msgh_id; 61} 62 63 64Boolean 65SCDynamicStoreNotifyWait(SCDynamicStoreRef store) 66{ 67 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 68 kern_return_t status; 69 mach_port_t port; 70 mach_port_t oldNotify; 71 int sc_status; 72 mach_msg_id_t msgid; 73 74 if (store == NULL) { 75 /* sorry, you must provide a session */ 76 _SCErrorSet(kSCStatusNoStoreSession); 77 return FALSE; 78 } 79 80 if (storePrivate->server == MACH_PORT_NULL) { 81 /* sorry, you must have an open session to play */ 82 _SCErrorSet(kSCStatusNoStoreServer); 83 return FALSE; 84 } 85 86 if (storePrivate->notifyStatus != NotifierNotRegistered) { 87 /* sorry, you can only have one notification registered at once */ 88 _SCErrorSet(kSCStatusNotifierActive); 89 return FALSE; 90 } 91 92 /* Allocating port (for server response) */ 93 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); 94 if (status != KERN_SUCCESS) { 95 SC_log(LOG_ERR, "mach_port_allocate() failed: %s", mach_error_string(status)); 96 _SCErrorSet(status); 97 return FALSE; 98 } 99 100 status = mach_port_insert_right(mach_task_self(), 101 port, 102 port, 103 MACH_MSG_TYPE_MAKE_SEND); 104 if (status != KERN_SUCCESS) { 105 /* 106 * We can't insert a send right into our own port! This should 107 * only happen if someone stomped on OUR port (so let's leave 108 * the port alone). 109 */ 110 SC_log(LOG_NOTICE, "mach_port_insert_right() failed: %s", mach_error_string(status)); 111 _SCErrorSet(status); 112 return FALSE; 113 } 114 115 /* Request a notification when/if the server dies */ 116 status = mach_port_request_notification(mach_task_self(), 117 port, 118 MACH_NOTIFY_NO_SENDERS, 119 1, 120 port, 121 MACH_MSG_TYPE_MAKE_SEND_ONCE, 122 &oldNotify); 123 if (status != KERN_SUCCESS) { 124 /* 125 * We can't request a notification for our own port! This should 126 * only happen if someone stomped on OUR port (so let's leave 127 * the port alone). 128 */ 129 SC_log(LOG_NOTICE, "mach_port_request_notification() failed: %s", mach_error_string(status)); 130 _SCErrorSet(status); 131 return FALSE; 132 } 133 134 if (oldNotify != MACH_PORT_NULL) { 135 SC_log(LOG_NOTICE, "oldNotify != MACH_PORT_NULL"); 136 } 137 138 retry : 139 140 status = notifyviaport(storePrivate->server, 141 port, 142 0, 143 (int *)&sc_status); 144 145 if (__SCDynamicStoreCheckRetryAndHandleError(store, 146 status, 147 &sc_status, 148 "SCDynamicStoreNotifyWait notifyviaport()")) { 149 goto retry; 150 } 151 152 if (status != KERN_SUCCESS) { 153 if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { 154 /* remove the send right that we tried (but failed) to pass to the server */ 155 (void) mach_port_deallocate(mach_task_self(), port); 156 } 157 158 /* remove our receive right */ 159 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); 160 } 161 162 if (sc_status != kSCStatusOK) { 163 _SCErrorSet(sc_status); 164 return FALSE; 165 } 166 167 /* set notifier active */ 168 storePrivate->notifyStatus = Using_NotifierWait; 169 170 msgid = waitForMachMessage(port); 171 172 /* set notifier inactive */ 173 storePrivate->notifyStatus = NotifierNotRegistered; 174 175 if (msgid == MACH_NOTIFY_NO_SENDERS) { 176 /* the server closed the notifier port */ 177#ifdef DEBUG 178 SC_log(LOG_DEBUG, "notifier port closed, port %d", port); 179#endif /* DEBUG */ 180 _SCErrorSet(kSCStatusNoStoreServer); 181 return FALSE; 182 } 183 184 if (msgid == -1) { 185 /* one of the mach routines returned an error */ 186#ifdef DEBUG 187 SC_log(LOG_DEBUG, "communication with server failed, remove port right %d", port); 188#endif /* DEBUG */ 189 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE , -1); 190 _SCErrorSet(kSCStatusNoStoreServer); 191 return FALSE; 192 } 193 194 // something changed, cancelling notification request 195 status = notifycancel(storePrivate->server, 196 (int *)&sc_status); 197 198 if (__SCDynamicStoreCheckRetryAndHandleError(store, 199 status, 200 &sc_status, 201 "SCDynamicStoreNotifyWait notifycancel()")) { 202 sc_status = kSCStatusOK; 203 } 204 205 /* remove our receive right */ 206 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE , -1); 207 208 if (sc_status != kSCStatusOK) { 209 _SCErrorSet(sc_status); 210 return FALSE; 211 } 212 213 return TRUE; 214}