2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include <CoreFoundation/CFRunLoop.h>
31 #include <CoreFoundation/CFSet.h>
32 #include <CoreFoundation/CFBag.h>
33 #include "CFInternal.h"
37 #include <mach/mach.h>
38 #include <mach/clock_types.h>
39 #include <mach/clock.h>
44 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
47 extern mach_port_name_t
mk_timer_create(void);
48 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
49 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
50 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
52 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
55 a
.lo
= x
& (int64_t)0xFFFFFFFF;
61 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
63 mach_msg_header_t header
;
64 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
65 header
.msgh_size
= sizeof(mach_msg_header_t
);
66 header
.msgh_remote_port
= port
;
67 header
.msgh_local_port
= MACH_PORT_NULL
;
68 header
.msgh_id
= msg_id
;
69 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
73 static kern_return_t
__CFClearPortSet(mach_port_t task
, mach_port_t portSet
) {
75 mach_port_name_array_t array
;
76 mach_msg_type_number_t idx
, number
;
78 ret
= mach_port_get_set_status(task
, portSet
, &array
, &number
);
79 if (KERN_SUCCESS
!= ret
) return ret
;
80 for (idx
= 0; idx
< number
; idx
++) {
81 ret
= mach_port_extract_member(task
, array
[idx
], portSet
);
82 if (KERN_SUCCESS
!= ret
) {
83 vm_deallocate(task
, (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
87 vm_deallocate(task
, (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
92 /* unlock a run loop and modes before doing callouts/sleeping */
93 /* never try to take the run loop lock with a mode locked */
94 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
95 /* run loop mode structures should never be deallocated, even if they become empty */
97 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
98 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
99 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
100 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
101 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
103 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
105 struct __CFRunLoopMode
{
107 CFSpinLock_t _lock
; /* must have the run loop locked before locking this */
111 CFMutableSetRef _sources
;
112 CFMutableSetRef _observers
;
113 CFMutableSetRef _timers
;
114 CFMutableArrayRef _submodes
; // names of the submodes
115 #if defined(__MACH__)
116 mach_port_t _portSet
;
118 #if defined(__WIN32__)
123 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
124 __CFSpinLock(&(rlm
->_lock
));
127 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
128 __CFSpinUnlock(&(rlm
->_lock
));
131 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
132 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
133 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
134 return CFEqual(rlm1
->_name
, rlm2
->_name
);
137 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
138 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
139 return CFHash(rlm
->_name
);
142 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
143 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
144 CFMutableStringRef result
;
145 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
146 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, rlm
->_lock
? "true" : "false");
147 #if defined(__MACH__)
148 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p,"), rlm
->_portSet
);
150 #if defined(__WIN32__)
151 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p,"), rlm
->_msgQMask
);
153 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm
->_sources
, rlm
->_observers
, rlm
->_timers
);
157 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
158 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
159 if (NULL
!= rlm
->_sources
) CFRelease(rlm
->_sources
);
160 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
161 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
162 if (NULL
!= rlm
->_submodes
) CFRelease(rlm
->_submodes
);
163 CFRelease(rlm
->_name
);
164 #if defined(__MACH__)
165 __CFClearPortSet(mach_task_self(), rlm
->_portSet
);
166 mach_port_destroy(mach_task_self(), rlm
->_portSet
);
172 CFSpinLock_t _lock
; /* locked for accessing mode list */
173 #if defined(__MACH__)
174 mach_port_t _waitPort
;
176 #if defined(__WIN32__)
179 volatile CFIndex
*_stopped
;
180 CFMutableSetRef _commonModes
;
181 CFMutableSetRef _commonModeItems
;
182 CFRunLoopModeRef _currentMode
;
183 CFMutableSetRef _modes
;
186 /* Bit 0 of the base reserved bits is used for stopped state */
187 /* Bit 1 of the base reserved bits is used for sleeping state */
188 /* Bit 2 of the base reserved bits is used for deallocating state */
190 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
191 return (rl
->_stopped
&& rl
->_stopped
[2]) ? true : false;
194 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
195 if (rl
->_stopped
) rl
->_stopped
[2] = 0x53544F50; // 'STOP'
198 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
199 if (rl
->_stopped
) rl
->_stopped
[2] = 0x0;
202 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
203 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_info
, 1, 1);
206 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
207 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 1, 1, 1);
210 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
211 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 1, 1, 0);
214 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
215 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_info
, 2, 2);
218 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
219 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 2, 2, 1);
222 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
223 __CFSpinLock(&(((CFRunLoopRef
)rl
)->_lock
));
226 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
227 __CFSpinUnlock(&(((CFRunLoopRef
)rl
)->_lock
));
230 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
231 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
232 CFMutableStringRef result
;
233 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
234 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), rl
->_lock
? "true" : "false", rl
->_waitPort
, (rl
->_stopped
&& *(rl
->_stopped
)) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
235 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
239 /* call with rl locked */
240 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
241 CFRunLoopModeRef rlm
;
242 struct __CFRunLoopMode srlm
;
243 srlm
._base
._isa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
244 srlm
._base
._info
= 0;
245 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
246 srlm
._name
= modeName
;
247 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
249 __CFRunLoopModeLock(rlm
);
255 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(CFGetAllocator(rl
), __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
260 rlm
->_name
= CFStringCreateCopy(CFGetAllocator(rlm
), modeName
);
261 rlm
->_stopped
= false;
262 rlm
->_sources
= NULL
;
263 rlm
->_observers
= NULL
;
265 rlm
->_submodes
= NULL
;
266 #if defined(__MACH__)
269 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &(rlm
->_portSet
));
270 if (KERN_SUCCESS
== ret
) {
271 ret
= mach_port_insert_member(mach_task_self(), rl
->_waitPort
, rlm
->_portSet
);
273 if (KERN_SUCCESS
!= ret
) HALT
;
276 #if defined(__WIN32__)
279 CFSetAddValue(rl
->_modes
, rlm
);
281 __CFRunLoopModeLock(rlm
); /* return mode locked */
285 #if defined(__WIN32__)
287 // expects rl and rlm locked
288 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
289 if (NULL
== rlm
) return true;
290 if (0 != rlm
->_msgQMask
) return false;
291 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
292 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
293 if (NULL
!= rlm
->_submodes
) {
295 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
296 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
297 CFRunLoopModeRef subrlm
;
299 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
300 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
) : true;
301 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
302 if (!subIsEmpty
) return false;
308 DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
309 CFRunLoopModeRef rlm
;
312 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
314 result
= rlm
->_msgQMask
;
315 __CFRunLoopModeUnlock(rlm
);
317 __CFRunLoopUnlock(rl
);
321 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef modeName
) {
322 CFRunLoopModeRef rlm
;
324 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
325 rlm
->_msgQMask
= mask
;
326 __CFRunLoopModeUnlock(rlm
);
327 __CFRunLoopUnlock(rl
);
332 // expects rl and rlm locked
333 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
334 if (NULL
== rlm
) return true;
335 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
336 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
337 if (NULL
!= rlm
->_submodes
) {
339 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
340 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
341 CFRunLoopModeRef subrlm
;
343 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
344 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
) : true;
345 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
346 if (!subIsEmpty
) return false;
354 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
356 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
357 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 3, 3);
360 CF_INLINE
void __CFSetValid(void *cf
) {
361 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 3, 3, 1);
364 CF_INLINE
void __CFUnsetValid(void *cf
) {
365 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 3, 3, 0);
368 struct __CFRunLoopSource
{
372 CFIndex _order
; /* immutable */
373 CFMutableBagRef _runLoops
;
375 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
376 #if defined(__MACH__)
377 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
382 /* Bit 1 of the base reserved bits is used for signaled state */
384 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
385 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
388 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
389 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
392 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
393 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
396 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
397 __CFSpinLock(&(rls
->_lock
));
400 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
401 __CFSpinUnlock(&(rls
->_lock
));
404 /* rlm is not locked */
405 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
406 __CFRunLoopSourceLock(rls
);
407 if (NULL
== rls
->_runLoops
) {
408 rls
->_runLoops
= CFBagCreateMutable(CFGetAllocator(rls
), 0, NULL
);
410 CFBagAddValue(rls
->_runLoops
, rl
);
411 __CFRunLoopSourceUnlock(rls
); // have to unlock before the callout -- cannot help clients with safety
412 if (0 == rls
->_context
.version0
.version
) {
413 if (NULL
!= rls
->_context
.version0
.schedule
) {
414 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, rlm
->_name
);
416 #if defined(__MACH__)
417 } else if (1 == rls
->_context
.version0
.version
) {
419 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
420 if (MACH_PORT_NULL
!= port
) {
421 mach_port_insert_member(mach_task_self(), port
, rlm
->_portSet
);
427 /* rlm is not locked */
428 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
429 if (0 == rls
->_context
.version0
.version
) {
430 if (NULL
!= rls
->_context
.version0
.cancel
) {
431 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
433 #if defined(__MACH__)
434 } else if (1 == rls
->_context
.version0
.version
) {
436 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
437 if (MACH_PORT_NULL
!= port
) {
438 mach_port_extract_member(mach_task_self(), port
, rlm
->_portSet
);
442 __CFRunLoopSourceLock(rls
);
443 if (NULL
!= rls
->_runLoops
) {
444 CFBagRemoveValue(rls
->_runLoops
, rl
);
446 __CFRunLoopSourceUnlock(rls
);
449 struct __CFRunLoopObserver
{
452 CFRunLoopRef _runLoop
;
454 CFOptionFlags _activities
; /* immutable */
455 CFIndex _order
; /* immutable */
456 CFRunLoopObserverCallBack _callout
; /* immutable */
457 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
460 /* Bit 0 of the base reserved bits is used for firing state */
461 /* Bit 1 of the base reserved bits is used for repeats state */
463 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
464 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_info
, 0, 0);
467 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
468 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 0, 0, 1);
471 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
472 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 0, 0, 0);
475 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
476 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_info
, 1, 1);
479 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
480 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 1, 1, 1);
483 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
484 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 1, 1, 0);
487 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
488 __CFSpinLock(&(rlo
->_lock
));
491 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
492 __CFSpinUnlock(&(rlo
->_lock
));
495 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
496 __CFRunLoopObserverLock(rlo
);
497 if (0 == rlo
->_rlCount
) {
501 __CFRunLoopObserverUnlock(rlo
);
504 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
505 __CFRunLoopObserverLock(rlo
);
507 if (0 == rlo
->_rlCount
) {
508 rlo
->_runLoop
= NULL
;
510 __CFRunLoopObserverUnlock(rlo
);
513 struct __CFRunLoopTimer
{
516 CFRunLoopRef _runLoop
;
518 #if defined(__MACH__)
519 mach_port_name_t _port
;
521 CFIndex _order
; /* immutable */
522 int64_t _fireTSR
; /* TSR units */
523 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
524 CFRunLoopTimerCallBack _callout
; /* immutable */
525 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
528 /* Bit 0 of the base reserved bits is used for firing state */
529 /* Bit 1 of the base reserved bits is used for has-reset state */
531 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
532 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_info
, 0, 0);
535 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
536 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 0, 0, 1);
539 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
540 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 0, 0, 0);
543 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
544 __CFSpinLock(&(rlt
->_lock
));
547 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
548 __CFSpinUnlock(&(rlt
->_lock
));
551 static CFSpinLock_t __CFRLTFireTSRLock
= 0;
553 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
554 __CFSpinLock(&__CFRLTFireTSRLock
);
557 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
558 __CFSpinUnlock(&__CFRLTFireTSRLock
);
561 static CFMutableDictionaryRef __CFRLTPortMap
= NULL
;
562 static CFSpinLock_t __CFRLTPortMapLock
= 0;
564 CF_INLINE
void __CFRunLoopTimerPortMapLock(void) {
565 __CFSpinLock(&__CFRLTPortMapLock
);
568 CF_INLINE
void __CFRunLoopTimerPortMapUnlock(void) {
569 __CFSpinUnlock(&__CFRLTPortMapLock
);
572 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
573 #if defined(__MACH__)
574 __CFRunLoopTimerLock(rlt
);
575 if (0 == rlt
->_rlCount
) {
577 if (MACH_PORT_NULL
== rlt
->_port
) {
578 rlt
->_port
= mk_timer_create();
580 __CFRunLoopTimerPortMapLock();
581 if (NULL
== __CFRLTPortMap
) {
582 __CFRLTPortMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
584 CFDictionarySetValue(__CFRLTPortMap
, (void *)rlt
->_port
, rlt
);
585 __CFRunLoopTimerPortMapUnlock();
588 mach_port_insert_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
589 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
590 __CFRunLoopTimerUnlock(rlt
);
594 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
595 #if defined(__MACH__)
596 __CFRunLoopTimerLock(rlt
);
597 mach_port_extract_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
599 if (0 == rlt
->_rlCount
) {
600 __CFRunLoopTimerPortMapLock();
601 if (NULL
!= __CFRLTPortMap
) {
602 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)rlt
->_port
);
604 __CFRunLoopTimerPortMapUnlock();
605 rlt
->_runLoop
= NULL
;
606 mk_timer_cancel(rlt
->_port
, NULL
);
608 __CFRunLoopTimerUnlock(rlt
);
612 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
) {
613 #if defined(__MACH__)
614 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
621 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
622 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
624 #if defined(__MACH__)
628 CFRunLoopSourceRef result
;
631 static void __CFRunLoopFindSource(const void *value
, void *ctx
) {
632 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
633 struct _findsource
*context
= (struct _findsource
*)ctx
;
635 if (NULL
!= context
->result
) return;
636 if (1 != rls
->_context
.version0
.version
) return;
637 __CFRunLoopSourceLock(rls
);
638 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
639 if (port
== context
->port
) {
640 context
->result
= rls
;
642 __CFRunLoopSourceUnlock(rls
);
645 // call with rl and rlm locked
646 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, mach_port_t port
) { /* DOES CALLOUT */
647 struct _findsource context
= {port
, NULL
};
648 if (NULL
!= rlm
->_sources
) {
649 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopFindSource
), &context
);
651 if (NULL
== context
.result
&& NULL
!= rlm
->_submodes
) {
653 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
654 CFRunLoopSourceRef source
= NULL
;
655 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
656 CFRunLoopModeRef subrlm
;
657 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
658 if (NULL
!= subrlm
) {
659 source
= __CFRunLoopModeFindSourceForMachPort(rl
, subrlm
, port
);
660 __CFRunLoopModeUnlock(subrlm
);
662 if (NULL
!= source
) {
663 context
.result
= source
;
668 return context
.result
;
671 // call with rl and rlm locked
672 static CFRunLoopTimerRef
__CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm
, mach_port_name_t port
) {
673 CFRunLoopTimerRef result
= NULL
;
674 __CFRunLoopTimerPortMapLock();
675 if (NULL
!= __CFRLTPortMap
) {
676 result
= (CFRunLoopTimerRef
)CFDictionaryGetValue(__CFRLTPortMap
, (void *)port
);
678 __CFRunLoopTimerPortMapUnlock();
683 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
684 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
685 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
687 const void **list
, *buffer
[256];
688 if (NULL
== rlm
->_sources
) return;
689 cnt
= CFSetGetCount(rlm
->_sources
);
690 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
691 CFSetGetValues(rlm
->_sources
, list
);
692 for (idx
= 0; idx
< cnt
; idx
++) {
695 CFSetRemoveAllValues(rlm
->_sources
);
696 for (idx
= 0; idx
< cnt
; idx
++) {
697 __CFRunLoopSourceCancel((CFRunLoopSourceRef
)list
[idx
], rl
, rlm
);
698 CFRelease(list
[idx
]);
700 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
703 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
704 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
705 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
707 const void **list
, *buffer
[256];
708 if (NULL
== rlm
->_observers
) return;
709 cnt
= CFSetGetCount(rlm
->_observers
);
710 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
711 CFSetGetValues(rlm
->_observers
, list
);
712 for (idx
= 0; idx
< cnt
; idx
++) {
715 CFSetRemoveAllValues(rlm
->_observers
);
716 for (idx
= 0; idx
< cnt
; idx
++) {
717 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
718 CFRelease(list
[idx
]);
720 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
723 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
724 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
725 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
727 const void **list
, *buffer
[256];
728 if (NULL
== rlm
->_timers
) return;
729 cnt
= CFSetGetCount(rlm
->_timers
);
730 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
731 CFSetGetValues(rlm
->_timers
, list
);
732 for (idx
= 0; idx
< cnt
; idx
++) {
735 CFSetRemoveAllValues(rlm
->_timers
);
736 for (idx
= 0; idx
< cnt
; idx
++) {
737 __CFRunLoopTimerCancel((CFRunLoopTimerRef
)list
[idx
], rl
, rlm
);
738 CFRelease(list
[idx
]);
740 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
743 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
744 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
745 /* We try to keep the run loop in a valid state as long as possible,
746 since sources may have non-retained references to the run loop.
747 Another reason is that we don't want to lock the run loop for
748 callback reasons, if we can get away without that. We start by
749 eliminating the sources, since they are the most likely to call
750 back into the run loop during their "cancellation". Common mode
751 items will be removed from the mode indirectly by the following
753 __CFRunLoopSetDeallocating(rl
);
754 if (NULL
!= rl
->_modes
) {
755 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
756 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
757 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
760 if (NULL
!= rl
->_commonModeItems
) {
761 CFRelease(rl
->_commonModeItems
);
763 if (NULL
!= rl
->_commonModes
) {
764 CFRelease(rl
->_commonModes
);
766 if (NULL
!= rl
->_modes
) {
767 CFRelease(rl
->_modes
);
769 #if defined(__MACH__)
770 mach_port_destroy(mach_task_self(), rl
->_waitPort
);
773 #if defined(__WIN32__)
774 CloseHandle(rl
->_waitPort
);
777 __CFRunLoopUnlock(rl
);
780 static const CFRuntimeClass __CFRunLoopModeClass
= {
785 __CFRunLoopModeDeallocate
,
786 __CFRunLoopModeEqual
,
789 __CFRunLoopModeCopyDescription
792 static const CFRuntimeClass __CFRunLoopClass
= {
797 __CFRunLoopDeallocate
,
801 __CFRunLoopCopyDescription
804 __private_extern__
void __CFRunLoopInitialize(void) {
805 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
806 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
809 CFTypeID
CFRunLoopGetTypeID(void) {
810 return __kCFRunLoopTypeID
;
813 static CFRunLoopRef
__CFRunLoopCreate(void) {
814 CFRunLoopRef loop
= NULL
;
815 CFRunLoopModeRef rlm
;
816 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
817 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
821 loop
->_stopped
= NULL
;
823 #if defined(__MACH__)
826 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &(loop
->_waitPort
));
827 if (KERN_SUCCESS
== ret
) {
828 ret
= mach_port_insert_right(mach_task_self(), loop
->_waitPort
, loop
->_waitPort
, MACH_MSG_TYPE_MAKE_SEND
);
830 if (KERN_SUCCESS
== ret
) {
831 mach_port_limits_t limits
;
832 limits
.mpl_qlimit
= 1;
833 ret
= mach_port_set_attributes(mach_task_self(), loop
->_waitPort
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
835 if (KERN_SUCCESS
!= ret
) HALT
;
837 #elif defined(__WIN32__)
838 loop
->_waitPort
= CreateEvent(NULL
, true, false, NULL
);
840 loop
->_commonModes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
841 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
842 loop
->_commonModeItems
= NULL
;
843 loop
->_currentMode
= NULL
;
844 loop
->_modes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
845 _CFSetSetCapacity(loop
->_modes
, 10);
846 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
847 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
851 static CFRunLoopRef mainLoop
= NULL
;
852 static int mainLoopPid
= 0;
853 static CFSpinLock_t mainLoopLock
= 0;
855 CFRunLoopRef
CFRunLoopGetMain(void) {
856 __CFSpinLock(&mainLoopLock
);
857 if (mainLoopPid
!= getpid()) {
858 // intentionally leak mainLoop so we don't kill any ports in the child
862 mainLoop
= __CFRunLoopCreate();
863 mainLoopPid
= getpid();
865 __CFSpinUnlock(&mainLoopLock
);
869 static void _CFRunLoopSetMain(CFRunLoopRef rl
) {
870 if (rl
!= mainLoop
) {
871 if (rl
) CFRetain(rl
);
872 // intentionally leak the old main run loop
873 // if (mainLoop) CFRelease(mainLoop);
878 CFRunLoopRef
CFRunLoopGetCurrent(void) {
879 if (pthread_main_np()) {
880 return CFRunLoopGetMain();
882 CFRunLoopRef currentLoop
= __CFGetThreadSpecificData_inline()->_runLoop
;
883 int currentLoopPid
= __CFGetThreadSpecificData_inline()->_runLoop_pid
;
884 if (currentLoopPid
!= getpid()) {
885 // intentionally leak currentLoop so we don't kill any ports in the child
889 currentLoop
= __CFRunLoopCreate();
890 __CFGetThreadSpecificData_inline()->_runLoop
= currentLoop
;
891 __CFGetThreadSpecificData_inline()->_runLoop_pid
= getpid();
896 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
897 if (pthread_main_np()) {
898 return _CFRunLoopSetMain(rl
);
900 CFRunLoopRef currentLoop
= __CFGetThreadSpecificData_inline()->_runLoop
;
901 if (rl
!= currentLoop
) {
902 if (rl
) CFRetain(rl
);
903 // intentionally leak old run loop
904 // if (currentLoop) CFRelease(currentLoop);
905 __CFGetThreadSpecificData_inline()->_runLoop
= rl
;
906 __CFGetThreadSpecificData_inline()->_runLoop_pid
= getpid();
910 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
911 CFStringRef result
= NULL
;
913 if (NULL
!= rl
->_currentMode
) {
914 result
= CFRetain(rl
->_currentMode
->_name
);
916 __CFRunLoopUnlock(rl
);
920 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
921 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
922 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
923 CFArrayAppendValue(array
, rlm
->_name
);
926 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
927 CFMutableArrayRef array
;
929 array
= CFArrayCreateMutable(kCFAllocatorDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
930 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
931 __CFRunLoopUnlock(rl
);
935 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
936 CFTypeRef item
= (CFTypeRef
)value
;
937 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
938 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
939 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
940 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
941 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
942 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
943 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
944 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
948 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
949 CFStringRef modeName
= (CFStringRef
)value
;
950 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
951 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
952 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
953 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
954 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
955 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
956 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
957 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
961 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
962 CFStringRef modeName
= (CFStringRef
)value
;
963 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
964 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
965 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
966 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
967 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
968 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
969 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
970 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
974 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
975 if (__CFRunLoopIsDeallocating(rl
)) return;
977 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
978 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
979 CFSetAddValue(rl
->_commonModes
, modeName
);
980 __CFRunLoopUnlock(rl
);
982 CFTypeRef context
[2] = {rl
, modeName
};
983 /* add all common-modes items to new mode */
984 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
988 __CFRunLoopUnlock(rl
);
992 static CFComparisonResult
__CFRunLoopObserverComparator(const void *val1
, const void *val2
, void *context
) {
993 CFRunLoopObserverRef o1
= (CFRunLoopObserverRef
)val1
;
994 CFRunLoopObserverRef o2
= (CFRunLoopObserverRef
)val2
;
995 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
996 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
997 return kCFCompareEqualTo
;
1000 struct _collectobs
{
1001 CFRunLoopActivity activity
;
1002 CFMutableArrayRef array
;
1005 static void __CFRunLoopCollectObservers(const void *value
, void *context
) {
1006 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)value
;
1007 struct _collectobs
*info
= (struct _collectobs
*)context
;
1008 if (0 != (rlo
->_activities
& info
->activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1009 CFArrayAppendValue(info
->array
, rlo
);
1013 /* rl is unlocked, rlm is locked on entrance and exit */
1014 /* ALERT: this should collect all the candidate observers from the top level
1015 * and all submodes, recursively, THEN start calling them, in order to obey
1016 * the ordering parameter. */
1017 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1019 CFMutableArrayRef array
;
1020 CFArrayRef submodes
;
1021 struct _collectobs info
;
1023 /* Fire the observers */
1024 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1025 if (NULL
!= rlm
->_observers
) {
1026 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rlm
->_observers
), &kCFTypeArrayCallBacks
);
1028 info
.activity
= activity
;
1029 CFSetApplyFunction(rlm
->_observers
, (__CFRunLoopCollectObservers
), &info
);
1030 cnt
= CFArrayGetCount(array
);
1032 __CFRunLoopModeUnlock(rlm
);
1033 CFArraySortValues(array
, CFRangeMake(0, cnt
), (__CFRunLoopObserverComparator
), NULL
);
1034 for (idx
= 0; idx
< cnt
; idx
++) {
1035 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(array
, idx
);
1036 __CFRunLoopObserverLock(rlo
);
1037 if (__CFIsValid(rlo
)) {
1038 __CFRunLoopObserverUnlock(rlo
);
1039 __CFRunLoopObserverSetFiring(rlo
);
1040 rlo
->_callout(rlo
, activity
, rlo
->_context
.info
); /* CALLOUT */
1041 __CFRunLoopObserverUnsetFiring(rlo
);
1042 if (!__CFRunLoopObserverRepeats(rlo
)) {
1043 CFRunLoopObserverInvalidate(rlo
);
1046 __CFRunLoopObserverUnlock(rlo
);
1049 __CFRunLoopModeLock(rlm
);
1053 if (NULL
!= submodes
) {
1054 __CFRunLoopModeUnlock(rlm
);
1055 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1056 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1057 CFRunLoopModeRef subrlm
;
1058 __CFRunLoopLock(rl
);
1059 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1060 __CFRunLoopUnlock(rl
);
1061 if (NULL
!= subrlm
) {
1062 __CFRunLoopDoObservers(rl
, subrlm
, activity
);
1063 __CFRunLoopModeUnlock(subrlm
);
1066 CFRelease(submodes
);
1067 __CFRunLoopModeLock(rlm
);
1071 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1072 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1073 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1074 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1075 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1076 return kCFCompareEqualTo
;
1079 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1080 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1081 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1082 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1083 if (NULL
== *sources
) {
1084 *sources
= CFRetain(rls
);
1085 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1086 CFTypeRef oldrls
= *sources
;
1087 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1088 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1089 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1092 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1097 /* rl is unlocked, rlm is locked on entrance and exit */
1098 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1099 CFTypeRef sources
= NULL
;
1100 Boolean sourceHandled
= false;
1103 __CFRunLoopModeUnlock(rlm
); // locks have to be taken in order
1104 __CFRunLoopLock(rl
);
1105 __CFRunLoopModeLock(rlm
);
1106 /* Fire the version 0 sources */
1107 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) {
1108 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1110 for (idx
= 0, cnt
= (NULL
!= rlm
->_submodes
) ? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1111 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1112 CFRunLoopModeRef subrlm
;
1113 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1114 if (NULL
!= subrlm
) {
1115 if (NULL
!= subrlm
->_sources
&& 0 < CFSetGetCount(subrlm
->_sources
)) {
1116 CFSetApplyFunction(subrlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1118 __CFRunLoopModeUnlock(subrlm
);
1121 __CFRunLoopUnlock(rl
);
1122 if (NULL
!= sources
) {
1123 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1124 __CFRunLoopModeUnlock(rlm
);
1125 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1126 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1127 __CFRunLoopSourceLock(rls
);
1128 __CFRunLoopSourceUnsetSignaled(rls
);
1129 if (__CFIsValid(rls
)) {
1130 __CFRunLoopSourceUnlock(rls
);
1131 if (NULL
!= rls
->_context
.version0
.perform
) {
1132 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1134 sourceHandled
= true;
1136 __CFRunLoopSourceUnlock(rls
);
1139 cnt
= CFArrayGetCount(sources
);
1140 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1141 for (idx
= 0; idx
< cnt
; idx
++) {
1142 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, idx
);
1143 __CFRunLoopSourceLock(rls
);
1144 __CFRunLoopSourceUnsetSignaled(rls
);
1145 if (__CFIsValid(rls
)) {
1146 __CFRunLoopSourceUnlock(rls
);
1147 if (NULL
!= rls
->_context
.version0
.perform
) {
1148 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1150 sourceHandled
= true;
1152 __CFRunLoopSourceUnlock(rls
);
1154 if (stopAfterHandle
&& sourceHandled
) {
1160 __CFRunLoopModeLock(rlm
);
1162 return sourceHandled
;
1165 #if defined(__MACH__)
1166 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
, mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
) { /* DOES CALLOUT */
1167 Boolean sourceHandled
= false;
1169 /* Fire a version 1 source */
1171 __CFRunLoopModeUnlock(rlm
);
1172 __CFRunLoopSourceLock(rls
);
1173 if (__CFIsValid(rls
)) {
1174 __CFRunLoopSourceUnsetSignaled(rls
);
1175 __CFRunLoopSourceUnlock(rls
);
1176 if (NULL
!= rls
->_context
.version1
.perform
) {
1177 *reply
= rls
->_context
.version1
.perform(msg
, size
, kCFAllocatorSystemDefault
, rls
->_context
.version1
.info
); /* CALLOUT */
1179 sourceHandled
= true;
1181 __CFRunLoopSourceUnlock(rls
);
1184 __CFRunLoopModeLock(rlm
);
1185 return sourceHandled
;
1189 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1190 Boolean timerHandled
= false;
1191 int64_t oldFireTSR
= 0;
1195 __CFRunLoopModeUnlock(rlm
);
1196 __CFRunLoopTimerLock(rlt
);
1197 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
1198 __CFRunLoopTimerSetFiring(rlt
);
1199 __CFRunLoopTimerUnlock(rlt
);
1200 __CFRunLoopTimerFireTSRLock();
1201 oldFireTSR
= rlt
->_fireTSR
;
1202 __CFRunLoopTimerFireTSRUnlock();
1203 rlt
->_callout(rlt
, rlt
->_context
.info
); /* CALLOUT */
1204 __CFRunLoopTimerUnsetFiring(rlt
);
1205 timerHandled
= true;
1207 __CFRunLoopTimerUnlock(rlt
);
1209 if (__CFIsValid(rlt
) && timerHandled
) {
1210 if (0 == rlt
->_intervalTSR
) {
1211 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1213 /* This is just a little bit tricky: we want to support calling
1214 * CFRunLoopTimerSetNextFireDate() from within the callout and
1215 * honor that new time here if it is a later date, otherwise
1216 * it is completely ignored. */
1217 int64_t currentFireTSR
;
1218 __CFRunLoopTimerFireTSRLock();
1219 currentFireTSR
= rlt
->_fireTSR
;
1220 if (oldFireTSR
< currentFireTSR
) {
1221 /* Next fire TSR was set, and set to a date after the previous
1222 * fire date, so we honor it. */
1224 if ((uint64_t)LLONG_MAX
<= (uint64_t)oldFireTSR
+ (uint64_t)rlt
->_intervalTSR
) {
1225 currentFireTSR
= LLONG_MAX
;
1227 int64_t currentTSR
= (int64_t)__CFReadTSR();
1228 currentFireTSR
= oldFireTSR
;
1229 while (currentFireTSR
<= currentTSR
) {
1230 currentFireTSR
+= rlt
->_intervalTSR
;
1234 rlt
->_fireTSR
= currentFireTSR
;
1235 __CFRunLoopTimerFireTSRUnlock();
1236 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rl
);
1240 __CFRunLoopModeLock(rlm
);
1241 return timerHandled
;
1244 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1245 CFRunLoopModeRef rlm
;
1246 Boolean result
= false;
1247 __CFRunLoopLock(rl
);
1248 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1249 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1252 __CFRunLoopUnlock(rl
);
1253 if (rlm
) __CFRunLoopModeUnlock(rlm
);
1257 // rl is locked, rlm is locked on entry and exit
1258 #if defined(__MACH__)
1259 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, mach_port_t portSet
) {
1261 const void **list
, *buffer
[256];
1263 // Timers and version 1 sources go into the portSet currently
1264 if (NULL
!= rlm
->_sources
) {
1265 cnt
= CFSetGetCount(rlm
->_sources
);
1266 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1267 CFSetGetValues(rlm
->_sources
, list
);
1268 for (idx
= 0; idx
< cnt
; idx
++) {
1269 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1271 if (1 != rls
->_context
.version0
.version
) continue;
1272 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
1273 if (MACH_PORT_NULL
!= port
) {
1274 mach_port_insert_member(mach_task_self(), port
, portSet
);
1277 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1279 if (NULL
!= rlm
->_timers
) {
1280 cnt
= CFSetGetCount(rlm
->_timers
);
1281 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1282 CFSetGetValues(rlm
->_timers
, list
);
1283 for (idx
= 0; idx
< cnt
; idx
++) {
1284 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1285 if (MACH_PORT_NULL
!= rlt
->_port
) {
1286 mach_port_insert_member(mach_task_self(), rlt
->_port
, portSet
);
1289 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1291 // iterate over submodes
1292 for (idx
= 0, cnt
= NULL
!= rlm
->_submodes
? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1293 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1294 CFRunLoopModeRef subrlm
;
1295 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1296 if (NULL
!= subrlm
) {
1297 __CFRunLoopModeAddPortsToPortSet(rl
, subrlm
, portSet
);
1298 __CFRunLoopModeUnlock(subrlm
);
1304 /* rl is unlocked, rlm locked on entrance and exit */
1305 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, Boolean waitIfEmpty
) { /* DOES CALLOUT */
1307 #if defined(__MACH__)
1308 mach_port_name_t timeoutPort
= MACH_PORT_NULL
;
1309 Boolean timeoutPortAdded
= false;
1310 #elif defined(__WIN32__)
1311 HANDLE timeoutPort
= NULL
;
1313 Boolean poll
= false;
1315 if (__CFRunLoopIsStopped(rl
)) {
1316 return kCFRunLoopRunStopped
;
1317 } else if (rlm
->_stopped
) {
1318 rlm
->_stopped
= false;
1319 return kCFRunLoopRunStopped
;
1321 #if !defined(__WIN32__)
1322 if (seconds
<= 0.0) {
1324 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < seconds
) {
1325 termTSR
= LLONG_MAX
;
1326 } else if ((uint64_t)LLONG_MAX
<= __CFReadTSR() + (uint64_t)__CFTimeIntervalToTSR(seconds
)) {
1327 termTSR
= LLONG_MAX
;
1329 termTSR
= (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds
);
1330 timeoutPort
= mk_timer_create();
1331 mk_timer_arm(timeoutPort
, __CFUInt64ToAbsoluteTime(termTSR
));
1333 #elif defined(__WIN32__)
1335 //int64_t time = (int64_t)(seconds * -10000000.0);
1336 //timeoutPort = CreateWaitableTimer(NULL,FALSE,NULL);
1337 //SetWaitableTimer(rl->_waitPort, &time, 0, NULL, NULL);
1340 if (seconds
<= 0.0) {
1344 #if defined(__MACH__)
1345 mach_msg_header_t
*msg
;
1347 mach_port_t waitSet
= MACH_PORT_NULL
;
1348 Boolean destroyWaitSet
= false;
1350 CFRunLoopSourceRef rls
;
1351 int32_t returnValue
= 0;
1352 Boolean sourceHandledThisLoop
= false;
1353 uint8_t buffer
[1024 + 80]; // large enough for 1k of inline payload
1355 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
1356 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
1358 sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
1360 if (sourceHandledThisLoop
) {
1365 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
1366 __CFRunLoopSetSleeping(rl
);
1368 #if defined(__MACH__)
1369 if (NULL
!= rlm
->_submodes
) {
1370 // !!! what do we do if this doesn't succeed?
1371 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &waitSet
);
1372 if (KERN_SUCCESS
!= ret
) HALT
;
1373 __CFRunLoopModeUnlock(rlm
);
1374 __CFRunLoopLock(rl
);
1375 __CFRunLoopModeLock(rlm
);
1376 __CFRunLoopModeAddPortsToPortSet(rl
, rlm
, waitSet
);
1377 __CFRunLoopUnlock(rl
);
1378 if (MACH_PORT_NULL
!= timeoutPort
) {
1379 mach_port_insert_member(mach_task_self(), timeoutPort
, waitSet
);
1381 destroyWaitSet
= true;
1383 waitSet
= rlm
->_portSet
;
1384 if (!timeoutPortAdded
&& MACH_PORT_NULL
!= timeoutPort
) {
1385 mach_port_insert_member(mach_task_self(), timeoutPort
, waitSet
);
1386 timeoutPortAdded
= true;
1389 __CFRunLoopModeUnlock(rlm
);
1391 msg
= (mach_msg_header_t
*)buffer
;
1392 msg
->msgh_size
= sizeof(buffer
);
1394 /* In that sleep of death what nightmares may come ... */
1397 msg
->msgh_local_port
= waitSet
;
1398 msg
->msgh_remote_port
= MACH_PORT_NULL
;
1400 #if defined(MACH_RCV_TRAILER_AUDIT)
1401 ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|(poll
? MACH_RCV_TIMEOUT
: 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
), 0, msg
->msgh_size
, waitSet
, 0, MACH_PORT_NULL
);
1403 ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|(poll
? MACH_RCV_TIMEOUT
: 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER
), 0, msg
->msgh_size
, waitSet
, 0, MACH_PORT_NULL
);
1405 if (MACH_RCV_TOO_LARGE
== ret
) {
1406 #if defined(MACH_RCV_TRAILER_AUDIT)
1407 uint32_t newSize
= round_msg(msg
->msgh_size
) + sizeof(mach_msg_audit_trailer_t
);
1409 uint32_t newSize
= round_msg(msg
->msgh_size
) + sizeof(mach_msg_security_trailer_t
);
1411 if (msg
== (mach_msg_header_t
*)buffer
) msg
= NULL
;
1412 msg
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, msg
, newSize
, 0);
1413 msg
->msgh_size
= newSize
;
1415 } else if (MACH_RCV_TIMED_OUT
== ret
) {
1416 // timeout, for poll
1417 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1419 } else if (MACH_MSG_SUCCESS
!= ret
) {
1422 #elif defined(__WIN32__)
1423 // should msgQMask be an OR'ing of this and all submodes' masks?
1424 if (0 == GetQueueStatus(rlm
->_msgQMask
)) {
1426 objects
[0] = rl
->_waitPort
;
1427 //objects[1] = timeoutPort;
1428 MsgWaitForMultipleObjects(1 /*1*/, objects
/*&(rl->_waitPort)*/, false, seconds
, rlm
->_msgQMask
);
1430 ResetEvent(rl
->_waitPort
);
1433 #if defined(__MACH__)
1434 if (destroyWaitSet
) {
1435 __CFClearPortSet(mach_task_self(), waitSet
);
1436 mach_port_destroy(mach_task_self(), waitSet
);
1439 __CFRunLoopLock(rl
);
1440 __CFRunLoopModeLock(rlm
);
1441 __CFRunLoopUnlock(rl
);
1443 __CFRunLoopUnsetSleeping(rl
);
1444 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
1447 __CFRunLoopModeUnlock(rlm
);
1448 __CFRunLoopLock(rl
);
1449 __CFRunLoopModeLock(rlm
);
1451 #if defined(__MACH__)
1453 if (msg
->msgh_local_port
== timeoutPort
) {
1454 returnValue
= kCFRunLoopRunTimedOut
;
1455 __CFRunLoopUnlock(rl
);
1456 } else if (msg
->msgh_local_port
== rl
->_waitPort
) {
1458 __CFRunLoopUnlock(rl
);
1459 } else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, msg
->msgh_local_port
))) {
1460 mach_msg_header_t
*reply
= NULL
;
1461 __CFRunLoopUnlock(rl
);
1462 if (__CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
)) {
1463 sourceHandledThisLoop
= true;
1465 if (NULL
!= reply
) {
1466 ret
= mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
1467 //#warning CF: what should be done with the return value?
1468 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
1471 CFRunLoopTimerRef rlt
;
1472 rlt
= __CFRunLoopModeFindTimerForMachPort(rlm
, msg
->msgh_local_port
);
1473 __CFRunLoopUnlock(rl
);
1475 __CFRunLoopDoTimer(rl
, rlm
, rlt
);
1478 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1480 __CFRunLoopUnlock(rl
);
1484 __CFRunLoopModeUnlock(rlm
); // locks must be taken in order
1485 __CFRunLoopLock(rl
);
1486 __CFRunLoopModeLock(rlm
);
1487 if (sourceHandledThisLoop
&& stopAfterHandle
) {
1488 returnValue
= kCFRunLoopRunHandledSource
;
1489 } else if (0 != returnValue
|| (uint64_t)termTSR
<= __CFReadTSR()) {
1490 returnValue
= kCFRunLoopRunTimedOut
;
1491 } else if (__CFRunLoopIsStopped(rl
)) {
1492 returnValue
= kCFRunLoopRunStopped
;
1493 } else if (rlm
->_stopped
) {
1494 rlm
->_stopped
= false;
1495 returnValue
= kCFRunLoopRunStopped
;
1496 } else if (!waitIfEmpty
&& __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1497 returnValue
= kCFRunLoopRunFinished
;
1499 __CFRunLoopUnlock(rl
);
1500 if (0 != returnValue
) {
1501 #if defined(__MACH__)
1502 if (MACH_PORT_NULL
!= timeoutPort
) {
1503 if (!destroyWaitSet
) mach_port_extract_member(mach_task_self(), timeoutPort
, waitSet
);
1504 mk_timer_destroy(timeoutPort
);
1512 void CFRunLoopRun(void) { /* DOES CALLOUT */
1515 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
1516 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
1519 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1520 CFRunLoopModeRef currentMode
, previousMode
;
1521 CFIndex
*previousStopped
;
1524 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
1525 __CFRunLoopLock(rl
);
1526 currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
1527 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
)) {
1528 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
1529 __CFRunLoopUnlock(rl
);
1530 return kCFRunLoopRunFinished
;
1532 previousStopped
= (CFIndex
*)rl
->_stopped
;
1533 rl
->_stopped
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, 16, 0);
1534 rl
->_stopped
[0] = 0x4346524C;
1535 rl
->_stopped
[1] = 0x4346524C; // 'CFRL'
1536 rl
->_stopped
[2] = 0x00000000; // here the value is stored
1537 rl
->_stopped
[3] = 0x4346524C;
1538 previousMode
= rl
->_currentMode
;
1539 rl
->_currentMode
= currentMode
;
1540 __CFRunLoopUnlock(rl
);
1541 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
1542 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, false);
1543 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
1544 __CFRunLoopModeUnlock(currentMode
);
1545 __CFRunLoopLock(rl
);
1546 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (void *)rl
->_stopped
);
1547 rl
->_stopped
= previousStopped
;
1548 rl
->_currentMode
= previousMode
;
1549 __CFRunLoopUnlock(rl
);
1553 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1554 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
1557 static void __CFRunLoopFindMinTimer(const void *value
, void *ctx
) {
1558 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
1559 CFRunLoopTimerRef
*result
= ctx
;
1560 if (NULL
== *result
|| rlt
->_fireTSR
< (*result
)->_fireTSR
) {
1565 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
1566 CFRunLoopModeRef rlm
;
1567 CFRunLoopTimerRef result
= NULL
;
1568 int64_t fireTime
= 0;
1569 __CFRunLoopLock(rl
);
1570 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1571 __CFRunLoopUnlock(rl
);
1573 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
1574 __CFRunLoopTimerFireTSRLock();
1575 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
1576 fireTime
= result
->_fireTSR
;
1577 __CFRunLoopTimerFireTSRUnlock();
1579 __CFRunLoopModeUnlock(rlm
);
1581 return (0 == fireTime
) ? 0.0 : __CFTSRToAbsoluteTime(fireTime
);
1584 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
1585 return __CFRunLoopIsSleeping(rl
);
1588 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
1589 #if defined(__MACH__)
1591 /* We unconditionally try to send the message, since we don't want
1592 * to lose a wakeup, but the send may fail if there is already a
1593 * wakeup pending, since the queue length is 1. */
1594 ret
= __CFSendTrivialMachMessage(rl
->_waitPort
, 0, MACH_SEND_TIMEOUT
, 0);
1595 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
1599 SetEvent(rl
->_waitPort
);
1603 void CFRunLoopStop(CFRunLoopRef rl
) {
1604 __CFRunLoopLock(rl
);
1605 __CFRunLoopSetStopped(rl
);
1606 __CFRunLoopUnlock(rl
);
1607 CFRunLoopWakeUp(rl
);
1610 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1611 CFRunLoopModeRef rlm
;
1612 __CFRunLoopLock(rl
);
1613 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1614 __CFRunLoopUnlock(rl
);
1616 rlm
->_stopped
= true;
1617 __CFRunLoopModeUnlock(rlm
);
1619 CFRunLoopWakeUp(rl
);
1622 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
1623 CFRunLoopModeRef rlm
;
1624 if (modeName
== kCFRunLoopCommonModes
|| candidateContainedName
== kCFRunLoopCommonModes
) {
1626 } else if (CFEqual(modeName
, candidateContainedName
)) {
1629 __CFRunLoopLock(rl
);
1630 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1631 __CFRunLoopUnlock(rl
);
1633 CFArrayRef submodes
;
1634 if (NULL
== rlm
->_submodes
) {
1635 __CFRunLoopModeUnlock(rlm
);
1638 if (CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), candidateContainedName
)) {
1639 __CFRunLoopModeUnlock(rlm
);
1642 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1643 __CFRunLoopModeUnlock(rlm
);
1644 if (NULL
!= submodes
) {
1646 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1647 CFStringRef subname
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1648 if (_CFRunLoopModeContainsMode(rl
, subname
, candidateContainedName
)) {
1649 CFRelease(submodes
);
1653 CFRelease(submodes
);
1659 CF_EXPORT
void _CFRunLoopAddModeToMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef toModeName
) {
1660 CFRunLoopModeRef rlm
;
1661 if (__CFRunLoopIsDeallocating(rl
)) return;
1662 // should really do a recursive check here, to make sure that a cycle isn't
1663 // introduced; of course, if that happens, you aren't going to get very far.
1664 if (modeName
== kCFRunLoopCommonModes
|| toModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, toModeName
)) {
1667 __CFRunLoopLock(rl
);
1668 rlm
= __CFRunLoopFindMode(rl
, toModeName
, true);
1669 __CFRunLoopUnlock(rl
);
1671 if (NULL
== rlm
->_submodes
) {
1672 rlm
->_submodes
= CFArrayCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeArrayCallBacks
);
1674 if (!CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), modeName
)) {
1675 CFArrayAppendValue(rlm
->_submodes
, modeName
);
1677 __CFRunLoopModeUnlock(rlm
);
1682 CF_EXPORT
void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef fromModeName
) {
1683 CFRunLoopModeRef rlm
;
1684 // should really do a recursive check here, to make sure that a cycle isn't
1685 // introduced; of course, if that happens, you aren't going to get very far.
1686 if (modeName
== kCFRunLoopCommonModes
|| fromModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, fromModeName
)) {
1689 __CFRunLoopLock(rl
);
1690 rlm
= __CFRunLoopFindMode(rl
, fromModeName
, true);
1691 __CFRunLoopUnlock(rl
);
1693 if (NULL
!= rlm
->_submodes
) {
1694 CFIndex idx
, cnt
= CFArrayGetCount(rlm
->_submodes
);
1695 idx
= CFArrayGetFirstIndexOfValue(rlm
->_submodes
, CFRangeMake(0, cnt
), modeName
);
1696 if (0 <= idx
) CFArrayRemoveValueAtIndex(rlm
->_submodes
, idx
);
1698 __CFRunLoopModeUnlock(rlm
);
1703 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
1704 CFRunLoopModeRef rlm
;
1705 Boolean hasValue
= false;
1706 __CFRunLoopLock(rl
);
1707 if (modeName
== kCFRunLoopCommonModes
) {
1708 if (NULL
!= rl
->_commonModeItems
) {
1709 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
1711 __CFRunLoopUnlock(rl
);
1713 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1714 __CFRunLoopUnlock(rl
);
1715 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
1716 hasValue
= CFSetContainsValue(rlm
->_sources
, rls
);
1717 __CFRunLoopModeUnlock(rlm
);
1718 } else if (NULL
!= rlm
) {
1719 __CFRunLoopModeUnlock(rlm
);
1725 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
1726 CFRunLoopModeRef rlm
;
1727 if (__CFRunLoopIsDeallocating(rl
)) return;
1728 if (!__CFIsValid(rls
)) return;
1729 __CFRunLoopLock(rl
);
1730 if (modeName
== kCFRunLoopCommonModes
) {
1731 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1732 if (NULL
== rl
->_commonModeItems
) {
1733 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
1734 _CFSetSetCapacity(rl
->_commonModeItems
, 20);
1736 CFSetAddValue(rl
->_commonModeItems
, rls
);
1737 __CFRunLoopUnlock(rl
);
1739 CFTypeRef context
[2] = {rl
, rls
};
1740 /* add new item to all common-modes */
1741 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
1745 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1746 __CFRunLoopUnlock(rl
);
1747 if (NULL
!= rlm
&& NULL
== rlm
->_sources
) {
1748 rlm
->_sources
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
1749 _CFSetSetCapacity(rlm
->_sources
, 10);
1751 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources
, rls
)) {
1752 CFSetAddValue(rlm
->_sources
, rls
);
1753 __CFRunLoopModeUnlock(rlm
);
1754 __CFRunLoopSourceSchedule(rls
, rl
, rlm
); /* DOES CALLOUT */
1755 } else if (NULL
!= rlm
) {
1756 __CFRunLoopModeUnlock(rlm
);
1761 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
1762 CFRunLoopModeRef rlm
;
1763 __CFRunLoopLock(rl
);
1764 if (modeName
== kCFRunLoopCommonModes
) {
1765 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
1766 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1767 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
1768 __CFRunLoopUnlock(rl
);
1770 CFTypeRef context
[2] = {rl
, rls
};
1771 /* remove new item from all common-modes */
1772 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
1776 __CFRunLoopUnlock(rl
);
1779 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1780 __CFRunLoopUnlock(rl
);
1781 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
&& CFSetContainsValue(rlm
->_sources
, rls
)) {
1783 CFSetRemoveValue(rlm
->_sources
, rls
);
1784 __CFRunLoopModeUnlock(rlm
);
1785 __CFRunLoopSourceCancel(rls
, rl
, rlm
); /* DOES CALLOUT */
1787 } else if (NULL
!= rlm
) {
1788 __CFRunLoopModeUnlock(rlm
);
1793 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
1794 CFRunLoopModeRef rlm
;
1795 Boolean hasValue
= false;
1796 __CFRunLoopLock(rl
);
1797 if (modeName
== kCFRunLoopCommonModes
) {
1798 if (NULL
!= rl
->_commonModeItems
) {
1799 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
1801 __CFRunLoopUnlock(rl
);
1803 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1804 __CFRunLoopUnlock(rl
);
1805 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
1806 hasValue
= CFSetContainsValue(rlm
->_observers
, rlo
);
1807 __CFRunLoopModeUnlock(rlm
);
1808 } else if (NULL
!= rlm
) {
1809 __CFRunLoopModeUnlock(rlm
);
1815 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
1816 CFRunLoopModeRef rlm
;
1817 if (__CFRunLoopIsDeallocating(rl
)) return;
1818 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
1819 __CFRunLoopLock(rl
);
1820 if (modeName
== kCFRunLoopCommonModes
) {
1821 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1822 if (NULL
== rl
->_commonModeItems
) {
1823 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
1825 CFSetAddValue(rl
->_commonModeItems
, rlo
);
1826 __CFRunLoopUnlock(rl
);
1828 CFTypeRef context
[2] = {rl
, rlo
};
1829 /* add new item to all common-modes */
1830 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
1834 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1835 __CFRunLoopUnlock(rl
);
1836 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
1837 rlm
->_observers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
1839 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_observers
, rlo
)) {
1840 CFSetAddValue(rlm
->_observers
, rlo
);
1841 __CFRunLoopModeUnlock(rlm
);
1842 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
1843 } else if (NULL
!= rlm
) {
1844 __CFRunLoopModeUnlock(rlm
);
1849 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
1850 CFRunLoopModeRef rlm
;
1851 __CFRunLoopLock(rl
);
1852 if (modeName
== kCFRunLoopCommonModes
) {
1853 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
1854 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1855 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
1856 __CFRunLoopUnlock(rl
);
1858 CFTypeRef context
[2] = {rl
, rlo
};
1859 /* remove new item from all common-modes */
1860 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
1864 __CFRunLoopUnlock(rl
);
1867 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1868 __CFRunLoopUnlock(rl
);
1869 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
&& CFSetContainsValue(rlm
->_observers
, rlo
)) {
1871 CFSetRemoveValue(rlm
->_observers
, rlo
);
1872 __CFRunLoopModeUnlock(rlm
);
1873 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
1875 } else if (NULL
!= rlm
) {
1876 __CFRunLoopModeUnlock(rlm
);
1881 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
1882 CFRunLoopModeRef rlm
;
1883 Boolean hasValue
= false;
1884 __CFRunLoopLock(rl
);
1885 if (modeName
== kCFRunLoopCommonModes
) {
1886 if (NULL
!= rl
->_commonModeItems
) {
1887 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
1889 __CFRunLoopUnlock(rl
);
1891 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1892 __CFRunLoopUnlock(rl
);
1893 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
1894 hasValue
= CFSetContainsValue(rlm
->_timers
, rlt
);
1895 __CFRunLoopModeUnlock(rlm
);
1896 } else if (NULL
!= rlm
) {
1897 __CFRunLoopModeUnlock(rlm
);
1903 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
1904 CFRunLoopModeRef rlm
;
1905 if (__CFRunLoopIsDeallocating(rl
)) return;
1906 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
1907 __CFRunLoopLock(rl
);
1908 if (modeName
== kCFRunLoopCommonModes
) {
1909 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1910 if (NULL
== rl
->_commonModeItems
) {
1911 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
1913 CFSetAddValue(rl
->_commonModeItems
, rlt
);
1914 __CFRunLoopUnlock(rl
);
1916 CFTypeRef context
[2] = {rl
, rlt
};
1917 /* add new item to all common-modes */
1918 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
1922 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1923 __CFRunLoopUnlock(rl
);
1924 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
1925 rlm
->_timers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
1927 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_timers
, rlt
)) {
1928 CFSetAddValue(rlm
->_timers
, rlt
);
1929 __CFRunLoopModeUnlock(rlm
);
1930 __CFRunLoopTimerSchedule(rlt
, rl
, rlm
);
1931 } else if (NULL
!= rlm
) {
1932 __CFRunLoopModeUnlock(rlm
);
1937 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
1938 CFRunLoopModeRef rlm
;
1939 __CFRunLoopLock(rl
);
1940 if (modeName
== kCFRunLoopCommonModes
) {
1941 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
1942 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
1943 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
1944 __CFRunLoopUnlock(rl
);
1946 CFTypeRef context
[2] = {rl
, rlt
};
1947 /* remove new item from all common-modes */
1948 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
1952 __CFRunLoopUnlock(rl
);
1955 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1956 __CFRunLoopUnlock(rl
);
1957 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
&& CFSetContainsValue(rlm
->_timers
, rlt
)) {
1959 CFSetRemoveValue(rlm
->_timers
, rlt
);
1960 __CFRunLoopModeUnlock(rlm
);
1961 __CFRunLoopTimerCancel(rlt
, rl
, rlm
);
1963 } else if (NULL
!= rlm
) {
1964 __CFRunLoopModeUnlock(rlm
);
1970 /* CFRunLoopSource */
1972 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
1973 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
1974 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
1975 if (rls1
== rls2
) return true;
1976 if (rls1
->_order
!= rls2
->_order
) return false;
1977 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
1978 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
1979 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
1980 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
1981 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
1982 if (rls1
->_context
.version0
.equal
)
1983 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
1984 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
1987 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
1988 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
1989 if (rls
->_context
.version0
.hash
)
1990 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
1991 return (CFHashCode
)rls
->_context
.version0
.info
;
1994 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
1995 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
1997 CFStringRef contextDesc
= NULL
;
1998 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
1999 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
2001 if (NULL
== contextDesc
) {
2002 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource context %p>"), rls
->_context
.version0
.info
);
2004 result
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), rls
->_lock
? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
2005 CFRelease(contextDesc
);
2009 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2010 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2011 CFRunLoopSourceInvalidate(rls
);
2012 if (rls
->_context
.version0
.release
) {
2013 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
2017 static const CFRuntimeClass __CFRunLoopSourceClass
= {
2022 __CFRunLoopSourceDeallocate
,
2023 __CFRunLoopSourceEqual
,
2024 __CFRunLoopSourceHash
,
2026 __CFRunLoopSourceCopyDescription
2029 __private_extern__
void __CFRunLoopSourceInitialize(void) {
2030 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
2033 CFTypeID
CFRunLoopSourceGetTypeID(void) {
2034 return __kCFRunLoopSourceTypeID
;
2037 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
2038 CFRunLoopSourceRef memory
;
2040 if (NULL
== context
) HALT
;
2041 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
2042 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
2043 if (NULL
== memory
) {
2046 __CFSetValid(memory
);
2047 __CFRunLoopSourceUnsetSignaled(memory
);
2050 memory
->_order
= order
;
2051 memory
->_runLoops
= NULL
;
2052 #if defined(__MACH__)
2053 memmove(&memory
->_context
, context
, (0 == context
->version
) ? sizeof(CFRunLoopSourceContext
) : sizeof(CFRunLoopSourceContext1
));
2055 memmove(&memory
->_context
, context
, sizeof(CFRunLoopSourceContext
));
2057 if (context
->retain
) {
2058 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
2063 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
2064 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2068 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
2069 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
2070 CFTypeRef
*params
= context
;
2071 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
2074 if (rl
== params
[1]) return;
2075 array
= CFRunLoopCopyAllModes(rl
);
2076 for (idx
= CFArrayGetCount(array
); idx
--;) {
2077 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2078 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2080 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
2085 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
2086 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2088 __CFRunLoopSourceLock(rls
);
2089 if (__CFIsValid(rls
)) {
2090 __CFUnsetValid(rls
);
2091 if (NULL
!= rls
->_runLoops
) {
2092 CFTypeRef params
[2] = {rls
, NULL
};
2093 CFBagRef bag
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
2094 CFRelease(rls
->_runLoops
);
2095 rls
->_runLoops
= NULL
;
2096 __CFRunLoopSourceUnlock(rls
);
2097 CFBagApplyFunction(bag
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
2100 __CFRunLoopSourceUnlock(rls
);
2102 /* for hashing- and equality-use purposes, can't actually release the context here */
2104 __CFRunLoopSourceUnlock(rls
);
2109 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
2110 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2111 return __CFIsValid(rls
);
2114 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
2115 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2116 #if defined(__MACH__)
2117 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
2118 memmove(context
, &rls
->_context
, (0 == context
->version
) ? sizeof(CFRunLoopSourceContext
) : sizeof(CFRunLoopSourceContext1
));
2120 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2121 memmove(context
, &rls
->_context
, sizeof(CFRunLoopSourceContext
));
2125 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
2126 __CFRunLoopSourceLock(rls
);
2127 if (__CFIsValid(rls
)) {
2128 __CFRunLoopSourceSetSignaled(rls
);
2130 __CFRunLoopSourceUnlock(rls
);
2134 /* CFRunLoopObserver */
2136 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2137 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2139 CFStringRef contextDesc
= NULL
;
2140 __CFRunLoopObserverLock(rlo
);
2141 if (NULL
!= rlo
->_context
.copyDescription
) {
2142 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
2145 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlo
), NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
2147 result
= CFStringCreateWithFormat(CFGetAllocator(rlo
), NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf
, CFGetAllocator(rlo
), rlo
->_lock
? "Yes" : "No", __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, rlo
->_callout
, contextDesc
);
2148 __CFRunLoopObserverUnlock(rlo
);
2149 CFRelease(contextDesc
);
2153 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2154 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2155 CFRunLoopObserverInvalidate(rlo
);
2158 static const CFRuntimeClass __CFRunLoopObserverClass
= {
2160 "CFRunLoopObserver",
2163 __CFRunLoopObserverDeallocate
,
2167 __CFRunLoopObserverCopyDescription
2170 __private_extern__
void __CFRunLoopObserverInitialize(void) {
2171 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
2174 CFTypeID
CFRunLoopObserverGetTypeID(void) {
2175 return __kCFRunLoopObserverTypeID
;
2178 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
2179 CFRunLoopObserverRef memory
;
2181 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
2182 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
2183 if (NULL
== memory
) {
2186 __CFSetValid(memory
);
2187 __CFRunLoopObserverUnsetFiring(memory
);
2189 __CFRunLoopObserverSetRepeats(memory
);
2191 __CFRunLoopObserverUnsetRepeats(memory
);
2194 memory
->_runLoop
= NULL
;
2195 memory
->_rlCount
= 0;
2196 memory
->_activities
= activities
;
2197 memory
->_order
= order
;
2198 memory
->_callout
= callout
;
2200 if (context
->retain
) {
2201 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2203 memory
->_context
.info
= context
->info
;
2205 memory
->_context
.retain
= context
->retain
;
2206 memory
->_context
.release
= context
->release
;
2207 memory
->_context
.copyDescription
= context
->copyDescription
;
2209 memory
->_context
.info
= 0;
2210 memory
->_context
.retain
= 0;
2211 memory
->_context
.release
= 0;
2212 memory
->_context
.copyDescription
= 0;
2217 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
2218 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2219 return rlo
->_activities
;
2222 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
2223 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2227 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
2228 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2229 return __CFRunLoopObserverRepeats(rlo
);
2232 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
2233 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2235 __CFRunLoopObserverLock(rlo
);
2236 if (__CFIsValid(rlo
)) {
2237 CFRunLoopRef rl
= rlo
->_runLoop
;
2238 __CFUnsetValid(rlo
);
2239 __CFRunLoopObserverUnlock(rlo
);
2243 array
= CFRunLoopCopyAllModes(rl
);
2244 for (idx
= CFArrayGetCount(array
); idx
--;) {
2245 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2246 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
2248 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
2251 if (rlo
->_context
.release
)
2252 rlo
->_context
.release(rlo
->_context
.info
); /* CALLOUT */
2253 rlo
->_context
.info
= NULL
;
2255 __CFRunLoopObserverUnlock(rlo
);
2260 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
2261 return __CFIsValid(rlo
);
2264 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
2265 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2266 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2267 *context
= rlo
->_context
;
2270 /* CFRunLoopTimer */
2272 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2273 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2275 CFStringRef contextDesc
= NULL
;
2277 __CFRunLoopTimerFireTSRLock();
2278 fireTime
= rlt
->_fireTSR
;
2279 __CFRunLoopTimerFireTSRUnlock();
2280 __CFRunLoopTimerLock(rlt
);
2281 if (NULL
!= rlt
->_context
.copyDescription
) {
2282 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
2284 if (NULL
== contextDesc
) {
2285 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlt
), NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
2287 result
= CFStringCreateWithFormat(CFGetAllocator(rlt
), NULL
, CFSTR("<CFRunLoopTimer %x [%x]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf
, CFGetAllocator(rlt
), rlt
->_lock
? "Yes" : "No", __CFIsValid(rlt
) ? "Yes" : "No", __CFTSRToTimeInterval(rlt
->_intervalTSR
), __CFTSRToAbsoluteTime(fireTime
), rlt
->_order
, rlt
->_callout
, contextDesc
);
2288 __CFRunLoopTimerUnlock(rlt
);
2289 CFRelease(contextDesc
);
2293 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2294 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2295 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
2298 static const CFRuntimeClass __CFRunLoopTimerClass
= {
2303 __CFRunLoopTimerDeallocate
,
2307 __CFRunLoopTimerCopyDescription
2310 __private_extern__
void __CFRunLoopTimerInitialize(void) {
2311 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
2314 CFTypeID
CFRunLoopTimerGetTypeID(void) {
2315 return __kCFRunLoopTimerTypeID
;
2318 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
2319 CFRunLoopTimerRef memory
;
2321 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
2322 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
2323 if (NULL
== memory
) {
2326 __CFSetValid(memory
);
2327 __CFRunLoopTimerUnsetFiring(memory
);
2329 memory
->_runLoop
= NULL
;
2330 memory
->_rlCount
= 0;
2331 #if defined(__MACH__)
2332 memory
->_port
= MACH_PORT_NULL
;
2334 memory
->_order
= order
;
2335 if (fireDate
< __CFTSRToAbsoluteTime(0)) {
2336 memory
->_fireTSR
= 0;
2337 } else if (__CFTSRToAbsoluteTime(LLONG_MAX
) < fireDate
) {
2338 memory
->_fireTSR
= LLONG_MAX
;
2340 memory
->_fireTSR
= __CFAbsoluteTimeToTSR(fireDate
);
2342 if (interval
<= 0.0) {
2343 memory
->_intervalTSR
= 0;
2344 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < interval
) {
2345 memory
->_intervalTSR
= LLONG_MAX
;
2347 memory
->_intervalTSR
= __CFTimeIntervalToTSR(interval
);
2349 memory
->_callout
= callout
;
2350 if (NULL
!= context
) {
2351 if (context
->retain
) {
2352 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2354 memory
->_context
.info
= context
->info
;
2356 memory
->_context
.retain
= context
->retain
;
2357 memory
->_context
.release
= context
->release
;
2358 memory
->_context
.copyDescription
= context
->copyDescription
;
2360 memory
->_context
.info
= 0;
2361 memory
->_context
.retain
= 0;
2362 memory
->_context
.release
= 0;
2363 memory
->_context
.copyDescription
= 0;
2368 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
2369 int64_t fireTime
, result
= 0;
2370 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, rlt
, "_cffireTime");
2371 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2372 __CFRunLoopTimerFireTSRLock();
2373 fireTime
= rlt
->_fireTSR
;
2374 __CFRunLoopTimerFireTSRUnlock();
2375 __CFRunLoopTimerLock(rlt
);
2376 if (__CFIsValid(rlt
)) {
2379 __CFRunLoopTimerUnlock(rlt
);
2380 return __CFTSRToAbsoluteTime(result
);
2383 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
2384 __CFRunLoopTimerFireTSRLock();
2385 if (fireDate
< __CFTSRToAbsoluteTime(0)) {
2387 } else if (__CFTSRToAbsoluteTime(LLONG_MAX
) < fireDate
) {
2388 rlt
->_fireTSR
= LLONG_MAX
;
2390 rlt
->_fireTSR
= __CFAbsoluteTimeToTSR(fireDate
);
2392 __CFRunLoopTimerFireTSRUnlock();
2393 if (rlt
->_runLoop
!= NULL
) {
2394 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rlt
->_runLoop
);
2398 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
2399 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFTimeInterval
, rlt
, "timeInterval");
2400 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2401 return __CFTSRToTimeInterval(rlt
->_intervalTSR
);
2404 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
2405 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2406 return (0 != rlt
->_intervalTSR
);
2409 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
2410 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFIndex
, rlt
, "order");
2411 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2415 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
2416 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, void, rlt
, "invalidate");
2417 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2419 __CFRunLoopTimerLock(rlt
);
2420 if (__CFIsValid(rlt
)) {
2421 CFRunLoopRef rl
= rlt
->_runLoop
;
2422 void *info
= rlt
->_context
.info
;
2423 __CFUnsetValid(rlt
);
2424 #if defined(__MACH__)
2425 __CFRunLoopTimerPortMapLock();
2426 if (NULL
!= __CFRLTPortMap
) {
2427 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)rlt
->_port
);
2429 __CFRunLoopTimerPortMapUnlock();
2430 mk_timer_destroy(rlt
->_port
);
2431 rlt
->_port
= MACH_PORT_NULL
;
2433 rlt
->_context
.info
= NULL
;
2434 __CFRunLoopTimerUnlock(rlt
);
2438 array
= CFRunLoopCopyAllModes(rl
);
2439 for (idx
= CFArrayGetCount(array
); idx
--;) {
2440 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2441 CFRunLoopRemoveTimer(rl
, rlt
, modeName
);
2443 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
2446 if (NULL
!= rlt
->_context
.release
) {
2447 rlt
->_context
.release(info
); /* CALLOUT */
2450 __CFRunLoopTimerUnlock(rlt
);
2455 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
2456 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, Boolean
, rlt
, "isValid");
2457 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2458 return __CFIsValid(rlt
);
2461 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
2462 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2463 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2464 *context
= rlt
->_context
;
2468 CFRunLoopRef rl
; // not retained
2469 CFStringRef mode
; // not retained
2472 static Boolean
__CFRLPKeyEqual(const void *value1
, const void *value2
) {
2473 const struct rlpair
*s1
= value1
;
2474 const struct rlpair
*s2
= value2
;
2475 return (s1
->rl
== s2
->rl
) && CFEqual(s1
->mode
, s2
->mode
);
2478 static CFHashCode
__CFRLPKeyHash(const void *value
) {
2479 const struct rlpair
*s
= value
;
2480 return (CFHashCode
)s
->rl
+ CFHash(s
->mode
);
2483 static CFSpinLock_t __CFRunLoopPerformLock
= 0;
2484 static CFMutableDictionaryRef __CFRunLoopPerformSources
= NULL
;
2486 struct performentry
{
2487 CFRunLoopPerformCallBack callout
;
2491 struct performinfo
{
2493 CFRunLoopSourceRef source
;
2498 struct performentry
*entries
;
2501 static void __CFRunLoopPerformCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2502 // we don't ever remove the source, so we know the run loop is dying
2503 struct rlpair key
, *pair
;
2504 struct performinfo
*pinfo
= info
;
2505 __CFSpinLock(&__CFRunLoopPerformLock
);
2508 if (CFDictionaryGetKeyIfPresent(__CFRunLoopPerformSources
, &key
, (const void **)&pair
)) {
2509 CFDictionaryRemoveValue(__CFRunLoopPerformSources
, pair
);
2510 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pair
);
2512 CFRunLoopSourceInvalidate(pinfo
->source
);
2513 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pinfo
->entries
);
2514 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pinfo
);
2515 // We can free pinfo here, even though the source isn't freed and still has
2516 // a weak pointer to it, because the hash and equal callbacks of the source
2517 // don't indirect into the info for their operations.
2518 __CFSpinUnlock(&__CFRunLoopPerformLock
);
2521 static void __CFRunLoopPerformPerform(void *info
) {
2522 struct performinfo
*pinfo
= info
;
2523 struct performentry
*entries
;
2525 __CFSpinLock(&(pinfo
->lock
));
2526 entries
= pinfo
->entries
;
2528 pinfo
->entries
= NULL
;
2531 __CFSpinUnlock(&(pinfo
->lock
));
2532 for (idx
= 0; idx
< cnt
; idx
++) {
2533 entries
[idx
].callout(entries
[idx
].info
);
2535 // done with this list
2536 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, entries
);
2537 // don't need to check to see if there's still something in the queue,
2538 // and resignal here, since anything added during the callouts,
2539 // from this or another thread, would have caused resignalling
2542 // retaining and freeing the info pointer and stuff inside is completely
2543 // the caller's (and probably the callout's) responsibility
2544 void _CFRunLoopPerformEnqueue(CFRunLoopRef rl
, CFStringRef mode
, CFRunLoopPerformCallBack callout
, void *info
) {
2545 CFRunLoopSourceContext context
= {0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
2546 CFRunLoopSourceRef source
;
2548 struct performinfo
*pinfo
;
2549 __CFSpinLock(&__CFRunLoopPerformLock
);
2550 if (!__CFRunLoopPerformSources
) {
2551 CFDictionaryKeyCallBacks kcb
= {0, NULL
, NULL
, NULL
, __CFRLPKeyEqual
, __CFRLPKeyHash
};
2552 __CFRunLoopPerformSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kcb
, &kCFTypeDictionaryValueCallBacks
);
2556 if (!CFDictionaryGetValueIfPresent(__CFRunLoopPerformSources
, &key
, (const void **)&source
)) {
2557 struct rlpair
*pair
;
2558 context
.info
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct performinfo
), 0);
2559 pinfo
= context
.info
;
2565 pinfo
->entries
= NULL
;
2566 context
.cancel
= __CFRunLoopPerformCancel
;
2567 context
.perform
= __CFRunLoopPerformPerform
;
2568 source
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &context
);
2569 pair
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(*pair
), 0);
2571 CFDictionarySetValue(__CFRunLoopPerformSources
, pair
, source
);
2572 pinfo
->source
= source
;
2573 CFRunLoopAddSource(rl
, source
, mode
);
2576 CFRunLoopSourceGetContext(source
, &context
);
2577 pinfo
= context
.info
;
2579 __CFSpinLock(&(pinfo
->lock
));
2580 __CFSpinUnlock(&__CFRunLoopPerformLock
);
2581 if (pinfo
->count
== pinfo
->size
) {
2582 pinfo
->size
= (0 == pinfo
->size
? 3 : 2 * pinfo
->size
);
2583 pinfo
->entries
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, pinfo
->entries
, pinfo
->size
* sizeof(struct performentry
), 0);
2585 pinfo
->entries
[pinfo
->count
].callout
= callout
;
2586 pinfo
->entries
[pinfo
->count
].info
= info
;
2588 __CFSpinUnlock(&(pinfo
->lock
));
2589 CFRunLoopSourceSignal(source
);
2590 CFRunLoopWakeUp(rl
);