2 * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 31, 2000 Allan Nathanson <ajn@apple.com>
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>
41 #include <SystemConfiguration/SystemConfiguration.h>
42 #include <SystemConfiguration/SCPrivate.h>
43 #include "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
48 informCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
50 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
51 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
52 mach_no_senders_notification_t
*buf
= msg
;
53 mach_msg_id_t msgid
= buf
->not_header
.msgh_id
;
54 SCDynamicStoreCallBack_v1 cbFunc
= storePrivate
->callbackFunction
;
55 void *cbArg
= storePrivate
->callbackArgument
;
57 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
58 /* the server died, disable additional callbacks */
60 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" notifier port closed, disabling notifier"));
62 } else if (cbFunc
== NULL
) {
63 /* there is no (longer) a callback function, disable additional callbacks */
65 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" no callback function, disabling notifier"));
69 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" executing notification function"));
71 if ((*cbFunc
)(store
, cbArg
)) {
73 * callback function returned success.
78 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" callback returned error, disabling notifier"));
84 if (port
!= storePrivate
->callbackPort
) {
85 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("informCallback, why is port != callbackPort?"));
89 /* invalidate the run loop source */
90 if (storePrivate
->callbackRLS
!= NULL
) {
91 CFRunLoopSourceInvalidate(storePrivate
->callbackRLS
);
92 CFRelease(storePrivate
->callbackRLS
);
93 storePrivate
->callbackRLS
= NULL
;
97 if (storePrivate
->callbackPort
!= NULL
) {
98 __MACH_PORT_DEBUG(TRUE
, "*** informCallback", CFMachPortGetPort(storePrivate
->callbackPort
));
99 CFMachPortInvalidate(storePrivate
->callbackPort
);
100 CFRelease(storePrivate
->callbackPort
);
101 storePrivate
->callbackPort
= NULL
;
104 /* disable notifier */
105 storePrivate
->notifyStatus
= NotifierNotRegistered
;
106 storePrivate
->callbackArgument
= NULL
;
107 storePrivate
->callbackFunction
= NULL
;
114 notifyMPCopyDescription(const void *info
)
116 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
118 return CFStringCreateWithFormat(NULL
,
120 CFSTR("<SCDynamicStore notification MP> {store = %p}"),
126 SCDynamicStoreNotifyCallback(SCDynamicStoreRef store
,
127 CFRunLoopRef runLoop
,
128 SCDynamicStoreCallBack_v1 func
,
131 CFMachPortContext context
= { 0
135 , notifyMPCopyDescription
137 mach_port_t oldNotify
;
140 kern_return_t status
;
141 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
144 /* sorry, you must provide a session */
145 _SCErrorSet(kSCStatusNoStoreSession
);
149 if (storePrivate
->server
== MACH_PORT_NULL
) {
150 /* sorry, you must have an open session to play */
151 _SCErrorSet(kSCStatusNoStoreServer
);
155 if (storePrivate
->notifyStatus
!= NotifierNotRegistered
) {
156 /* sorry, you can only have one notification registered at once */
157 _SCErrorSet(kSCStatusNotifierActive
);
161 /* Allocating port (for server response) */
162 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &port
);
163 if (status
!= KERN_SUCCESS
) {
164 SCLog(TRUE
, LOG_ERR
, CFSTR("mach_port_allocate(): %s"), mach_error_string(status
));
169 status
= mach_port_insert_right(mach_task_self(),
172 MACH_MSG_TYPE_MAKE_SEND
);
173 if (status
!= KERN_SUCCESS
) {
175 * We can't insert a send right into our own port! This should
176 * only happen if someone stomped on OUR port (so let's leave
179 SCLog(TRUE
, LOG_ERR
, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status
));
184 /* Request a notification when/if the server dies */
185 status
= mach_port_request_notification(mach_task_self(),
187 MACH_NOTIFY_NO_SENDERS
,
190 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
192 if (status
!= KERN_SUCCESS
) {
194 * We can't request a notification for our own port! This should
195 * only happen if someone stomped on OUR port (so let's leave
198 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status
));
203 if (oldNotify
!= MACH_PORT_NULL
) {
204 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStoreNotifyCallback(): oldNotify != MACH_PORT_NULL"));
209 /* Requesting notification via mach port */
210 status
= notifyviaport(storePrivate
->server
,
215 if (status
!= KERN_SUCCESS
) {
216 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
217 /* the server's gone and our session port's dead, remove the dead name right */
218 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
220 /* we got an unexpected error, leave the [session] port alone */
221 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStoreNotifyCallback notifyviaport(): %s"), mach_error_string(status
));
223 storePrivate
->server
= MACH_PORT_NULL
;
224 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
225 if (__SCDynamicStoreReconnect(store
)) {
228 /* remove the send right that we tried (but failed) to pass to the server */
229 (void) mach_port_deallocate(mach_task_self(), port
);
232 /* remove our receive right */
233 (void) mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
237 if (sc_status
!= kSCStatusOK
) {
238 _SCErrorSet(sc_status
);
242 /* set notifier active */
243 storePrivate
->notifyStatus
= Using_NotifierInformViaCallback
;
245 /* Creating/adding a run loop source for the port */
246 __MACH_PORT_DEBUG(TRUE
, "*** SCDynamicStoreNotifyCallback", port
);
247 storePrivate
->callbackArgument
= arg
;
248 storePrivate
->callbackFunction
= func
;
249 storePrivate
->callbackPort
= _SC_CFMachPortCreateWithPort("SCDynamicStoreNotifyCallback",
253 storePrivate
->callbackRLS
= CFMachPortCreateRunLoopSource(NULL
, storePrivate
->callbackPort
, 0);
254 CFRunLoopAddSource(runLoop
, storePrivate
->callbackRLS
, kCFRunLoopDefaultMode
);
261 rlsCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
263 mach_no_senders_notification_t
*buf
= msg
;
264 mach_msg_id_t msgid
= buf
->not_header
.msgh_id
;
265 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
266 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
268 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
269 /* the server died, disable additional callbacks */
271 SCLog(_sc_verbose
, LOG_INFO
, CFSTR(" rlsCallback(), notifier port closed"));
275 if (port
!= storePrivate
->callbackPort
) {
276 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("rlsCallback(), why is port != callbackPort?"));
280 /* re-establish notification and inform the client */
281 (void)__SCDynamicStoreReconnectNotifications(store
);
284 /* signal the real runloop source */
285 if (storePrivate
->rls
!= NULL
) {
286 CFRunLoopSourceSignal(storePrivate
->rls
);
293 portInvalidate(CFMachPortRef port
, void *info
) {
294 mach_port_t mp
= CFMachPortGetPort(port
);
296 __MACH_PORT_DEBUG(TRUE
, "*** portInvalidate", mp
);
297 /* remove our receive right */
298 (void)mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_RECEIVE
, -1);
303 rlsSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
)
305 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
306 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
309 SCLog(_sc_verbose
, LOG_DEBUG
,
310 CFSTR("schedule notifications for mode %@"),
311 (rl
!= NULL
) ? mode
: CFSTR("libdispatch"));
314 if (storePrivate
->rlList
== NULL
) {
315 CFMachPortContext context
= { 0
319 , notifyMPCopyDescription
321 mach_port_t oldNotify
;
324 kern_return_t status
;
327 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" activate callback runloop source"));
330 /* Allocating port (for server response) */
331 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &port
);
332 if (status
!= KERN_SUCCESS
) {
333 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_allocate(): %s"), mach_error_string(status
));
337 status
= mach_port_insert_right(mach_task_self(),
340 MACH_MSG_TYPE_MAKE_SEND
);
341 if (status
!= KERN_SUCCESS
) {
343 * We can't insert a send right into our own port! This should
344 * only happen if someone stomped on OUR port (so let's leave
347 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(status
));
351 /* Request a notification when/if the server dies */
352 status
= mach_port_request_notification(mach_task_self(),
354 MACH_NOTIFY_NO_SENDERS
,
357 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
359 if (status
!= KERN_SUCCESS
) {
361 * We can't request a notification for our own port! This should
362 * only happen if someone stomped on OUR port (so let's leave
365 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(status
));
369 if (oldNotify
!= MACH_PORT_NULL
) {
370 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL"));
375 __MACH_PORT_DEBUG(TRUE
, "*** rlsSchedule", port
);
376 status
= notifyviaport(storePrivate
->server
, port
, 0, (int *)&sc_status
);
377 if (status
!= KERN_SUCCESS
) {
378 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
379 /* the server's gone and our session port's dead, remove the dead name right */
380 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
382 /* we got an unexpected error, leave the [session] port alone */
383 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule notifyviaport(): %s"), mach_error_string(status
));
385 storePrivate
->server
= MACH_PORT_NULL
;
386 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
387 if (__SCDynamicStoreReconnect(store
)) {
390 /* remove the send right that we tried (but failed) to pass to the server */
391 (void) mach_port_deallocate(mach_task_self(), port
);
394 /* remove our receive right */
395 (void) mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
399 if (sc_status
!= kSCStatusOK
) {
400 /* something [else] didn't work, remove our receive right */
401 (void) mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
405 __MACH_PORT_DEBUG(TRUE
, "*** rlsSchedule (after notifyviaport)", port
);
406 storePrivate
->callbackPort
= _SC_CFMachPortCreateWithPort("SCDynamicStore",
410 CFMachPortSetInvalidationCallBack(storePrivate
->callbackPort
, portInvalidate
);
411 storePrivate
->callbackRLS
= CFMachPortCreateRunLoopSource(NULL
, storePrivate
->callbackPort
, 0);
413 storePrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
416 if ((rl
!= NULL
) && (storePrivate
->callbackRLS
!= NULL
)) {
417 if (!_SC_isScheduled(store
, rl
, mode
, storePrivate
->rlList
)) {
419 * if we are not already scheduled with this runLoop / runLoopMode
421 CFRunLoopAddSource(rl
, storePrivate
->callbackRLS
, mode
);
422 __MACH_PORT_DEBUG(TRUE
, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate
->callbackPort
));
425 _SC_schedule(store
, rl
, mode
, storePrivate
->rlList
);
433 rlsCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
)
436 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
437 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
440 SCLog(_sc_verbose
, LOG_DEBUG
,
441 CFSTR("cancel notifications for mode %@"),
442 (rl
!= NULL
) ? mode
: CFSTR("libdispatch"));
445 if ((rl
!= NULL
) && (storePrivate
->callbackRLS
!= NULL
)) {
446 if (_SC_unschedule(store
, rl
, mode
, storePrivate
->rlList
, FALSE
)) {
448 * if currently scheduled on this runLoop / runLoopMode
450 n
= CFArrayGetCount(storePrivate
->rlList
);
451 if (n
== 0 || !_SC_isScheduled(store
, rl
, mode
, storePrivate
->rlList
)) {
453 * if we are no longer scheduled to receive notifications for
454 * this runLoop / runLoopMode
456 CFRunLoopRemoveSource(rl
, storePrivate
->callbackRLS
, mode
);
463 kern_return_t status
;
466 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" cancel callback runloop source"));
468 __MACH_PORT_DEBUG((storePrivate
->callbackPort
!= NULL
),
470 CFMachPortGetPort(storePrivate
->callbackPort
));
472 CFRelease(storePrivate
->rlList
);
473 storePrivate
->rlList
= NULL
;
475 if (storePrivate
->callbackRLS
!= NULL
) {
476 /* invalidate & remove the run loop source */
477 CFRunLoopSourceInvalidate(storePrivate
->callbackRLS
);
478 CFRelease(storePrivate
->callbackRLS
);
479 storePrivate
->callbackRLS
= NULL
;
482 if (storePrivate
->callbackPort
!= NULL
) {
483 /* invalidate port */
484 __MACH_PORT_DEBUG((storePrivate
->callbackPort
!= NULL
),
485 "*** rlsCancel (before invalidating CFMachPort)",
486 CFMachPortGetPort(storePrivate
->callbackPort
));
487 CFMachPortInvalidate(storePrivate
->callbackPort
);
488 CFRelease(storePrivate
->callbackPort
);
489 storePrivate
->callbackPort
= NULL
;
492 if (storePrivate
->server
!= MACH_PORT_NULL
) {
493 status
= notifycancel(storePrivate
->server
, (int *)&sc_status
);
494 if (status
!= KERN_SUCCESS
) {
495 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
496 /* the server's gone and our session port's dead, remove the dead name right */
497 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
499 /* we got an unexpected error, leave the [session] port alone */
500 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsCancel notifycancel(): %s"), mach_error_string(status
));
502 storePrivate
->server
= MACH_PORT_NULL
;
503 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
504 (void) __SCDynamicStoreReconnect(store
);
516 rlsPerform(void *info
)
518 CFArrayRef changedKeys
;
520 void (*context_release
)(const void *);
521 SCDynamicStoreCallBack rlsFunction
;
522 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
523 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
526 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" executing notification function"));
529 changedKeys
= SCDynamicStoreCopyNotifiedKeys(store
);
530 if (storePrivate
->disconnectForceCallBack
) {
531 storePrivate
->disconnectForceCallBack
= FALSE
;
532 if (changedKeys
== NULL
) {
533 changedKeys
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
536 if (changedKeys
== NULL
) {
537 /* if no changes or something happened to the server */
539 } else if (CFArrayGetCount(changedKeys
) == 0) {
544 rlsFunction
= storePrivate
->rlsFunction
;
546 if (storePrivate
->rlsContext
.retain
!= NULL
) {
547 context_info
= (void *)storePrivate
->rlsContext
.retain(storePrivate
->rlsContext
.info
);
548 context_release
= storePrivate
->rlsContext
.release
;
550 context_info
= storePrivate
->rlsContext
.info
;
551 context_release
= NULL
;
553 (*rlsFunction
)(store
, changedKeys
, context_info
);
554 if (context_release
) {
555 context_release(context_info
);
560 CFRelease(changedKeys
);
566 rlsRetain(CFTypeRef cf
)
568 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
569 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
571 switch (storePrivate
->notifyStatus
) {
572 case NotifierNotRegistered
:
573 /* mark RLS active */
574 storePrivate
->notifyStatus
= Using_NotifierInformViaRunLoop
;
575 /* keep a reference to the store */
578 case Using_NotifierInformViaRunLoop
:
581 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsRetain() error: notifyStatus=%d"), storePrivate
->notifyStatus
);
590 rlsRelease(CFTypeRef cf
)
592 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
593 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
595 switch (storePrivate
->notifyStatus
) {
596 case NotifierNotRegistered
:
598 case Using_NotifierInformViaRunLoop
:
599 /* mark RLS inactive */
600 storePrivate
->notifyStatus
= NotifierNotRegistered
;
601 storePrivate
->rls
= NULL
;
603 /* release our reference to the store */
607 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsRelease() error: notifyStatus=%d"), storePrivate
->notifyStatus
);
616 rlsCopyDescription(const void *info
)
618 CFMutableStringRef result
;
619 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
620 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
622 result
= CFStringCreateMutable(NULL
, 0);
623 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore RLS> {"));
624 CFStringAppendFormat(result
, NULL
, CFSTR("store = %p"), store
);
625 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
626 CFStringRef description
= NULL
;
628 CFStringAppendFormat(result
, NULL
, CFSTR(", callout = %p"), storePrivate
->rlsFunction
);
630 if ((storePrivate
->rlsContext
.info
!= NULL
) && (storePrivate
->rlsContext
.copyDescription
!= NULL
)) {
631 description
= (*storePrivate
->rlsContext
.copyDescription
)(storePrivate
->rlsContext
.info
);
633 if (description
== NULL
) {
634 description
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SCDynamicStore context %p>"), storePrivate
->rlsContext
.info
);
636 if (description
== NULL
) {
637 description
= CFRetain(CFSTR("<no description>"));
639 CFStringAppendFormat(result
, NULL
, CFSTR(", context = %@"), description
);
640 CFRelease(description
);
642 CFStringAppendFormat(result
, NULL
, CFSTR(", callout = %p"), storePrivate
->callbackFunction
);
643 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->callbackArgument
);
645 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
652 SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator
,
653 SCDynamicStoreRef store
,
656 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
659 /* sorry, you must provide a session */
660 _SCErrorSet(kSCStatusNoStoreSession
);
664 if (storePrivate
->server
== MACH_PORT_NULL
) {
665 /* sorry, you must have an open session to play */
666 _SCErrorSet(kSCStatusNoStoreServer
);
670 switch (storePrivate
->notifyStatus
) {
671 case NotifierNotRegistered
:
672 case Using_NotifierInformViaRunLoop
:
673 /* OK to enable runloop notification */
676 /* sorry, you can only have one notification registered at once */
677 _SCErrorSet(kSCStatusNotifierActive
);
681 if (storePrivate
->rls
!= NULL
) {
682 CFRetain(storePrivate
->rls
);
684 CFRunLoopSourceContext context
= { 0 // version
685 , (void *)store
// info
686 , rlsRetain
// retain
687 , rlsRelease
// release
688 , rlsCopyDescription
// copyDescription
691 , rlsSchedule
// schedule
692 , rlsCancel
// cancel
693 , rlsPerform
// perform
696 storePrivate
->rls
= CFRunLoopSourceCreate(allocator
, order
, &context
);
697 if (storePrivate
->rls
== NULL
) {
698 _SCErrorSet(kSCStatusFailed
);
702 return storePrivate
->rls
;
707 SCDynamicStoreNotifyMIGCallback(mach_msg_header_t
*message
, mach_msg_header_t
*reply
)
709 mach_msg_empty_rcv_t
*buf
= (mach_msg_empty_rcv_t
*)message
;
710 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
711 SCDynamicStoreRef store
;
713 store
= dispatch_get_context(dispatch_get_current_queue());
715 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
717 CFRetain(storePrivate
);
718 dispatch_async(storePrivate
->dispatchQueue
, ^{
719 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
720 /* re-establish notification and inform the client */
721 (void)__SCDynamicStoreReconnectNotifications(store
);
723 rlsPerform(storePrivate
);
724 CFRelease(storePrivate
);
727 reply
->msgh_remote_port
= MACH_PORT_NULL
;
733 SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store
, dispatch_queue_t queue
)
736 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
739 /* sorry, you must provide a session */
740 _SCErrorSet(kSCStatusNoStoreSession
);
747 if (storePrivate
->server
== MACH_PORT_NULL
) {
748 /* sorry, you must have an open session to play */
749 _SCErrorSet(kSCStatusNoStoreServer
);
753 if ((storePrivate
->dispatchQueue
!= NULL
) || (storePrivate
->rls
!= NULL
)) {
754 _SCErrorSet(kSCStatusInvalidArgument
);
758 if (storePrivate
->notifyStatus
!= NotifierNotRegistered
) {
759 /* sorry, you can only have one notification registered at once... */
760 _SCErrorSet(kSCStatusNotifierActive
);
765 * mark our using of the SCDynamicStore notifications, create and schedule
766 * the notification port (storePrivate->callbackPort), and a bunch of other
769 storePrivate
->notifyStatus
= Using_NotifierInformViaDispatch
;
770 rlsSchedule((void*)store
, NULL
, NULL
);
771 storePrivate
->dispatchQueue
= queue
;
772 dispatch_retain(storePrivate
->dispatchQueue
);
774 if (storePrivate
->callbackPort
== NULL
) {
775 /* if we could not schedule the notification */
776 _SCErrorSet(kSCStatusFailed
);
781 * create a dispatch queue for the mach notifications source, we'll use
782 * this queue's context to carry the store pointer for the callback code.
784 storePrivate
->callbackQueue
= dispatch_queue_create("com.apple.SCDynamicStore.notifications", NULL
);
785 if (storePrivate
->callbackQueue
== NULL
){
786 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStore dispatch_queue_create() failed"));
787 _SCErrorSet(kSCStatusFailed
);
790 CFRetain(store
); // Note: will be released when the dispatch queue is released
791 dispatch_set_context(storePrivate
->callbackQueue
, (void *)store
);
792 dispatch_set_finalizer_f(storePrivate
->callbackQueue
, (dispatch_function_t
)CFRelease
);
795 * create a dispatch source for the mach notifications
797 mp
= CFMachPortGetPort(storePrivate
->callbackPort
);
798 storePrivate
->callbackSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
,
801 storePrivate
->callbackQueue
);
802 if (storePrivate
->callbackSource
== NULL
) {
803 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStore dispatch_source_create() failed"));
804 _SCErrorSet(kSCStatusFailed
);
807 dispatch_source_set_event_handler(storePrivate
->callbackSource
, ^{
809 mach_msg_empty_rcv_t normal
;
810 mach_no_senders_notification_t no_senders
;
813 dispatch_mig_server(storePrivate
->callbackSource
,
814 sizeof(union MaxMsgSize
),
815 SCDynamicStoreNotifyMIGCallback
);
817 dispatch_resume(storePrivate
->callbackSource
);
822 if (storePrivate
->dispatchQueue
== NULL
) {
823 _SCErrorSet(kSCStatusInvalidArgument
);
832 if (storePrivate
->callbackSource
!= NULL
) {
833 dispatch_source_cancel(storePrivate
->callbackSource
);
834 if (storePrivate
->callbackQueue
!= dispatch_get_current_queue()) {
835 // ensure the cancellation has completed
836 dispatch_sync(storePrivate
->callbackQueue
, ^{});
838 dispatch_release(storePrivate
->callbackSource
);
839 storePrivate
->callbackSource
= NULL
;
841 if (storePrivate
->callbackQueue
!= NULL
) {
842 dispatch_release(storePrivate
->callbackQueue
);
843 storePrivate
->callbackQueue
= NULL
;
845 dispatch_release(storePrivate
->dispatchQueue
);
846 storePrivate
->dispatchQueue
= NULL
;
847 rlsCancel((void*)store
, NULL
, NULL
);
848 storePrivate
->notifyStatus
= NotifierNotRegistered
;