X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/6bb659645459a5a8b169b9554c8dfc459f435bc2..085a2e6a11110e1303f99ce18f80f98e067cb876:/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c?ds=sidebyside diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c index 166c0ce..02e7d48 100644 --- a/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c +++ b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2008-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -44,72 +44,6 @@ #include "config.h" /* MiG generated file */ -static void -informCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) -{ - SCDynamicStoreRef store = (SCDynamicStoreRef)info; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - mach_no_senders_notification_t *buf = msg; - mach_msg_id_t msgid = buf->not_header.msgh_id; - SCDynamicStoreCallBack_v1 cbFunc = storePrivate->callbackFunction; - void *cbArg = storePrivate->callbackArgument; - - if (msgid == MACH_NOTIFY_NO_SENDERS) { - /* the server died, disable additional callbacks */ -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" notifier port closed, disabling notifier")); -#endif /* DEBUG */ - } else if (cbFunc == NULL) { - /* there is no (longer) a callback function, disable additional callbacks */ -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" no callback function, disabling notifier")); -#endif /* DEBUG */ - } else { -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" executing notification function")); -#endif /* DEBUG */ - if ((*cbFunc)(store, cbArg)) { - /* - * callback function returned success. - */ - return; - } else { -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" callback returned error, disabling notifier")); -#endif /* DEBUG */ - } - } - -#ifdef DEBUG - if (port != storePrivate->callbackPort) { - SCLog(_sc_verbose, LOG_DEBUG, CFSTR("informCallback, why is port != callbackPort?")); - } -#endif /* DEBUG */ - - /* invalidate the run loop source */ - if (storePrivate->callbackRLS != NULL) { - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; - } - - /* invalidate port */ - if (storePrivate->callbackPort != NULL) { - __MACH_PORT_DEBUG(TRUE, "*** informCallback", CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; - } - - /* disable notifier */ - storePrivate->notifyStatus = NotifierNotRegistered; - storePrivate->callbackArgument = NULL; - storePrivate->callbackFunction = NULL; - - return; -} - - static CFStringRef notifyMPCopyDescription(const void *info) { @@ -122,141 +56,6 @@ notifyMPCopyDescription(const void *info) } -Boolean -SCDynamicStoreNotifyCallback(SCDynamicStoreRef store, - CFRunLoopRef runLoop, - SCDynamicStoreCallBack_v1 func, - void *arg) -{ - CFMachPortContext context = { 0 - , (void *)store - , CFRetain - , CFRelease - , notifyMPCopyDescription - }; - mach_port_t oldNotify; - mach_port_t port; - int sc_status; - kern_return_t status; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - if (storePrivate->notifyStatus != NotifierNotRegistered) { - /* sorry, you can only have one notification registered at once */ - _SCErrorSet(kSCStatusNotifierActive); - return FALSE; - } - - /* Allocating port (for server response) */ - status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); - if (status != KERN_SUCCESS) { - SCLog(TRUE, LOG_ERR, CFSTR("mach_port_allocate(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - status = mach_port_insert_right(mach_task_self(), - port, - port, - MACH_MSG_TYPE_MAKE_SEND); - if (status != KERN_SUCCESS) { - /* - * We can't insert a send right into our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - /* Request a notification when/if the server dies */ - status = mach_port_request_notification(mach_task_self(), - port, - MACH_NOTIFY_NO_SENDERS, - 1, - port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &oldNotify); - if (status != KERN_SUCCESS) { - /* - * We can't request a notification for our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - if (oldNotify != MACH_PORT_NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback(): oldNotify != MACH_PORT_NULL")); - } - - retry : - - /* Requesting notification via mach port */ - status = notifyviaport(storePrivate->server, - port, - 0, - (int *)&sc_status); - - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - /* remove the send right that we tried (but failed) to pass to the server */ - (void) mach_port_deallocate(mach_task_self(), port); - } - - /* remove our receive right */ - (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); - sc_status = status; - } - - if (sc_status != kSCStatusOK) { - _SCErrorSet(sc_status); - return FALSE; - } - - /* set notifier active */ - storePrivate->notifyStatus = Using_NotifierInformViaCallback; - - /* Creating/adding a run loop source for the port */ - __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCallback", port); - storePrivate->callbackArgument = arg; - storePrivate->callbackFunction = func; - storePrivate->callbackPort = _SC_CFMachPortCreateWithPort("SCDynamicStoreNotifyCallback", - port, - informCallback, - &context); - storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0); - CFRunLoopAddSource(runLoop, storePrivate->callbackRLS, kCFRunLoopDefaultMode); - - return TRUE; -} - - static void rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { @@ -272,8 +71,8 @@ rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) #endif /* DEBUG */ #ifdef DEBUG - if (port != storePrivate->callbackPort) { - SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != callbackPort?")); + if (port != storePrivate->rlsNotifyPort) { + SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != rlsNotifyPort?")); } #endif /* DEBUG */ @@ -289,16 +88,6 @@ rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) } -static void -portInvalidate(CFMachPortRef port, void *info) { - mach_port_t mp = CFMachPortGetPort(port); - - __MACH_PORT_DEBUG(TRUE, "*** portInvalidate", mp); - /* remove our receive right */ - (void)mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); -} - - static void rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { @@ -374,19 +163,16 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port); status = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status); + + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "rlsSchedule notifyviaport()")) { + goto retry; + } + if (status != KERN_SUCCESS) { if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } /* remove the send right that we tried (but failed) to pass to the server */ (void) mach_port_deallocate(mach_task_self(), port); } @@ -403,23 +189,22 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) } __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port); - storePrivate->callbackPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", - port, - rlsCallback, - &context); - CFMachPortSetInvalidationCallBack(storePrivate->callbackPort, portInvalidate); - storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0); + storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", + port, + rlsCallback, + &context); + storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0); storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) { + if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are not already scheduled with this runLoop / runLoopMode */ - CFRunLoopAddSource(rl, storePrivate->callbackRLS, mode); - __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->callbackPort)); + CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); + __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); } _SC_schedule(store, rl, mode, storePrivate->rlList); @@ -442,7 +227,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ - if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) { + if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { /* * if currently scheduled on this runLoop / runLoopMode @@ -453,7 +238,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ - CFRunLoopRemoveSource(rl, storePrivate->callbackRLS, mode); + CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); } } } @@ -465,44 +250,48 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source")); #endif /* DEBUG */ - __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL), + __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel", - CFMachPortGetPort(storePrivate->callbackPort)); + CFMachPortGetPort(storePrivate->rlsNotifyPort)); - CFRelease(storePrivate->rlList); - storePrivate->rlList = NULL; + if (storePrivate->rlList != NULL) { + CFRelease(storePrivate->rlList); + storePrivate->rlList = NULL; + } - if (storePrivate->callbackRLS != NULL) { + if (storePrivate->rlsNotifyRLS != NULL) { /* invalidate & remove the run loop source */ - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; + CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); + CFRelease(storePrivate->rlsNotifyRLS); + storePrivate->rlsNotifyRLS = NULL; } - if (storePrivate->callbackPort != NULL) { - /* invalidate port */ - __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL), - "*** rlsCancel (before invalidating CFMachPort)", - CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; + if (storePrivate->rlsNotifyPort != NULL) { + mach_port_t mp; + + mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); + __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), + "*** rlsCancel (before invalidating/releasing CFMachPort)", + mp); + + /* invalidate and release port */ + CFMachPortInvalidate(storePrivate->rlsNotifyPort); + CFRelease(storePrivate->rlsNotifyPort); + storePrivate->rlsNotifyPort = NULL; + + /* and, finally, remove our receive right */ + (void)mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); } if (storePrivate->server != MACH_PORT_NULL) { status = notifycancel(storePrivate->server, (int *)&sc_status); + + (void) __SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "rlsCancel notifycancel()"); + if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("rlsCancel notifycancel(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - (void) __SCDynamicStoreReconnect(store); - } return; } } @@ -550,8 +339,10 @@ rlsPerform(void *info) context_info = storePrivate->rlsContext.info; context_release = NULL; } - (*rlsFunction)(store, changedKeys, context_info); - if (context_release) { + if (rlsFunction != NULL) { + (*rlsFunction)(store, changedKeys, context_info); + } + if (context_release != NULL) { context_release(context_info); } @@ -638,9 +429,6 @@ rlsCopyDescription(const void *info) } CFStringAppendFormat(result, NULL, CFSTR(", context = %@"), description); CFRelease(description); - } else { - CFStringAppendFormat(result, NULL, CFSTR(", callout = %p"), storePrivate->callbackFunction); - CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument); } CFStringAppendFormat(result, NULL, CFSTR("}")); @@ -703,151 +491,162 @@ SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator, } -static boolean_t -SCDynamicStoreNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply) -{ - mach_msg_empty_rcv_t *buf = (mach_msg_empty_rcv_t *)message; - mach_msg_id_t msgid = buf->header.msgh_id; - SCDynamicStoreRef store; - - store = dispatch_get_context(dispatch_get_current_queue()); - if (store != NULL) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - CFRetain(storePrivate); - dispatch_async(storePrivate->dispatchQueue, ^{ - if (msgid == MACH_NOTIFY_NO_SENDERS) { - /* re-establish notification and inform the client */ - (void)__SCDynamicStoreReconnectNotifications(store); - } - rlsPerform(storePrivate); - CFRelease(storePrivate); - }); - } - reply->msgh_remote_port = MACH_PORT_NULL; - return false; -} - - Boolean SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) { + dispatch_group_t drainGroup = NULL; + dispatch_queue_t drainQueue = NULL; + dispatch_group_t group = NULL; + mach_port_t mp; Boolean ok = FALSE; + dispatch_source_t source; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (store == NULL) { - /* sorry, you must provide a session */ + // sorry, you must provide a session _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } - if (queue != NULL) { - mach_port_t mp; - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { + if (queue == NULL) { + if (storePrivate->dispatchQueue == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } - if (storePrivate->notifyStatus != NotifierNotRegistered) { - /* sorry, you can only have one notification registered at once... */ - _SCErrorSet(kSCStatusNotifierActive); - return FALSE; - } + ok = TRUE; + goto cleanup; + } - /* - * mark our using of the SCDynamicStore notifications, create and schedule - * the notification port (storePrivate->callbackPort), and a bunch of other - * "setup" - */ - storePrivate->notifyStatus = Using_NotifierInformViaDispatch; - rlsSchedule((void*)store, NULL, NULL); - storePrivate->dispatchQueue = queue; - dispatch_retain(storePrivate->dispatchQueue); - - if (storePrivate->callbackPort == NULL) { - /* if we could not schedule the notification */ - _SCErrorSet(kSCStatusFailed); - goto cleanup; - } + if (storePrivate->server == MACH_PORT_NULL) { + // sorry, you must have an open session to play + _SCErrorSet(kSCStatusNoStoreServer); + return FALSE; + } - /* - * create a dispatch queue for the mach notifications source, we'll use - * this queue's context to carry the store pointer for the callback code. - */ - storePrivate->callbackQueue = dispatch_queue_create("com.apple.SCDynamicStore.notifications", NULL); - if (storePrivate->callbackQueue == NULL){ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_queue_create() failed")); - _SCErrorSet(kSCStatusFailed); - goto cleanup; - } - CFRetain(store); // Note: will be released when the dispatch queue is released - dispatch_set_context(storePrivate->callbackQueue, (void *)store); - dispatch_set_finalizer_f(storePrivate->callbackQueue, (dispatch_function_t)CFRelease); - - /* - * create a dispatch source for the mach notifications - */ - mp = CFMachPortGetPort(storePrivate->callbackPort); - storePrivate->callbackSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, - mp, - 0, - storePrivate->callbackQueue); - if (storePrivate->callbackSource == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); - _SCErrorSet(kSCStatusFailed); - goto cleanup; + if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (storePrivate->notifyStatus != NotifierNotRegistered) { + // sorry, you can only have one notification registered at once... + _SCErrorSet(kSCStatusNotifierActive); + return FALSE; + } + + /* + * mark our using of the SCDynamicStore notifications, create and schedule + * the notification port (storePrivate->rlsNotifyPort), and a bunch of other + * "setup" + */ + storePrivate->notifyStatus = Using_NotifierInformViaDispatch; + rlsSchedule((void*)store, NULL, NULL); + if (storePrivate->rlsNotifyPort == NULL) { + /* if we could not schedule the notification */ + _SCErrorSet(kSCStatusFailed); + goto cleanup; + } + + // retain the dispatch queue + storePrivate->dispatchQueue = queue; + dispatch_retain(storePrivate->dispatchQueue); + + // + // We've taken a reference to the callers dispatch_queue and we + // want to hold on to that reference until we've processed any/all + // notifications. To facilitate this we create a group, dispatch + // any notification blocks to via that group, and when the caller + // has told us to stop the notifications (unschedule) we wait for + // the group to empty and use the group's finalizer to release + // our reference to the SCDynamicStore. + // + group = dispatch_group_create(); + storePrivate->dispatchGroup = group; + CFRetain(store); + dispatch_set_context(storePrivate->dispatchGroup, (void *)store); + dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); + + // create a dispatch source for the mach notifications + mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); + if (source == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); + _SCErrorSet(kSCStatusFailed); + goto cleanup; + } + + dispatch_source_set_event_handler(source, ^{ + kern_return_t kr; + mach_msg_id_t msgid; + union { + u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; + mach_msg_empty_rcv_t msg; + mach_no_senders_notification_t no_senders; + } notify_msg; + + kr = mach_msg(¬ify_msg.msg.header, // msg + MACH_RCV_MSG, // options + 0, // send_size + sizeof(notify_msg), // rcv_size + mp, // rcv_name + MACH_MSG_TIMEOUT_NONE, // timeout + MACH_PORT_NULL); // notify + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCDynamicStore notification handler, kr=0x%x"), + kr); + return; } - dispatch_source_set_event_handler(storePrivate->callbackSource, ^{ - union MaxMsgSize { - mach_msg_empty_rcv_t normal; - mach_no_senders_notification_t no_senders; - }; - - dispatch_mig_server(storePrivate->callbackSource, - sizeof(union MaxMsgSize), - SCDynamicStoreNotifyMIGCallback); + + msgid = notify_msg.msg.header.msgh_id; + + CFRetain(store); + dispatch_group_async(group, queue, ^{ + if (msgid == MACH_NOTIFY_NO_SENDERS) { + // re-establish notification and inform the client + (void)__SCDynamicStoreReconnectNotifications(store); + } + rlsPerform(storePrivate); + CFRelease(store); }); - dispatch_resume(storePrivate->callbackSource); + }); - ok = TRUE; - goto done; - } else { - if (storePrivate->dispatchQueue == NULL) { - _SCErrorSet(kSCStatusInvalidArgument); - return FALSE; - } + dispatch_source_set_cancel_handler(source, ^{ + dispatch_release(source); + }); - ok = TRUE; - } + storePrivate->dispatchSource = source; + dispatch_resume(source); + + return TRUE; cleanup : - if (storePrivate->callbackSource != NULL) { - dispatch_source_cancel(storePrivate->callbackSource); - if (storePrivate->callbackQueue != dispatch_get_current_queue()) { - // ensure the cancellation has completed - dispatch_sync(storePrivate->callbackQueue, ^{}); - } - dispatch_release(storePrivate->callbackSource); - storePrivate->callbackSource = NULL; - } - if (storePrivate->callbackQueue != NULL) { - dispatch_release(storePrivate->callbackQueue); - storePrivate->callbackQueue = NULL; + CFRetain(store); + + if (storePrivate->dispatchSource != NULL) { + dispatch_source_cancel(storePrivate->dispatchSource); + storePrivate->dispatchSource = NULL; } - dispatch_release(storePrivate->dispatchQueue); + drainGroup = storePrivate->dispatchGroup; + storePrivate->dispatchGroup = NULL; + drainQueue = storePrivate->dispatchQueue; storePrivate->dispatchQueue = NULL; + rlsCancel((void*)store, NULL, NULL); + + if (drainGroup != NULL) { + dispatch_group_notify(drainGroup, drainQueue, ^{ + // release group/queue references + dispatch_release(drainQueue); + dispatch_release(drainGroup); // releases our store reference + }); + } + storePrivate->notifyStatus = NotifierNotRegistered; - done : + CFRelease(store); return ok; }