]> git.saurik.com Git - apple/configd.git/blobdiff - SystemConfiguration.fproj/SCDNotifierInformViaCallback.c
configd-596.13.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDNotifierInformViaCallback.c
index 166c0ced1744a74a49a982ac0d1df8958c4719a0..02e7d48911fb7f11382af001d486c667a7197e71 100644 (file)
@@ -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@
  * 
 #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(&notify_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;
 }