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