2 * Copyright (c) 2000-2005, 2008, 2009 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>
38 #include <dispatch/dispatch.h>
39 #endif // !TARGET_OS_IPHONE
40 #include <mach/mach.h>
41 #include <mach/mach_error.h>
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
45 #include "SCDynamicStoreInternal.h"
46 #include "config.h" /* MiG generated file */
50 informCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
52 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
53 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
54 mach_msg_empty_rcv_t
*buf
= msg
;
55 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
56 SCDynamicStoreCallBack_v1 cbFunc
= storePrivate
->callbackFunction
;
57 void *cbArg
= storePrivate
->callbackArgument
;
59 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
60 /* the server died, disable additional callbacks */
62 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" notifier port closed, disabling notifier"));
64 } else if (cbFunc
== NULL
) {
65 /* there is no (longer) a callback function, disable additional callbacks */
67 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" no callback function, disabling notifier"));
71 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" executing notification function"));
73 if ((*cbFunc
)(store
, cbArg
)) {
75 * callback function returned success.
80 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" callback returned error, disabling notifier"));
86 if (port
!= storePrivate
->callbackPort
) {
87 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("informCallback, why is port != callbackPort?"));
91 /* invalidate the run loop source */
92 if (storePrivate
->callbackRLS
!= NULL
) {
93 CFRunLoopSourceInvalidate(storePrivate
->callbackRLS
);
94 CFRelease(storePrivate
->callbackRLS
);
95 storePrivate
->callbackRLS
= NULL
;
99 if (storePrivate
->callbackPort
!= NULL
) {
100 __MACH_PORT_DEBUG(TRUE
, "*** informCallback", CFMachPortGetPort(storePrivate
->callbackPort
));
101 CFMachPortInvalidate(storePrivate
->callbackPort
);
102 CFRelease(storePrivate
->callbackPort
);
103 storePrivate
->callbackPort
= NULL
;
106 /* disable notifier */
107 storePrivate
->notifyStatus
= NotifierNotRegistered
;
108 storePrivate
->callbackArgument
= NULL
;
109 storePrivate
->callbackFunction
= NULL
;
116 notifyMPCopyDescription(const void *info
)
118 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
120 return CFStringCreateWithFormat(NULL
,
122 CFSTR("<SCDynamicStore notification MP> {store = %p}"),
128 SCDynamicStoreNotifyCallback(SCDynamicStoreRef store
,
129 CFRunLoopRef runLoop
,
130 SCDynamicStoreCallBack_v1 func
,
133 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
134 kern_return_t status
;
136 mach_port_t oldNotify
;
138 CFMachPortContext context
= { 0
142 , notifyMPCopyDescription
146 /* sorry, you must provide a session */
147 _SCErrorSet(kSCStatusNoStoreSession
);
151 if (storePrivate
->server
== MACH_PORT_NULL
) {
152 /* sorry, you must have an open session to play */
153 _SCErrorSet(kSCStatusNoStoreServer
);
157 if (storePrivate
->notifyStatus
!= NotifierNotRegistered
) {
158 /* sorry, you can only have one notification registered at once */
159 _SCErrorSet(kSCStatusNotifierActive
);
163 /* Allocating port (for server response) */
164 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &port
);
165 if (status
!= KERN_SUCCESS
) {
166 SCLog(TRUE
, LOG_ERR
, CFSTR("mach_port_allocate(): %s"), mach_error_string(status
));
171 status
= mach_port_insert_right(mach_task_self(),
174 MACH_MSG_TYPE_MAKE_SEND
);
175 if (status
!= KERN_SUCCESS
) {
177 * We can't insert a send right into our own port! This should
178 * only happen if someone stomped on OUR port (so let's leave
181 SCLog(TRUE
, LOG_ERR
, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status
));
186 /* Request a notification when/if the server dies */
187 status
= mach_port_request_notification(mach_task_self(),
189 MACH_NOTIFY_NO_SENDERS
,
192 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
194 if (status
!= KERN_SUCCESS
) {
196 * We can't request a notification for our own port! This should
197 * only happen if someone stomped on OUR port (so let's leave
200 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status
));
205 if (oldNotify
!= MACH_PORT_NULL
) {
206 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
) {
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
;
225 if (status
== MACH_SEND_INVALID_DEST
) {
226 /* remove the send right that we tried (but failed) to pass to the server */
227 (void) mach_port_deallocate(mach_task_self(), port
);
230 /* remove our receive right */
231 (void) mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
236 if (sc_status
!= kSCStatusOK
) {
237 _SCErrorSet(sc_status
);
241 /* set notifier active */
242 storePrivate
->notifyStatus
= Using_NotifierInformViaCallback
;
244 /* Creating/adding a run loop source for the port */
245 __MACH_PORT_DEBUG(TRUE
, "*** SCDynamicStoreNotifyCallback", port
);
246 storePrivate
->callbackArgument
= arg
;
247 storePrivate
->callbackFunction
= func
;
248 storePrivate
->callbackPort
= CFMachPortCreateWithPort(NULL
, port
, informCallback
, &context
, NULL
);
249 storePrivate
->callbackRLS
= CFMachPortCreateRunLoopSource(NULL
, storePrivate
->callbackPort
, 0);
250 CFRunLoopAddSource(runLoop
, storePrivate
->callbackRLS
, kCFRunLoopDefaultMode
);
257 rlsCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
259 mach_msg_empty_rcv_t
*buf
= msg
;
260 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
261 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
262 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
264 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
265 /* the server died, disable additional callbacks */
267 SCLog(_sc_verbose
, LOG_INFO
, CFSTR(" rlsCallback(), notifier port closed"));
271 if (port
!= storePrivate
->callbackPort
) {
272 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("rlsCallback(), why is port != callbackPort?"));
276 /* invalidate the run loop source(s) */
277 if (storePrivate
->callbackRLS
!= NULL
) {
278 CFRunLoopSourceInvalidate(storePrivate
->callbackRLS
);
279 CFRelease(storePrivate
->callbackRLS
);
280 storePrivate
->callbackRLS
= NULL
;
283 /* invalidate port */
284 if (storePrivate
->callbackPort
!= NULL
) {
285 __MACH_PORT_DEBUG(TRUE
, "*** rlsCallback w/MACH_NOTIFY_NO_SENDERS", CFMachPortGetPort(storePrivate
->callbackPort
));
286 CFMachPortInvalidate(storePrivate
->callbackPort
);
287 CFRelease(storePrivate
->callbackPort
);
288 storePrivate
->callbackPort
= NULL
;
294 /* signal the real runloop source */
295 if (storePrivate
->rls
!= NULL
) {
296 CFRunLoopSourceSignal(storePrivate
->rls
);
303 portInvalidate(CFMachPortRef port
, void *info
) {
304 mach_port_t mp
= CFMachPortGetPort(port
);
306 __MACH_PORT_DEBUG(TRUE
, "*** portInvalidate", mp
);
307 /* remove our receive right */
308 (void)mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_RECEIVE
, -1);
313 rlsSchedule(void *info
, CFRunLoopRef rl
, CFStringRef mode
)
315 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
316 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
319 SCLog(_sc_verbose
, LOG_DEBUG
,
320 CFSTR("schedule notifications for mode %@"),
321 (rl
!= NULL
) ? mode
: CFSTR("libdispatch"));
324 if (storePrivate
->rlsRefs
++ == 0) {
325 CFMachPortContext context
= { 0
329 , notifyMPCopyDescription
331 mach_port_t oldNotify
;
334 kern_return_t status
;
337 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" activate callback runloop source"));
340 /* Allocating port (for server response) */
341 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &port
);
342 if (status
!= KERN_SUCCESS
) {
343 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_allocate(): %s"), mach_error_string(status
));
347 status
= mach_port_insert_right(mach_task_self(),
350 MACH_MSG_TYPE_MAKE_SEND
);
351 if (status
!= KERN_SUCCESS
) {
353 * We can't insert a send right into our own port! This should
354 * only happen if someone stomped on OUR port (so let's leave
357 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_insert_right(): %s"), mach_error_string(status
));
361 /* Request a notification when/if the server dies */
362 status
= mach_port_request_notification(mach_task_self(),
364 MACH_NOTIFY_NO_SENDERS
,
367 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
369 if (status
!= KERN_SUCCESS
) {
371 * We can't request a notification for our own port! This should
372 * only happen if someone stomped on OUR port (so let's leave
375 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule mach_port_request_notification(): %s"), mach_error_string(status
));
379 if (oldNotify
!= MACH_PORT_NULL
) {
380 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule(): oldNotify != MACH_PORT_NULL"));
383 __MACH_PORT_DEBUG(TRUE
, "*** rlsSchedule", port
);
384 status
= notifyviaport(storePrivate
->server
, port
, 0, (int *)&sc_status
);
385 if (status
!= KERN_SUCCESS
) {
386 if (status
== MACH_SEND_INVALID_DEST
) {
387 /* the server's gone and our session port's dead, remove the dead name right */
388 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
390 /* we got an unexpected error, leave the [session] port alone */
391 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsSchedule notifyviaport(): %s"), mach_error_string(status
));
393 storePrivate
->server
= MACH_PORT_NULL
;
395 if (status
== MACH_SEND_INVALID_DEST
) {
396 /* remove the send right that we tried (but failed) to pass to the server */
397 (void) mach_port_deallocate(mach_task_self(), port
);
400 /* 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
= CFMachPortCreateWithPort(NULL
, port
, rlsCallback
, &context
, NULL
);
407 if (storePrivate
->callbackPort
== NULL
) {
408 SCLog(TRUE
, LOG_ERR
, CFSTR("*** CFMachPortCreateWithPort returned NULL while attempting to schedule"));
409 SCLog(TRUE
, LOG_ERR
, CFSTR("*** a SCDynamicStore notification. Did this process call \"fork\" without"));
410 SCLog(TRUE
, LOG_ERR
, CFSTR("*** calling \"exec\""));
412 /* the server's gone and our session port's dead, remove the dead name right */
413 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
414 storePrivate
->server
= MACH_PORT_NULL
;
416 /* remove our receive right */
417 (void) mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
420 CFMachPortSetInvalidationCallBack(storePrivate
->callbackPort
, portInvalidate
);
421 storePrivate
->callbackRLS
= CFMachPortCreateRunLoopSource(NULL
, storePrivate
->callbackPort
, 0);
424 if ((rl
!= NULL
) && (storePrivate
->callbackRLS
!= NULL
)) {
425 CFRunLoopAddSource(rl
, storePrivate
->callbackRLS
, mode
);
426 __MACH_PORT_DEBUG(TRUE
, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate
->callbackPort
));
434 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 CFRunLoopRemoveSource(rl
, storePrivate
->callbackRLS
, mode
);
449 if (--storePrivate
->rlsRefs
== 0) {
451 kern_return_t status
;
454 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" cancel callback runloop source"));
456 __MACH_PORT_DEBUG((storePrivate
->callbackPort
!= NULL
),
458 CFMachPortGetPort(storePrivate
->callbackPort
));
460 if (storePrivate
->callbackRLS
!= NULL
) {
461 /* invalidate & remove the run loop source */
462 CFRunLoopSourceInvalidate(storePrivate
->callbackRLS
);
463 CFRelease(storePrivate
->callbackRLS
);
464 storePrivate
->callbackRLS
= NULL
;
467 if (storePrivate
->callbackPort
!= NULL
) {
468 /* invalidate port */
469 __MACH_PORT_DEBUG((storePrivate
->callbackPort
!= NULL
),
470 "*** rlsCancel (before invalidating CFMachPort)",
471 CFMachPortGetPort(storePrivate
->callbackPort
));
472 CFMachPortInvalidate(storePrivate
->callbackPort
);
473 CFRelease(storePrivate
->callbackPort
);
474 storePrivate
->callbackPort
= NULL
;
477 if (storePrivate
->server
!= MACH_PORT_NULL
) {
478 status
= notifycancel(storePrivate
->server
, (int *)&sc_status
);
479 if (status
!= KERN_SUCCESS
) {
480 if (status
== MACH_SEND_INVALID_DEST
) {
481 /* the server's gone and our session port's dead, remove the dead name right */
482 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
484 /* we got an unexpected error, leave the [session] port alone */
485 SCLog(TRUE
, LOG_ERR
, CFSTR("rlsCancel notifycancel(): %s"), mach_error_string(status
));
487 storePrivate
->server
= MACH_PORT_NULL
;
498 rlsPerform(void *info
)
500 CFArrayRef changedKeys
;
502 void (*context_release
)(const void *);
503 SCDynamicStoreCallBack rlsFunction
;
504 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
505 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
508 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR(" executing notification function"));
511 changedKeys
= SCDynamicStoreCopyNotifiedKeys(store
);
512 if (changedKeys
== NULL
) {
513 /* if no changes or something happened to the server */
517 if (CFArrayGetCount(changedKeys
) == 0) {
521 rlsFunction
= storePrivate
->rlsFunction
;
523 if (storePrivate
->rlsContext
.retain
!= NULL
) {
524 context_info
= (void *)storePrivate
->rlsContext
.retain(storePrivate
->rlsContext
.info
);
525 context_release
= storePrivate
->rlsContext
.release
;
527 context_info
= storePrivate
->rlsContext
.info
;
528 context_release
= NULL
;
530 (*rlsFunction
)(store
, changedKeys
, context_info
);
531 if (context_release
) {
532 context_release(context_info
);
537 CFRelease(changedKeys
);
543 rlsRetain(CFTypeRef cf
)
545 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
546 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
548 if (storePrivate
->notifyStatus
!= Using_NotifierInformViaRunLoop
) {
549 /* mark RLS active */
550 storePrivate
->notifyStatus
= Using_NotifierInformViaRunLoop
;
551 /* keep a reference to the store */
560 rlsRelease(CFTypeRef cf
)
562 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
563 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
565 /* mark RLS inactive */
566 storePrivate
->notifyStatus
= NotifierNotRegistered
;
567 storePrivate
->rls
= NULL
;
569 /* release our reference to the store */
577 rlsCopyDescription(const void *info
)
579 CFMutableStringRef result
;
580 SCDynamicStoreRef store
= (SCDynamicStoreRef
)info
;
581 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
583 result
= CFStringCreateMutable(NULL
, 0);
584 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore RLS> {"));
585 CFStringAppendFormat(result
, NULL
, CFSTR("store = %p"), store
);
586 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
587 CFStringRef description
= NULL
;
589 CFStringAppendFormat(result
, NULL
, CFSTR(", callout = %p"), storePrivate
->rlsFunction
);
591 if ((storePrivate
->rlsContext
.info
!= NULL
) && (storePrivate
->rlsContext
.copyDescription
!= NULL
)) {
592 description
= (*storePrivate
->rlsContext
.copyDescription
)(storePrivate
->rlsContext
.info
);
594 if (description
== NULL
) {
595 description
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SCDynamicStore context %p>"), storePrivate
->rlsContext
.info
);
597 if (description
== NULL
) {
598 description
= CFRetain(CFSTR("<no description>"));
600 CFStringAppendFormat(result
, NULL
, CFSTR(", context = %@"), description
);
601 CFRelease(description
);
603 CFStringAppendFormat(result
, NULL
, CFSTR(", callout = %p"), storePrivate
->callbackFunction
);
604 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->callbackArgument
);
606 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
613 SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator
,
614 SCDynamicStoreRef store
,
617 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
620 /* sorry, you must provide a session */
621 _SCErrorSet(kSCStatusNoStoreSession
);
625 if (storePrivate
->server
== MACH_PORT_NULL
) {
626 /* sorry, you must have an open session to play */
627 _SCErrorSet(kSCStatusNoStoreServer
);
631 switch (storePrivate
->notifyStatus
) {
632 case NotifierNotRegistered
:
633 case Using_NotifierInformViaRunLoop
:
634 /* OK to enable runloop notification */
637 /* sorry, you can only have one notification registered at once */
638 _SCErrorSet(kSCStatusNotifierActive
);
642 if (storePrivate
->rls
!= NULL
) {
643 CFRetain(storePrivate
->rls
);
645 CFRunLoopSourceContext context
= { 0 // version
646 , (void *)store
// info
647 , rlsRetain
// retain
648 , rlsRelease
// release
649 , rlsCopyDescription
// copyDescription
652 , rlsSchedule
// schedule
653 , rlsCancel
// cancel
654 , rlsPerform
// perform
657 storePrivate
->rls
= CFRunLoopSourceCreate(allocator
, order
, &context
);
658 if (storePrivate
->rls
== NULL
) {
659 _SCErrorSet(kSCStatusFailed
);
663 return storePrivate
->rls
;
667 #if !TARGET_OS_IPHONE
669 SCDynamicStoreNotifyMIGCallback(mach_msg_header_t
*message
, mach_msg_header_t
*reply
)
671 SCDynamicStorePrivateRef storePrivate
;
673 storePrivate
= dispatch_get_context(dispatch_get_current_queue());
674 if (storePrivate
!= NULL
) {
675 CFRetain(storePrivate
);
676 dispatch_async(storePrivate
->dispatchQueue
, ^{
677 rlsPerform(storePrivate
);
678 CFRelease(storePrivate
);
681 reply
->msgh_remote_port
= MACH_PORT_NULL
;
687 SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store
, dispatch_queue_t queue
)
690 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
693 /* sorry, you must provide a session */
694 _SCErrorSet(kSCStatusNoStoreSession
);
698 if (storePrivate
->server
== MACH_PORT_NULL
) {
699 /* sorry, you must have an open session to play */
700 _SCErrorSet(kSCStatusNoStoreServer
);
705 dispatch_queue_attr_t attr
;
709 if ((storePrivate
->dispatchQueue
!= NULL
) || (storePrivate
->rls
!= NULL
)) {
710 _SCErrorSet(kSCStatusInvalidArgument
);
714 if (storePrivate
->notifyStatus
!= NotifierNotRegistered
) {
715 /* sorry, you can only have one notification registered at once... */
716 _SCErrorSet(kSCStatusNotifierActive
);
721 * mark our using of the SCDynamicStore notifications, create and schedule
722 * the notification port (storePrivate->callbackPort), and a bunch of other
725 storePrivate
->notifyStatus
= Using_NotifierInformViaDispatch
;
726 rlsSchedule((void*)store
, NULL
, NULL
);
727 storePrivate
->dispatchQueue
= queue
;
728 dispatch_retain(storePrivate
->dispatchQueue
);
731 * create a queue for the mig source, we'll use this queue's context
732 * to carry the store pointer for the callback code.
734 attr
= dispatch_queue_attr_create();
735 res
= dispatch_queue_attr_set_finalizer(attr
,
736 ^(dispatch_queue_t dq
) {
737 SCDynamicStoreRef store
;
739 store
= (SCDynamicStoreRef
)dispatch_get_context(dq
);
743 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStore dispatch_queue_attr_set_finalizer() failed"));
744 dispatch_release(attr
);
745 _SCErrorSet(kSCStatusFailed
);
748 storePrivate
->callbackQueue
= dispatch_queue_create("com.apple.SCDynamicStore.notifications", attr
);
749 dispatch_release(attr
);
750 if (storePrivate
->callbackQueue
== NULL
){
751 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStore dispatch_queue_create() failed"));
752 _SCErrorSet(kSCStatusFailed
);
755 CFRetain(store
); // Note: will be released when the dispatch queue is released
756 dispatch_set_context(storePrivate
->callbackQueue
, (void *)store
);
758 dispatch_suspend(storePrivate
->callbackQueue
);
759 mp
= CFMachPortGetPort(storePrivate
->callbackPort
);
760 storePrivate
->callbackSource
= dispatch_source_mig_create(mp
, sizeof(mach_msg_header_t
), NULL
, storePrivate
->callbackQueue
, SCDynamicStoreNotifyMIGCallback
);
761 if (storePrivate
->callbackSource
== NULL
) {
762 SCLog(TRUE
, LOG_ERR
, CFSTR("SCDynamicStore dispatch_source_mig_create() failed"));
763 _SCErrorSet(kSCStatusFailed
);
766 dispatch_resume(storePrivate
->callbackQueue
);
771 if (storePrivate
->dispatchQueue
== NULL
) {
772 _SCErrorSet(kSCStatusInvalidArgument
);
781 if (storePrivate
->callbackSource
!= NULL
) {
782 dispatch_cancel(storePrivate
->callbackSource
);
783 dispatch_release(storePrivate
->callbackSource
);
784 storePrivate
->callbackSource
= NULL
;
786 if (storePrivate
->callbackQueue
!= NULL
) {
787 dispatch_release(storePrivate
->callbackQueue
);
788 storePrivate
->callbackQueue
= NULL
;
790 dispatch_release(storePrivate
->dispatchQueue
);
791 storePrivate
->dispatchQueue
= NULL
;
792 rlsCancel((void*)store
, NULL
, NULL
);
793 storePrivate
->notifyStatus
= NotifierNotRegistered
;
799 #endif // !TARGET_OS_IPHONE