this repo has no description
at fixPythonPipStalling 752 lines 21 kB view raw
1/* 2 * Copyright (c) 2000-2005, 2008-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 "SCD.h" 37 38#if !TARGET_OS_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090)) 39#define HAVE_MACHPORT_GUARDS 40#endif 41 42 43static void 44removeReceiveRight(SCDynamicStoreRef store, mach_port_t port) 45{ 46 /* remove our receive right */ 47#ifdef HAVE_MACHPORT_GUARDS 48 (void) mach_port_destruct(mach_task_self(), port, 0, (mach_port_context_t)store); 49#else // HAVE_MACHPORT_GUARDS 50 (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); 51#endif // HAVE_MACHPORT_GUARDS 52 return; 53} 54 55 56#define MAX_INVALID_RIGHT_RETRY 3 57 58static mach_port_t 59addNotifyPort(SCDynamicStoreRef store) 60{ 61 kern_return_t kr; 62 mach_port_t oldNotify; 63#ifdef HAVE_MACHPORT_GUARDS 64 mach_port_options_t opts; 65#endif // HAVE_MACHPORT_GUARDS 66 mach_port_t port; 67 int sc_status; 68 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 69 int try = 0; 70 71 /* allocate a mach port for the SCDynamicStore notifications */ 72 73 retry_allocate : 74 75#ifdef HAVE_MACHPORT_GUARDS 76 memset(&opts, 0, sizeof(opts)); 77 opts.flags = MPO_CONTEXT_AS_GUARD|MPO_INSERT_SEND_RIGHT; 78 79 kr = mach_port_construct(mach_task_self(), &opts, (mach_port_context_t)store, &port); 80#else // HAVE_MACHPORT_GUARDS 81 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); 82#endif // HAVE_MACHPORT_GUARDS 83 84 if (kr != KERN_SUCCESS) { 85 SC_log(LOG_NOTICE, "could not allocate mach port: %s", mach_error_string(kr)); 86 if ((kr == KERN_NO_SPACE) || (kr == KERN_RESOURCE_SHORTAGE)) { 87 usleep(50 * 1000); // sleep 50ms between attempts 88 goto retry_allocate; 89 } 90 goto fail; 91 } 92 93#ifndef HAVE_MACHPORT_GUARDS 94 kr = mach_port_insert_right(mach_task_self(), 95 port, 96 port, 97 MACH_MSG_TYPE_MAKE_SEND); 98 if (kr != KERN_SUCCESS) { 99 /* 100 * We can't insert a send right into our own port! This should 101 * only happen if someone stomped on OUR port (so let's leave 102 * the port alone). 103 */ 104 SC_log(LOG_NOTICE, "mach_port_insert_right() failed: %s", mach_error_string(kr)); 105 goto fail; 106 } 107#endif // HAVE_MACHPORT_GUARDS 108 109 /* Request a notification when/if the server dies */ 110 kr = mach_port_request_notification(mach_task_self(), 111 port, 112 MACH_NOTIFY_NO_SENDERS, 113 1, 114 port, 115 MACH_MSG_TYPE_MAKE_SEND_ONCE, 116 &oldNotify); 117 if (kr != KERN_SUCCESS) { 118 /* 119 * We can't request a notification for our own port! This should 120 * only happen if someone stomped on OUR port (so let's leave 121 * the port alone). 122 */ 123 SC_log(LOG_NOTICE, "mach_port_request_notification() failed: %s", mach_error_string(kr)); 124 goto fail; 125 } 126 127 if (oldNotify != MACH_PORT_NULL) { 128 SC_log(LOG_NOTICE, "oldNotify != MACH_PORT_NULL"); 129 } 130 131#ifdef DEBUG 132 SC_log(LOG_DEBUG, "+ establish notification request w/port=0x%x (%d) with SCDynamicStore server (%@)", 133 port, port, 134 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 135#endif /* DEBUG */ 136 137 retry : 138 139 __MACH_PORT_DEBUG(TRUE, "*** addNotifyPort", port); 140 kr = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status); 141 142 if (kr == MACH_SEND_INVALID_RIGHT) { 143 /* 144 * the notifyviaport() call was not able to pass/process 145 * the [notify port] send right. This was most likely due 146 * to the [SCDynamicStore] server having restarted. We 147 * handle this issue by removing the remaining receive 148 * right, reallocating the notify port, and retrying 149 * the operation. 150 */ 151 SC_log((try++ < MAX_INVALID_RIGHT_RETRY) ? LOG_INFO : LOG_ERR, 152 "SCDynamicStore callback notifyviaport() w/port 0x%x (%d) failed (try %d): %s", 153 port, port, 154 try, 155 mach_error_string(kr)); 156 157 removeReceiveRight(store, port); 158 } 159 160 if (__SCDynamicStoreCheckRetryAndHandleError(store, 161 kr, 162 &sc_status, 163 "SCDynamicStore callback notifyviaport()")) { 164 if (kr == MACH_SEND_INVALID_RIGHT) { 165 if (try <= MAX_INVALID_RIGHT_RETRY) { 166 goto retry_allocate; 167 } 168 goto fail; 169 } 170 goto retry; 171 } 172 173 if (try > 0) { 174 SC_log(LOG_INFO, 175 "SCDynamicStore callback notifyviaport() succeeded after %d retr%s w/port 0x%x (%d)", 176 try, 177 (try == 1) ? "y" : "ies", 178 port, port); 179 } 180 181 if (kr != KERN_SUCCESS) { 182 if ((kr == MACH_SEND_INVALID_DEST) || (kr == MIG_SERVER_DIED)) { 183 /* remove the send right that we tried (but failed) to pass to the server */ 184 (void) mach_port_deallocate(mach_task_self(), port); 185 } 186 removeReceiveRight(store, port); 187 goto fail; 188 } 189 190 if (sc_status != kSCStatusOK) { 191 /* something [else] didn't work */ 192 removeReceiveRight(store, port); 193 kr = sc_status; 194 goto fail; 195 } 196 197 return port; 198 199 fail : 200 201 _SCErrorSet(kr); 202 return MACH_PORT_NULL; 203} 204 205 206static CFStringRef 207notifyMPCopyDescription(const void *info) 208{ 209 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 210 211 return CFStringCreateWithFormat(NULL, 212 NULL, 213 CFSTR("<SCDynamicStore notification MP> {store = %p}"), 214 store); 215} 216 217 218static void 219rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) 220{ 221#ifndef DEBUG 222#pragma unused(port) 223#endif /* DEBUG */ 224#pragma unused(size) 225 mach_no_senders_notification_t *buf = msg; 226 mach_msg_id_t msgid = buf->not_header.msgh_id; 227 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 228 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 229 230#ifdef DEBUG 231 SC_log(LOG_DEBUG, "mach port callback, %ssignal RLS(%@)", 232 (msgid == MACH_NOTIFY_NO_SENDERS) ? "reconnect and " : "", 233 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 234#endif /* DEBUG */ 235 236 if (msgid == MACH_NOTIFY_NO_SENDERS) { 237 /* the server died, disable additional callbacks */ 238#ifdef DEBUG 239 SC_log(LOG_DEBUG, " notifier port closed"); 240#endif /* DEBUG */ 241 242#ifdef DEBUG 243 if (port != storePrivate->rlsNotifyPort) { 244 SC_log(LOG_DEBUG, "why is port != rlsNotifyPort?"); 245 } 246#endif /* DEBUG */ 247 248 /* re-establish notification and inform the client */ 249 (void)__SCDynamicStoreReconnectNotifications(store); 250 } 251 252 /* signal the real runloop source */ 253 if (storePrivate->rls != NULL) { 254 CFRunLoopSourceSignal(storePrivate->rls); 255 } 256 257 return; 258} 259 260 261static void 262rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) 263{ 264 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 265 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 266 267#ifdef DEBUG 268 SC_log(LOG_DEBUG, "schedule notifications for mode %@", mode); 269#endif /* DEBUG */ 270 271 if (storePrivate->rlsNotifyPort == NULL) { 272 CFMachPortContext context = { 0 273 , (void *)store 274 , CFRetain 275 , CFRelease 276 , notifyMPCopyDescription 277 }; 278 mach_port_t port; 279 280#ifdef DEBUG 281 SC_log(LOG_DEBUG, " activate callback runloop source"); 282#endif /* DEBUG */ 283 284 port = addNotifyPort(store); 285 if (port == MACH_PORT_NULL) { 286 return; 287 } 288 289 __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after addNotifyPort)", port); 290 storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", 291 port, 292 rlsCallback, 293 &context); 294 295 if (rl != NULL) { 296 storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0); 297 storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 298 } 299 } 300 301 if (storePrivate->rlsNotifyRLS != NULL) { 302 /* set notifier active */ 303 storePrivate->notifyStatus = Using_NotifierInformViaRunLoop; 304 305 if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { 306 /* 307 * if we are not already scheduled with this runLoop / runLoopMode 308 */ 309 CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); 310 __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); 311 } 312 313 _SC_schedule(store, rl, mode, storePrivate->rlList); 314 } 315 316 return; 317} 318 319 320static void 321rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) 322{ 323 CFIndex n = 0; 324 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 325 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 326 327#ifdef DEBUG 328 SC_log(LOG_DEBUG, "cancel notifications for mode %@", mode); 329#endif /* DEBUG */ 330 331 if (storePrivate->rlsNotifyRLS != NULL) { 332 if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { 333 /* 334 * if currently scheduled on this runLoop / runLoopMode 335 */ 336 n = CFArrayGetCount(storePrivate->rlList); 337 if (n == 0 || !_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { 338 /* 339 * if we are no longer scheduled to receive notifications for 340 * this runLoop / runLoopMode 341 */ 342 CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); 343 } 344 } 345 } 346 347 if (n == 0) { 348 int sc_status; 349 kern_return_t kr; 350 351#ifdef DEBUG 352 SC_log(LOG_DEBUG, " cancel callback runloop source"); 353#endif /* DEBUG */ 354 __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), 355 "*** rlsCancel", 356 CFMachPortGetPort(storePrivate->rlsNotifyPort)); 357 358 if (storePrivate->rls != NULL) { 359 // Remove the reference we took on the rls. We do not invalidate 360 // the runloop source and let the client do it when appropriate. 361 CFRelease(storePrivate->rls); 362 storePrivate->rls = NULL; 363 } 364 365 if (storePrivate->rlList != NULL) { 366 CFRelease(storePrivate->rlList); 367 storePrivate->rlList = NULL; 368 } 369 370 if (storePrivate->rlsNotifyRLS != NULL) { 371 /* invalidate & remove the run loop source */ 372 CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); 373 CFRelease(storePrivate->rlsNotifyRLS); 374 storePrivate->rlsNotifyRLS = NULL; 375 } 376 377 if (storePrivate->rlsNotifyPort != NULL) { 378 mach_port_t mp; 379 380 mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); 381 __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), 382 "*** rlsCancel (before invalidating/releasing CFMachPort)", 383 mp); 384 385 /* invalidate and release port */ 386 CFMachPortInvalidate(storePrivate->rlsNotifyPort); 387 CFRelease(storePrivate->rlsNotifyPort); 388 storePrivate->rlsNotifyPort = NULL; 389 390 /* and, finally, remove our receive right */ 391 removeReceiveRight(store, mp); 392 } 393 394#ifdef DEBUG 395 SC_log(LOG_DEBUG, " cancel notification request with SCDynamicStore server"); 396#endif /* DEBUG */ 397 398 if (storePrivate->server != MACH_PORT_NULL) { 399 kr = notifycancel(storePrivate->server, (int *)&sc_status); 400 401 (void) __SCDynamicStoreCheckRetryAndHandleError(store, 402 kr, 403 &sc_status, 404 "rlsCancel notifycancel()"); 405 406 if (kr != KERN_SUCCESS) { 407 return; 408 } 409 } 410 411 /* set notifier inactive */ 412 storePrivate->notifyStatus = NotifierNotRegistered; 413 } 414 415 return; 416} 417 418 419static void 420rlsPerform(void *info) 421{ 422 CFArrayRef changedKeys = NULL; 423 void *context_info; 424 void (*context_release)(const void *); 425 SCDynamicStoreCallBack rlsFunction; 426 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 427 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 428 429#ifdef DEBUG 430 SC_log(LOG_DEBUG, "handling SCDynamicStore changes (%@)", 431 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 432#endif /* DEBUG */ 433 434 changedKeys = SCDynamicStoreCopyNotifiedKeys(store); 435 if (storePrivate->disconnectForceCallBack) { 436 storePrivate->disconnectForceCallBack = FALSE; 437 if (changedKeys == NULL) { 438 changedKeys = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); 439 } 440 } else if ((changedKeys == NULL) || (CFArrayGetCount(changedKeys) == 0)) { 441 /* if no changes or something happened to the server */ 442 goto done; 443 } 444 445 rlsFunction = storePrivate->rlsFunction; 446 447 if (storePrivate->rlsContext.retain != NULL) { 448 context_info = (void *)storePrivate->rlsContext.retain(storePrivate->rlsContext.info); 449 context_release = storePrivate->rlsContext.release; 450 } else { 451 context_info = storePrivate->rlsContext.info; 452 context_release = NULL; 453 } 454 if (rlsFunction != NULL) { 455 SC_log(LOG_DEBUG, "+ exec SCDynamicStore callout"); 456 (*rlsFunction)(store, changedKeys, context_info); 457 SC_log(LOG_DEBUG, "+ done"); 458 } 459 if (context_release != NULL) { 460 context_release(context_info); 461 } 462 463 done : 464 465#ifdef DEBUG 466 SC_log(LOG_DEBUG, "done"); 467#endif /* DEBUG */ 468 469 if (changedKeys != NULL) { 470 CFRelease(changedKeys); 471 } 472 473 return; 474} 475 476 477static CFStringRef 478rlsCopyDescription(const void *info) 479{ 480 CFMutableStringRef result; 481 SCDynamicStoreRef store = (SCDynamicStoreRef)info; 482 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 483 484 result = CFStringCreateMutable(NULL, 0); 485 CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore RLS> {")); 486 CFStringAppendFormat(result, NULL, CFSTR("store = %p"), store); 487 if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) { 488 CFStringRef description = NULL; 489 490 CFStringAppendFormat(result, NULL, CFSTR(", callout = %p"), storePrivate->rlsFunction); 491 492 if ((storePrivate->rlsContext.info != NULL) && (storePrivate->rlsContext.copyDescription != NULL)) { 493 description = (*storePrivate->rlsContext.copyDescription)(storePrivate->rlsContext.info); 494 } 495 if (description == NULL) { 496 description = CFStringCreateWithFormat(NULL, NULL, CFSTR("<SCDynamicStore context %p>"), storePrivate->rlsContext.info); 497 } 498 if (description == NULL) { 499 description = CFRetain(CFSTR("<no description>")); 500 } 501 CFStringAppendFormat(result, NULL, CFSTR(", context = %@"), description); 502 CFRelease(description); 503 } 504 CFStringAppendFormat(result, NULL, CFSTR("}")); 505 506 return result; 507} 508 509 510CFRunLoopSourceRef 511SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator, 512 SCDynamicStoreRef store, 513 CFIndex order) 514{ 515 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 516 517 if (store == NULL) { 518 /* sorry, you must provide a session */ 519 _SCErrorSet(kSCStatusNoStoreSession); 520 return NULL; 521 } 522 523 if (storePrivate->server == MACH_PORT_NULL) { 524 /* sorry, you must have an open session to play */ 525 _SCErrorSet(kSCStatusNoStoreServer); 526 return NULL; 527 } 528 529 switch (storePrivate->notifyStatus) { 530 case NotifierNotRegistered : 531 case Using_NotifierInformViaRunLoop : 532 /* OK to enable runloop notification */ 533 break; 534 default : 535 /* sorry, you can only have one notification registered at once */ 536 _SCErrorSet(kSCStatusNotifierActive); 537 return NULL; 538 } 539 540 if (storePrivate->rls == NULL) { 541 CFRunLoopSourceContext context = { 0 // version 542 , (void *)store // info 543 , CFRetain // retain 544 , CFRelease // release 545 , rlsCopyDescription // copyDescription 546 , CFEqual // equal 547 , CFHash // hash 548 , rlsSchedule // schedule 549 , rlsCancel // cancel 550 , rlsPerform // perform 551 }; 552 553 storePrivate->rls = CFRunLoopSourceCreate(allocator, order, &context); 554 if (storePrivate->rls == NULL) { 555 _SCErrorSet(kSCStatusFailed); 556 } 557 } 558 559 if (storePrivate->rls != NULL) { 560 CFRetain(storePrivate->rls); 561 } 562 563 return storePrivate->rls; 564} 565 566 567Boolean 568SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) 569{ 570 dispatch_group_t drainGroup = NULL; 571 dispatch_queue_t drainQueue = NULL; 572 dispatch_group_t group = NULL; 573 mach_port_t mp; 574 Boolean ok = FALSE; 575 dispatch_source_t source; 576 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 577 578 if (store == NULL) { 579 // sorry, you must provide a session 580 _SCErrorSet(kSCStatusNoStoreSession); 581 return FALSE; 582 } 583 584 if (queue == NULL) { 585 if (storePrivate->dispatchQueue == NULL) { 586 // if not scheduled 587 _SCErrorSet(kSCStatusInvalidArgument); 588 return FALSE; 589 } 590 591#ifdef DEBUG 592 SC_log(LOG_DEBUG, "unschedule notifications from dispatch queue (%@)", 593 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 594#endif /* DEBUG */ 595 596 ok = TRUE; 597 goto cleanup; 598 } 599 600 if (storePrivate->server == MACH_PORT_NULL) { 601 // sorry, you must have an open session to play 602 _SCErrorSet(kSCStatusNoStoreServer); 603 return FALSE; 604 } 605 606 if ((storePrivate->dispatchQueue != NULL) || 607 (storePrivate->rls != NULL) || 608 (storePrivate->notifyStatus != NotifierNotRegistered)) { 609 // if already scheduled 610 _SCErrorSet(kSCStatusNotifierActive); 611 return FALSE; 612 } 613 614#ifdef DEBUG 615 SC_log(LOG_DEBUG, "schedule notifications for dispatch queue (%@)", 616 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 617#endif /* DEBUG */ 618 619 // 620 // mark our using of the SCDynamicStore notifications, create and schedule 621 // the notification source/port (storePrivate->dispatchSource), and a bunch 622 // of other "setup" 623 // 624 storePrivate->notifyStatus = Using_NotifierInformViaDispatch; 625 626 mp = addNotifyPort(store); 627 if (mp == MACH_PORT_NULL) { 628 // if we could not schedule the notification 629 _SCErrorSet(kSCStatusFailed); 630#ifdef DEBUG 631 SC_log(LOG_DEBUG, "addNotifyPort() failed (%@)", 632 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 633#endif /* DEBUG */ 634 goto cleanup; 635 } 636 637 // retain the dispatch queue 638 storePrivate->dispatchQueue = queue; 639 dispatch_retain(storePrivate->dispatchQueue); 640 641 // 642 // We've taken a reference to the callers dispatch_queue and we 643 // want to hold on to that reference until we've processed any/all 644 // notifications. To facilitate this we create a group, dispatch 645 // any notification blocks to via that group, and when the caller 646 // has told us to stop the notifications (unschedule) we wait for 647 // the group to empty and use the group's finalizer to release 648 // our reference to the SCDynamicStore. 649 // 650 group = dispatch_group_create(); 651 storePrivate->dispatchGroup = group; 652 CFRetain(store); 653 dispatch_set_context(storePrivate->dispatchGroup, (void *)store); 654 dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); 655 656 // create a dispatch source for the mach notifications 657 source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); 658 if (source == NULL) { 659 SC_log(LOG_NOTICE, "dispatch_source_create() failed"); 660 661 // remove our receive right 662 removeReceiveRight(store, mp); 663 664 _SCErrorSet(kSCStatusFailed); 665 goto cleanup; 666 } 667 668 dispatch_source_set_event_handler(source, ^{ 669 kern_return_t kr; 670 mach_msg_id_t msgid; 671 union { 672 u_int8_t buf1[sizeof(mach_msg_empty_rcv_t) + MAX_TRAILER_SIZE]; 673 u_int8_t buf2[sizeof(mach_no_senders_notification_t) + MAX_TRAILER_SIZE]; 674 mach_msg_empty_rcv_t msg; 675 mach_no_senders_notification_t no_senders; 676 } notify_msg; 677 678 kr = mach_msg(&notify_msg.msg.header, // msg 679 MACH_RCV_MSG, // options 680 0, // send_size 681 sizeof(notify_msg), // rcv_size 682 mp, // rcv_name 683 MACH_MSG_TIMEOUT_NONE, // timeout 684 MACH_PORT_NULL); // notify 685 if (kr != KERN_SUCCESS) { 686 SC_log(LOG_NOTICE, "mach_msg() failed, kr=0x%x", kr); 687 return; 688 } 689 690 msgid = notify_msg.msg.header.msgh_id; 691 mach_msg_destroy(&notify_msg.msg.header); 692 693#ifdef DEBUG 694 SC_log(LOG_DEBUG, "dispatch source callback, queue rlsPerform (%@)", 695 (storePrivate->name != NULL) ? storePrivate->name : CFSTR("?")); 696#endif /* DEBUG */ 697 698 CFRetain(store); 699 dispatch_group_async(group, queue, ^{ 700 if (msgid == MACH_NOTIFY_NO_SENDERS) { 701 // re-establish notification and inform the client 702 (void)__SCDynamicStoreReconnectNotifications(store); 703 } 704 rlsPerform(storePrivate); 705 CFRelease(store); 706 }); 707 }); 708 709 dispatch_source_set_cancel_handler(source, ^{ 710 __MACH_PORT_DEBUG(TRUE, 711 "*** SCDynamicStoreSetDispatchQueue (before cancel)", 712 mp); 713 714 // remove our receive right 715 removeReceiveRight(store, mp); 716 717 // release source 718 dispatch_release(source); 719 }); 720 721 storePrivate->dispatchSource = source; 722 dispatch_resume(source); 723 724 return TRUE; 725 726 cleanup : 727 728 CFRetain(store); 729 730 if (storePrivate->dispatchSource != NULL) { 731 dispatch_source_cancel(storePrivate->dispatchSource); 732 storePrivate->dispatchSource = NULL; 733 } 734 drainGroup = storePrivate->dispatchGroup; 735 storePrivate->dispatchGroup = NULL; 736 drainQueue = storePrivate->dispatchQueue; 737 storePrivate->dispatchQueue = NULL; 738 739 if ((drainGroup != NULL) && (drainQueue != NULL)) { 740 dispatch_group_notify(drainGroup, drainQueue, ^{ 741 // release group/queue references 742 dispatch_release(drainQueue); 743 dispatch_release(drainGroup); // releases our store reference 744 }); 745 } 746 747 storePrivate->notifyStatus = NotifierNotRegistered; 748 749 CFRelease(store); 750 751 return ok; 752}