static Boolean __SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs, CFRunLoopRef runLoop, CFStringRef runLoopMode) { SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; CFIndex n = 0; Boolean ok = FALSE; pthread_mutex_lock(&prefsPrivate->lock); if ((runLoop != NULL) && !prefsPrivate->scheduled) { // if we should be scheduled (but are not) _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (((runLoop == NULL) && (prefsPrivate->dispatchQueue == NULL)) || // if we should be scheduled on a dispatch queue (but are not) ((runLoop != NULL) && (prefsPrivate->dispatchQueue != NULL))) { // if we should be scheduled on a CFRunLoop (but are scheduled on a dispatch queue) _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (runLoop == NULL) { SCDynamicStoreSetDispatchQueue(prefsPrivate->session, NULL); dispatch_release(prefsPrivate->dispatchQueue); prefsPrivate->dispatchQueue = NULL; } else { if (!_SC_unschedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList, FALSE)) { // if not currently scheduled on this runLoop / runLoopMode _SCErrorSet(kSCStatusInvalidArgument); goto done; } n = CFArrayGetCount(prefsPrivate->rlList); if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) { /* * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ CFRunLoopRemoveSource(runLoop, prefsPrivate->rls, runLoopMode); if (n == 0) { // if *all* notifications have been unscheduled CFRelease(prefsPrivate->rlList); prefsPrivate->rlList = NULL; CFRunLoopSourceInvalidate(prefsPrivate->rls); CFRelease(prefsPrivate->rls); prefsPrivate->rls = NULL; } } } if (n == 0) { CFArrayRef changedKeys; // if *all* notifications have been unscheduled prefsPrivate->scheduled = FALSE; // no need to track changes (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL); // clear out any pending notifications changedKeys = SCDynamicStoreCopyNotifiedKeys(prefsPrivate->session); if (changedKeys != NULL) { CFRelease(changedKeys); } // release our reference to the prefs CFRelease(prefs); } ok = TRUE; done : pthread_mutex_unlock(&prefsPrivate->lock); return ok; }
static void rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("schedule notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if (storePrivate->rlList == NULL) { CFMachPortContext context = { 0 , (void *)store , CFRetain , CFRelease , notifyMPCopyDescription }; mach_port_t oldNotify; mach_port_t port; int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" activate callback runloop source")); #endif /* DEBUG */ /* 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("rlsSchedule mach_port_allocate(): %s"), mach_error_string(status)); return; } 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("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(status)); return; } /* 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("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(status)); return; } if (oldNotify != MACH_PORT_NULL) { SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL")); } retry : __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)) { /* 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); return; } if (sc_status != kSCStatusOK) { /* something [else] didn't work, remove our receive right */ (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); return; } __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port); 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->rlsNotifyRLS != NULL)) { if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are not already scheduled with this runLoop / runLoopMode */ CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); } _SC_schedule(store, rl, mode, storePrivate->rlList); } return; }
static Boolean __SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs, CFRunLoopRef runLoop, CFStringRef runLoopMode, dispatch_queue_t queue) { Boolean ok = FALSE; SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; pthread_mutex_lock(&prefsPrivate->lock); if ((prefsPrivate->dispatchQueue != NULL) || // if we are already scheduled on a dispatch queue ((queue != NULL) && prefsPrivate->scheduled)) { // if we are already scheduled on a CFRunLoop _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (!prefsPrivate->scheduled) { CFMutableArrayRef keys; if (prefsPrivate->session == NULL) { ok = __SCPreferencesAddSession(prefs); if (!ok) { goto done; } } CFRetain(prefs); // hold a reference to the prefs keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(keys, prefsPrivate->sessionKeyCommit); CFArrayAppendValue(keys, prefsPrivate->sessionKeyApply); (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, keys, NULL); CFRelease(keys); if (runLoop != NULL) { prefsPrivate->rls = SCDynamicStoreCreateRunLoopSource(NULL, prefsPrivate->session, 0); prefsPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } prefsPrivate->scheduled = TRUE; } if (queue != NULL) { ok = SCDynamicStoreSetDispatchQueue(prefsPrivate->session, queue); if (!ok) { prefsPrivate->scheduled = FALSE; (void) SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL); CFRelease(prefs); goto done; } prefsPrivate->dispatchQueue = queue; dispatch_retain(prefsPrivate->dispatchQueue); } else { if (!_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) { /* * if we do not already have notifications scheduled with * this runLoop / runLoopMode */ CFRunLoopAddSource(runLoop, prefsPrivate->rls, runLoopMode); } _SC_schedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList); } ok = TRUE; done : pthread_mutex_unlock(&prefsPrivate->lock); return ok; }
static void rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { CFIndex n = 0; SCDynamicStoreRef store = (SCDynamicStoreRef)info; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR("cancel notifications for mode %@"), (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { /* * if currently scheduled on this runLoop / runLoopMode */ n = CFArrayGetCount(storePrivate->rlList); if (n == 0 || !_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); } } } if (n == 0) { int sc_status; kern_return_t status; #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source")); #endif /* DEBUG */ __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel", CFMachPortGetPort(storePrivate->rlsNotifyPort)); if (storePrivate->rlList != NULL) { CFRelease(storePrivate->rlList); storePrivate->rlList = NULL; } if (storePrivate->rlsNotifyRLS != NULL) { /* invalidate & remove the run loop source */ CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); CFRelease(storePrivate->rlsNotifyRLS); storePrivate->rlsNotifyRLS = 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) { return; } } } return; }