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