+ // 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;
+ }
+
+ 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_source_set_cancel_handler(source, ^{
+ dispatch_release(source);
+ });
+
+ storePrivate->dispatchSource = source;
+ dispatch_resume(source);
+
+ return TRUE;
+
+ cleanup :
+
+ CFRetain(store);
+
+ if (storePrivate->dispatchSource != NULL) {
+ dispatch_source_cancel(storePrivate->dispatchSource);
+ storePrivate->dispatchSource = NULL;
+ }
+ 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;
+
+ CFRelease(store);
+
+ return ok;