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