2 * Copyright (c) 2005 Apple Computer, 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@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFRunLoop.h>
29 #include <CoreFoundation/CFSet.h>
30 #include <CoreFoundation/CFBag.h>
31 #include "CFRunLoopPriv.h"
32 #include "CFInternal.h"
37 #include <mach/mach.h>
38 #include <mach/clock_types.h>
39 #include <mach/clock.h>
41 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
42 // With the MS headers, turning off Standard-C gets you macros for stat vs _stat.
43 // Strictly speaking, this is supposed to control traditional vs ANSI C features.
48 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
54 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
56 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
57 // simple abstraction layer spanning Mach ports and Windows HANDLES
60 typedef mach_port_t __CFPort
;
61 #define CFPORT_NULL MACH_PORT_NULL
62 typedef mach_port_t __CFPortSet
;
64 static __CFPort
__CFPortAllocate(void) {
67 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
68 if (KERN_SUCCESS
== ret
) {
69 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
71 if (KERN_SUCCESS
== ret
) {
72 mach_port_limits_t limits
;
73 limits
.mpl_qlimit
= 1;
74 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
76 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
79 CF_INLINE
void __CFPortFree(__CFPort port
) {
80 mach_port_destroy(mach_task_self(), port
);
83 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
85 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
86 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
89 CF_INLINE Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
90 kern_return_t ret
= mach_port_insert_member(mach_task_self(), port
, portSet
);
91 return (KERN_SUCCESS
== ret
);
94 CF_INLINE Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
95 kern_return_t ret
= mach_port_extract_member(mach_task_self(), port
, portSet
);
96 return (KERN_SUCCESS
== ret
);
99 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
101 mach_port_name_array_t array
;
102 mach_msg_type_number_t idx
, number
;
104 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
105 if (KERN_SUCCESS
== ret
) {
106 for (idx
= 0; idx
< number
; idx
++) {
107 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
109 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
111 mach_port_destroy(mach_task_self(), portSet
);
114 #elif defined(__WIN32__)
116 typedef HANDLE __CFPort
;
117 #define CFPORT_NULL NULL
119 // A simple dynamic array of HANDLEs, which grows to a high-water mark
120 typedef struct ___CFPortSet
{
124 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
127 CF_INLINE __CFPort
__CFPortAllocate(void) {
128 return CreateEvent(NULL
, true, false, NULL
);
131 CF_INLINE
void __CFPortFree(__CFPort port
) {
135 static __CFPortSet
__CFPortSetAllocate(void) {
136 __CFPortSet result
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
139 result
->handles
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
144 static void __CFPortSetFree(__CFPortSet portSet
) {
145 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
146 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
149 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
150 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
151 __CFSpinLock(&(portSet
->lock
));
152 __CFPort
*result
= portBuf
;
153 if (bufSize
> portSet
->used
)
154 result
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
155 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
156 *portsUsed
= portSet
->used
;
157 __CFSpinUnlock(&(portSet
->lock
));
161 static Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
162 __CFSpinLock(&(portSet
->lock
));
163 if (portSet
->used
>= portSet
->size
) {
165 portSet
->handles
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
167 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
)
168 CFLog(0, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
169 portSet
->handles
[portSet
->used
++] = port
;
170 __CFSpinUnlock(&(portSet
->lock
));
174 static Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
176 __CFSpinLock(&(portSet
->lock
));
177 for (i
= 0; i
< portSet
->used
; i
++) {
178 if (portSet
->handles
[i
] == port
) {
179 for (j
= i
+1; j
< portSet
->used
; j
++) {
180 portSet
->handles
[j
-1] = portSet
->handles
[j
];
183 __CFSpinUnlock(&(portSet
->lock
));
187 __CFSpinUnlock(&(portSet
->lock
));
193 #if defined(__MACH__)
194 extern mach_port_name_t
mk_timer_create(void);
195 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
196 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
197 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
199 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
202 a
.lo
= x
& (int64_t)0xFFFFFFFF;
206 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
207 kern_return_t result
;
208 mach_msg_header_t header
;
209 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
210 header
.msgh_size
= sizeof(mach_msg_header_t
);
211 header
.msgh_remote_port
= port
;
212 header
.msgh_local_port
= MACH_PORT_NULL
;
213 header
.msgh_id
= msg_id
;
214 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
215 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
220 /* unlock a run loop and modes before doing callouts/sleeping */
221 /* never try to take the run loop lock with a mode locked */
222 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
223 /* run loop mode structures should never be deallocated, even if they become empty */
225 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
226 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
227 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
228 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
229 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
231 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
233 struct __CFRunLoopMode
{
235 CFSpinLock_t _lock
; /* must have the run loop locked before locking this */
239 CFMutableSetRef _sources
;
240 CFMutableSetRef _observers
;
241 CFMutableSetRef _timers
;
242 CFMutableArrayRef _submodes
; // names of the submodes
243 __CFPortSet _portSet
;
244 #if defined(__MACH__)
247 #if defined(__WIN32__)
252 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
);
254 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
255 __CFSpinLock(&(rlm
->_lock
));
258 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
259 __CFSpinUnlock(&(rlm
->_lock
));
262 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
263 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
264 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
265 return CFEqual(rlm1
->_name
, rlm2
->_name
);
268 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
269 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
270 return CFHash(rlm
->_name
);
273 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
274 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
275 CFMutableStringRef result
;
276 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
277 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, rlm
->_lock
? "true" : "false");
278 #if defined(__MACH__)
279 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p,"), rlm
->_portSet
);
281 #if defined(__WIN32__)
282 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p,"), rlm
->_msgQMask
);
284 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm
->_sources
, rlm
->_observers
, rlm
->_timers
);
288 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
289 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
290 if (NULL
!= rlm
->_sources
) CFRelease(rlm
->_sources
);
291 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
292 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
293 if (NULL
!= rlm
->_submodes
) CFRelease(rlm
->_submodes
);
294 CFRelease(rlm
->_name
);
295 __CFPortSetFree(rlm
->_portSet
);
296 #if defined(__MACH__)
297 if (-1 != rlm
->_kq
) close(rlm
->_kq
);
303 CFSpinLock_t _lock
; /* locked for accessing mode list */
304 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
305 volatile CFIndex
*_stopped
;
306 CFMutableSetRef _commonModes
;
307 CFMutableSetRef _commonModeItems
;
308 CFRunLoopModeRef _currentMode
;
309 CFMutableSetRef _modes
;
312 /* Bit 0 of the base reserved bits is used for stopped state */
313 /* Bit 1 of the base reserved bits is used for sleeping state */
314 /* Bit 2 of the base reserved bits is used for deallocating state */
316 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
317 return (rl
->_stopped
&& rl
->_stopped
[2]) ? true : false;
320 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
321 if (rl
->_stopped
) rl
->_stopped
[2] = 0x53544F50; // 'STOP'
324 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
325 if (rl
->_stopped
) rl
->_stopped
[2] = 0x0;
328 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
329 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_info
, 1, 1);
332 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
333 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 1, 1, 1);
336 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
337 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 1, 1, 0);
340 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
341 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_info
, 2, 2);
344 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
345 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_info
, 2, 2, 1);
348 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
349 __CFSpinLock(&(((CFRunLoopRef
)rl
)->_lock
));
352 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
353 __CFSpinUnlock(&(((CFRunLoopRef
)rl
)->_lock
));
356 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
357 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
358 CFMutableStringRef result
;
359 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
360 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
->_wakeUpPort
, (rl
->_stopped
&& *(rl
->_stopped
)) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
361 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
365 /* call with rl locked */
366 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
367 CFRunLoopModeRef rlm
;
368 struct __CFRunLoopMode srlm
;
369 srlm
._base
._isa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
370 srlm
._base
._info
= 0;
371 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
372 srlm
._name
= modeName
;
373 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
375 __CFRunLoopModeLock(rlm
);
381 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(CFGetAllocator(rl
), __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
386 rlm
->_name
= CFStringCreateCopy(CFGetAllocator(rlm
), modeName
);
387 rlm
->_stopped
= false;
388 rlm
->_sources
= NULL
;
389 rlm
->_observers
= NULL
;
391 rlm
->_submodes
= NULL
;
392 rlm
->_portSet
= __CFPortSetAllocate();
393 if (CFPORT_NULL
== rlm
->_portSet
) HALT
;
394 if (!__CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
)) HALT
;
395 #if defined(__MACH__)
398 #if defined(__WIN32__)
401 CFSetAddValue(rl
->_modes
, rlm
);
403 __CFRunLoopModeLock(rlm
); /* return mode locked */
408 // expects rl and rlm locked
409 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
410 if (NULL
== rlm
) return true;
411 #if defined(__WIN32__)
412 if (0 != rlm
->_msgQMask
) return false;
414 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
415 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
416 if (NULL
!= rlm
->_submodes
) {
418 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
419 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
420 CFRunLoopModeRef subrlm
;
422 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
423 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
) : true;
424 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
425 if (!subIsEmpty
) return false;
431 #if defined(__WIN32__)
432 DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
433 CFRunLoopModeRef rlm
;
436 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
438 result
= rlm
->_msgQMask
;
439 __CFRunLoopModeUnlock(rlm
);
441 __CFRunLoopUnlock(rl
);
445 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef modeName
) {
446 CFRunLoopModeRef rlm
;
448 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
449 rlm
->_msgQMask
= mask
;
450 __CFRunLoopModeUnlock(rlm
);
451 __CFRunLoopUnlock(rl
);
455 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
457 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
458 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 3, 3);
461 CF_INLINE
void __CFSetValid(void *cf
) {
462 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 3, 3, 1);
465 CF_INLINE
void __CFUnsetValid(void *cf
) {
466 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 3, 3, 0);
469 struct __CFRunLoopSource
{
473 CFIndex _order
; /* immutable */
474 CFMutableBagRef _runLoops
;
476 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
477 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
478 CFRunLoopSourceContext2 version2
; /* immutable, except invalidation */
482 /* Bit 1 of the base reserved bits is used for signaled state */
484 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
485 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
488 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
489 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
492 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
493 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
496 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
497 __CFSpinLock(&(rls
->_lock
));
500 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
501 __CFSpinUnlock(&(rls
->_lock
));
504 /* rlm is not locked */
505 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
506 __CFRunLoopSourceLock(rls
);
507 if (NULL
== rls
->_runLoops
) {
508 // GrP GC: source -> runloop is a WEAK REFERENCE
509 // Use non-scanned memory and non-retaining callbacks.
510 rls
->_runLoops
= CFBagCreateMutable(CF_USING_COLLECTABLE_MEMORY
? kCFAllocatorMallocZone
: CFGetAllocator(rls
), 0, NULL
);
512 CFBagAddValue(rls
->_runLoops
, rl
);
513 __CFRunLoopSourceUnlock(rls
); // have to unlock before the callout -- cannot help clients with safety
514 if (0 == rls
->_context
.version0
.version
) {
515 if (NULL
!= rls
->_context
.version0
.schedule
) {
516 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, rlm
->_name
);
518 } else if (1 == rls
->_context
.version0
.version
) {
519 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
520 if (CFPORT_NULL
!= port
) {
521 __CFPortSetInsert(port
, rlm
->_portSet
);
523 } else if (2 == rls
->_context
.version0
.version
) {
524 #if defined(__MACH__)
525 if (-1 == rlm
->_kq
) {
526 rlm
->_kq
= kqueue_from_portset_np(rlm
->_portSet
);
528 rls
->_context
.version2
.event
.flags
|= EV_ADD
;
529 int ret
= kevent(rlm
->_kq
, &(rls
->_context
.version2
.event
), 1, NULL
, 0, NULL
);
530 rls
->_context
.version2
.event
.flags
&= ~EV_ADD
;
532 CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #1"));
538 /* rlm is not locked */
539 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
540 if (0 == rls
->_context
.version0
.version
) {
541 if (NULL
!= rls
->_context
.version0
.cancel
) {
542 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
544 } else if (1 == rls
->_context
.version0
.version
) {
545 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
546 if (CFPORT_NULL
!= port
) {
547 __CFPortSetRemove(port
, rlm
->_portSet
);
549 } else if (2 == rls
->_context
.version0
.version
) {
550 #if defined(__MACH__)
551 if (-1 == rlm
->_kq
) {
552 rlm
->_kq
= kqueue_from_portset_np(rlm
->_portSet
);
554 rls
->_context
.version2
.event
.flags
|= EV_DELETE
;
555 int ret
= kevent(rlm
->_kq
, &(rls
->_context
.version2
.event
), 1, NULL
, 0, NULL
);
556 rls
->_context
.version2
.event
.flags
&= ~EV_DELETE
;
558 CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #2"));
562 __CFRunLoopSourceLock(rls
);
563 if (NULL
!= rls
->_runLoops
) {
564 CFBagRemoveValue(rls
->_runLoops
, rl
);
566 __CFRunLoopSourceUnlock(rls
);
569 struct __CFRunLoopObserver
{
572 CFRunLoopRef _runLoop
;
574 CFOptionFlags _activities
; /* immutable */
575 CFIndex _order
; /* immutable */
576 CFRunLoopObserverCallBack _callout
; /* immutable */
577 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
580 /* Bit 0 of the base reserved bits is used for firing state */
581 /* Bit 1 of the base reserved bits is used for repeats state */
583 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
584 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_info
, 0, 0);
587 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
588 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 0, 0, 1);
591 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
592 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 0, 0, 0);
595 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
596 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_info
, 1, 1);
599 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
600 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 1, 1, 1);
603 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
604 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_info
, 1, 1, 0);
607 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
608 __CFSpinLock(&(rlo
->_lock
));
611 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
612 __CFSpinUnlock(&(rlo
->_lock
));
615 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
616 __CFRunLoopObserverLock(rlo
);
617 if (0 == rlo
->_rlCount
) {
621 __CFRunLoopObserverUnlock(rlo
);
624 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
625 __CFRunLoopObserverLock(rlo
);
627 if (0 == rlo
->_rlCount
) {
628 rlo
->_runLoop
= NULL
;
630 __CFRunLoopObserverUnlock(rlo
);
633 struct __CFRunLoopTimer
{
636 CFRunLoopRef _runLoop
;
638 #if defined(__MACH__)
639 mach_port_name_t _port
;
641 CFIndex _order
; /* immutable */
642 int64_t _fireTSR
; /* TSR units */
643 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
644 CFRunLoopTimerCallBack _callout
; /* immutable */
645 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
648 /* Bit 0 of the base reserved bits is used for firing state */
649 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
651 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
652 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_info
, 0, 0);
655 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
656 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 0, 0, 1);
659 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
660 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 0, 0, 0);
663 CF_INLINE Boolean
__CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt
) {
664 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_info
, 1, 1);
667 CF_INLINE
void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt
) {
668 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 1, 1, 1);
671 CF_INLINE
void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt
) {
672 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_info
, 1, 1, 0);
675 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
676 __CFSpinLock(&(rlt
->_lock
));
679 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
680 __CFSpinUnlock(&(rlt
->_lock
));
683 static CFSpinLock_t __CFRLTFireTSRLock
= 0;
685 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
686 __CFSpinLock(&__CFRLTFireTSRLock
);
689 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
690 __CFSpinUnlock(&__CFRLTFireTSRLock
);
693 #if defined(__MACH__)
694 static CFMutableDictionaryRef __CFRLTPortMap
= NULL
;
695 static CFSpinLock_t __CFRLTPortMapLock
= 0;
697 CF_INLINE
void __CFRunLoopTimerPortMapLock(void) {
698 __CFSpinLock(&__CFRLTPortMapLock
);
701 CF_INLINE
void __CFRunLoopTimerPortMapUnlock(void) {
702 __CFSpinUnlock(&__CFRLTPortMapLock
);
706 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
707 #if defined(__MACH__)
708 __CFRunLoopTimerLock(rlt
);
709 if (0 == rlt
->_rlCount
) {
711 if (MACH_PORT_NULL
== rlt
->_port
) {
712 rlt
->_port
= mk_timer_create();
714 __CFRunLoopTimerPortMapLock();
715 if (NULL
== __CFRLTPortMap
) {
716 __CFRLTPortMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
718 CFDictionarySetValue(__CFRLTPortMap
, (void *)rlt
->_port
, rlt
);
719 __CFRunLoopTimerPortMapUnlock();
722 mach_port_insert_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
723 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
724 __CFRunLoopTimerUnlock(rlt
);
728 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
729 #if defined(__MACH__)
730 __CFRunLoopTimerLock(rlt
);
731 __CFPortSetRemove(rlt
->_port
, rlm
->_portSet
);
733 if (0 == rlt
->_rlCount
) {
734 __CFRunLoopTimerPortMapLock();
735 if (NULL
!= __CFRLTPortMap
) {
736 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)rlt
->_port
);
738 __CFRunLoopTimerPortMapUnlock();
739 rlt
->_runLoop
= NULL
;
740 mk_timer_cancel(rlt
->_port
, NULL
);
742 __CFRunLoopTimerUnlock(rlt
);
746 // Caller must hold the Timer lock for safety
747 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
) {
748 #if defined(__MACH__)
749 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
753 #if defined(__WIN32__)
755 struct _collectTimersContext
{
756 CFMutableArrayRef results
;
760 static void __CFRunLoopCollectTimers(const void *value
, void *ctx
) {
761 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
762 struct _collectTimersContext
*context
= ctx
;
763 if (rlt
->_fireTSR
<= context
->cutoffTSR
) {
764 if (NULL
== context
->results
)
765 context
->results
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
766 CFArrayAppendValue(context
->results
, rlt
);
770 // RunLoop and RunLoopMode must be locked
771 static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, struct _collectTimersContext
*ctxt
) {
772 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
773 __CFRunLoopTimerFireTSRLock();
774 CFSetApplyFunction(rlm
->_timers
, __CFRunLoopCollectTimers
, ctxt
);
775 __CFRunLoopTimerFireTSRUnlock();
777 if (NULL
!= rlm
->_submodes
) {
779 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
780 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
781 CFRunLoopModeRef subrlm
;
782 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
783 if (NULL
!= subrlm
) {
784 __CFRunLoopTimersToFireRecursive(rl
, subrlm
, ctxt
);
785 __CFRunLoopModeUnlock(subrlm
);
791 // RunLoop and RunLoopMode must be locked
792 static CFArrayRef
__CFRunLoopTimersToFire(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
793 struct _collectTimersContext ctxt
= {NULL
, __CFReadTSR()};
794 __CFRunLoopTimersToFireRecursive(rl
, rlm
, &ctxt
);
801 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
802 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
806 CFRunLoopSourceRef result
;
809 static void __CFRunLoopFindSource(const void *value
, void *ctx
) {
810 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
811 struct _findsource
*context
= (struct _findsource
*)ctx
;
813 if (NULL
!= context
->result
) return;
814 if (1 != rls
->_context
.version0
.version
) return;
815 __CFRunLoopSourceLock(rls
);
816 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
817 if (port
== context
->port
) {
818 context
->result
= rls
;
820 __CFRunLoopSourceUnlock(rls
);
823 // call with rl and rlm locked
824 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
825 struct _findsource context
= {port
, NULL
};
826 if (NULL
!= rlm
->_sources
) {
827 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopFindSource
), &context
);
829 if (NULL
== context
.result
&& NULL
!= rlm
->_submodes
) {
831 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
832 CFRunLoopSourceRef source
= NULL
;
833 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
834 CFRunLoopModeRef subrlm
;
835 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
836 if (NULL
!= subrlm
) {
837 source
= __CFRunLoopModeFindSourceForMachPort(rl
, subrlm
, port
);
838 __CFRunLoopModeUnlock(subrlm
);
840 if (NULL
!= source
) {
841 context
.result
= source
;
846 return context
.result
;
849 #if defined(__MACH__)
850 // call with rl and rlm locked
851 static CFRunLoopTimerRef
__CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm
, __CFPort port
) {
852 CFRunLoopTimerRef result
= NULL
;
853 __CFRunLoopTimerPortMapLock();
854 if (NULL
!= __CFRLTPortMap
) {
855 result
= (CFRunLoopTimerRef
)CFDictionaryGetValue(__CFRLTPortMap
, (void *)port
);
857 __CFRunLoopTimerPortMapUnlock();
862 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
863 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
864 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
866 const void **list
, *buffer
[256];
867 if (NULL
== rlm
->_sources
) return;
868 cnt
= CFSetGetCount(rlm
->_sources
);
869 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
870 CFSetGetValues(rlm
->_sources
, list
);
871 for (idx
= 0; idx
< cnt
; idx
++) {
874 CFSetRemoveAllValues(rlm
->_sources
);
875 for (idx
= 0; idx
< cnt
; idx
++) {
876 __CFRunLoopSourceCancel((CFRunLoopSourceRef
)list
[idx
], rl
, rlm
);
877 CFRelease(list
[idx
]);
879 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
882 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
883 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
884 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
886 const void **list
, *buffer
[256];
887 if (NULL
== rlm
->_observers
) return;
888 cnt
= CFSetGetCount(rlm
->_observers
);
889 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
890 CFSetGetValues(rlm
->_observers
, list
);
891 for (idx
= 0; idx
< cnt
; idx
++) {
894 CFSetRemoveAllValues(rlm
->_observers
);
895 for (idx
= 0; idx
< cnt
; idx
++) {
896 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
897 CFRelease(list
[idx
]);
899 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
902 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
903 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
904 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
906 const void **list
, *buffer
[256];
907 if (NULL
== rlm
->_timers
) return;
908 cnt
= CFSetGetCount(rlm
->_timers
);
909 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
910 CFSetGetValues(rlm
->_timers
, list
);
911 for (idx
= 0; idx
< cnt
; idx
++) {
914 CFSetRemoveAllValues(rlm
->_timers
);
915 for (idx
= 0; idx
< cnt
; idx
++) {
916 __CFRunLoopTimerCancel((CFRunLoopTimerRef
)list
[idx
], rl
, rlm
);
917 CFRelease(list
[idx
]);
919 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
922 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
923 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
924 /* We try to keep the run loop in a valid state as long as possible,
925 since sources may have non-retained references to the run loop.
926 Another reason is that we don't want to lock the run loop for
927 callback reasons, if we can get away without that. We start by
928 eliminating the sources, since they are the most likely to call
929 back into the run loop during their "cancellation". Common mode
930 items will be removed from the mode indirectly by the following
932 __CFRunLoopSetDeallocating(rl
);
933 if (NULL
!= rl
->_modes
) {
934 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
935 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
936 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
939 if (NULL
!= rl
->_commonModeItems
) {
940 CFRelease(rl
->_commonModeItems
);
942 if (NULL
!= rl
->_commonModes
) {
943 CFRelease(rl
->_commonModes
);
945 if (NULL
!= rl
->_modes
) {
946 CFRelease(rl
->_modes
);
948 __CFPortFree(rl
->_wakeUpPort
);
949 rl
->_wakeUpPort
= CFPORT_NULL
;
950 __CFRunLoopUnlock(rl
);
953 static const CFRuntimeClass __CFRunLoopModeClass
= {
958 __CFRunLoopModeDeallocate
,
959 __CFRunLoopModeEqual
,
962 __CFRunLoopModeCopyDescription
965 static const CFRuntimeClass __CFRunLoopClass
= {
970 __CFRunLoopDeallocate
,
974 __CFRunLoopCopyDescription
977 __private_extern__
void __CFRunLoopInitialize(void) {
978 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
979 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
982 CFTypeID
CFRunLoopGetTypeID(void) {
983 return __kCFRunLoopTypeID
;
986 static CFRunLoopRef
__CFRunLoopCreate(void) {
987 CFRunLoopRef loop
= NULL
;
988 CFRunLoopModeRef rlm
;
989 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
990 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
994 loop
->_stopped
= NULL
;
996 loop
->_wakeUpPort
= __CFPortAllocate();
997 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
998 loop
->_commonModes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
999 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
1000 loop
->_commonModeItems
= NULL
;
1001 loop
->_currentMode
= NULL
;
1002 loop
->_modes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
1003 _CFSetSetCapacity(loop
->_modes
, 10);
1004 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
1005 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
1009 #if defined(__MACH__)
1010 // We don't properly call _CFRunLoopSetMain on Win32, so better to cut these routines
1011 // out until they are properly implemented.
1013 static CFRunLoopRef mainLoop
= NULL
;
1014 static int mainLoopPid
= 0;
1015 static CFSpinLock_t mainLoopLock
= 0;
1017 CFRunLoopRef
CFRunLoopGetMain(void) {
1018 __CFSpinLock(&mainLoopLock
);
1019 if (mainLoopPid
!= getpid()) {
1020 // intentionally leak mainLoop so we don't kill any ports in the child
1024 mainLoop
= __CFRunLoopCreate();
1025 mainLoopPid
= getpid();
1027 __CFSpinUnlock(&mainLoopLock
);
1031 static void _CFRunLoopSetMain(CFRunLoopRef rl
) {
1032 if (rl
!= mainLoop
) {
1033 if (rl
) CFRetain(rl
);
1034 // intentionally leak the old main run loop
1035 // if (mainLoop) CFRelease(mainLoop);
1041 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1042 #if defined(__MACH__)
1043 if (pthread_main_np()) {
1044 return CFRunLoopGetMain();
1047 CFRunLoopRef currentLoop
= __CFGetThreadSpecificData_inline()->_runLoop
;
1048 int currentLoopPid
= __CFGetThreadSpecificData_inline()->_runLoop_pid
;
1049 if (currentLoopPid
!= getpid()) {
1050 // intentionally leak currentLoop so we don't kill any ports in the child
1054 currentLoop
= __CFRunLoopCreate();
1055 __CFGetThreadSpecificData_inline()->_runLoop
= currentLoop
;
1056 __CFGetThreadSpecificData_inline()->_runLoop_pid
= getpid();
1061 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1062 #if defined(__MACH__)
1063 if (pthread_main_np()) {
1064 return _CFRunLoopSetMain(rl
);
1067 CFRunLoopRef currentLoop
= __CFGetThreadSpecificData_inline()->_runLoop
;
1068 if (rl
!= currentLoop
) {
1069 if (rl
) CFRetain(rl
);
1070 // intentionally leak old run loop
1071 // if (currentLoop) CFRelease(currentLoop);
1072 __CFGetThreadSpecificData_inline()->_runLoop
= rl
;
1073 __CFGetThreadSpecificData_inline()->_runLoop_pid
= getpid();
1077 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1078 CFStringRef result
= NULL
;
1079 __CFRunLoopLock(rl
);
1080 if (NULL
!= rl
->_currentMode
) {
1081 result
= CFRetain(rl
->_currentMode
->_name
);
1083 __CFRunLoopUnlock(rl
);
1087 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1088 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1089 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1090 CFArrayAppendValue(array
, rlm
->_name
);
1093 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1094 CFMutableArrayRef array
;
1095 __CFRunLoopLock(rl
);
1096 array
= CFArrayCreateMutable(kCFAllocatorDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1097 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1098 __CFRunLoopUnlock(rl
);
1102 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1103 CFTypeRef item
= (CFTypeRef
)value
;
1104 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1105 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1106 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1107 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1108 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1109 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1110 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1111 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1115 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1116 CFStringRef modeName
= (CFStringRef
)value
;
1117 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1118 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1119 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1120 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1121 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1122 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1123 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1124 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1128 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1129 CFStringRef modeName
= (CFStringRef
)value
;
1130 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1131 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1132 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1133 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1134 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1135 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1136 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1137 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1141 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1142 if (__CFRunLoopIsDeallocating(rl
)) return;
1143 __CFRunLoopLock(rl
);
1144 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1145 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1146 CFSetAddValue(rl
->_commonModes
, modeName
);
1147 __CFRunLoopUnlock(rl
);
1149 CFTypeRef context
[2] = {rl
, modeName
};
1150 /* add all common-modes items to new mode */
1151 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1155 __CFRunLoopUnlock(rl
);
1159 static CFComparisonResult
__CFRunLoopObserverComparator(const void *val1
, const void *val2
, void *context
) {
1160 CFRunLoopObserverRef o1
= (CFRunLoopObserverRef
)val1
;
1161 CFRunLoopObserverRef o2
= (CFRunLoopObserverRef
)val2
;
1162 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1163 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1164 return kCFCompareEqualTo
;
1167 struct _collectobs
{
1168 CFRunLoopActivity activity
;
1169 CFMutableArrayRef array
;
1172 static void __CFRunLoopCollectObservers(const void *value
, void *context
) {
1173 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)value
;
1174 struct _collectobs
*info
= (struct _collectobs
*)context
;
1175 if (0 != (rlo
->_activities
& info
->activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1176 CFArrayAppendValue(info
->array
, rlo
);
1180 /* rl is unlocked, rlm is locked on entrance and exit */
1181 /* ALERT: this should collect all the candidate observers from the top level
1182 * and all submodes, recursively, THEN start calling them, in order to obey
1183 * the ordering parameter. */
1184 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1186 CFMutableArrayRef array
;
1187 CFArrayRef submodes
;
1188 struct _collectobs info
;
1190 /* Fire the observers */
1191 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1192 if (NULL
!= rlm
->_observers
) {
1193 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rlm
->_observers
), &kCFTypeArrayCallBacks
);
1195 info
.activity
= activity
;
1196 CFSetApplyFunction(rlm
->_observers
, (__CFRunLoopCollectObservers
), &info
);
1197 cnt
= CFArrayGetCount(array
);
1199 __CFRunLoopModeUnlock(rlm
);
1200 CFArraySortValues(array
, CFRangeMake(0, cnt
), (__CFRunLoopObserverComparator
), NULL
);
1201 for (idx
= 0; idx
< cnt
; idx
++) {
1202 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(array
, idx
);
1203 __CFRunLoopObserverLock(rlo
);
1204 if (__CFIsValid(rlo
)) {
1205 __CFRunLoopObserverUnlock(rlo
);
1206 __CFRunLoopObserverSetFiring(rlo
);
1207 rlo
->_callout(rlo
, activity
, rlo
->_context
.info
); /* CALLOUT */
1208 __CFRunLoopObserverUnsetFiring(rlo
);
1209 if (!__CFRunLoopObserverRepeats(rlo
)) {
1210 CFRunLoopObserverInvalidate(rlo
);
1213 __CFRunLoopObserverUnlock(rlo
);
1216 __CFRunLoopModeLock(rlm
);
1220 if (NULL
!= submodes
) {
1221 __CFRunLoopModeUnlock(rlm
);
1222 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1223 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1224 CFRunLoopModeRef subrlm
;
1225 __CFRunLoopLock(rl
);
1226 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1227 __CFRunLoopUnlock(rl
);
1228 if (NULL
!= subrlm
) {
1229 __CFRunLoopDoObservers(rl
, subrlm
, activity
);
1230 __CFRunLoopModeUnlock(subrlm
);
1233 CFRelease(submodes
);
1234 __CFRunLoopModeLock(rlm
);
1238 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1239 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1240 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1241 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1242 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1243 return kCFCompareEqualTo
;
1246 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1247 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1248 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1249 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1250 if (NULL
== *sources
) {
1251 *sources
= CFRetain(rls
);
1252 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1253 CFTypeRef oldrls
= *sources
;
1254 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1255 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1256 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1259 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1264 /* rl is unlocked, rlm is locked on entrance and exit */
1265 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1266 CFTypeRef sources
= NULL
;
1267 Boolean sourceHandled
= false;
1270 __CFRunLoopModeUnlock(rlm
); // locks have to be taken in order
1271 __CFRunLoopLock(rl
);
1272 __CFRunLoopModeLock(rlm
);
1273 /* Fire the version 0 sources */
1274 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) {
1275 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1277 for (idx
= 0, cnt
= (NULL
!= rlm
->_submodes
) ? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1278 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1279 CFRunLoopModeRef subrlm
;
1280 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1281 if (NULL
!= subrlm
) {
1282 if (NULL
!= subrlm
->_sources
&& 0 < CFSetGetCount(subrlm
->_sources
)) {
1283 CFSetApplyFunction(subrlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1285 __CFRunLoopModeUnlock(subrlm
);
1288 __CFRunLoopUnlock(rl
);
1289 if (NULL
!= sources
) {
1290 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1291 __CFRunLoopModeUnlock(rlm
);
1292 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1293 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1294 __CFRunLoopSourceLock(rls
);
1295 __CFRunLoopSourceUnsetSignaled(rls
);
1296 if (__CFIsValid(rls
)) {
1297 __CFRunLoopSourceUnlock(rls
);
1298 if (NULL
!= rls
->_context
.version0
.perform
) {
1299 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1301 sourceHandled
= true;
1303 __CFRunLoopSourceUnlock(rls
);
1306 cnt
= CFArrayGetCount(sources
);
1307 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1308 for (idx
= 0; idx
< cnt
; idx
++) {
1309 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, idx
);
1310 __CFRunLoopSourceLock(rls
);
1311 __CFRunLoopSourceUnsetSignaled(rls
);
1312 if (__CFIsValid(rls
)) {
1313 __CFRunLoopSourceUnlock(rls
);
1314 if (NULL
!= rls
->_context
.version0
.perform
) {
1315 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1317 sourceHandled
= true;
1319 __CFRunLoopSourceUnlock(rls
);
1321 if (stopAfterHandle
&& sourceHandled
) {
1327 __CFRunLoopModeLock(rlm
);
1329 return sourceHandled
;
1332 // msg, size and reply are unused on Windows
1333 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1334 #if defined(__MACH__)
1335 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1337 ) { /* DOES CALLOUT */
1338 Boolean sourceHandled
= false;
1340 /* Fire a version 1 source */
1342 __CFRunLoopModeUnlock(rlm
);
1343 __CFRunLoopSourceLock(rls
);
1344 if (__CFIsValid(rls
)) {
1345 __CFRunLoopSourceUnsetSignaled(rls
);
1346 __CFRunLoopSourceUnlock(rls
);
1347 if (NULL
!= rls
->_context
.version1
.perform
) {
1348 #if defined(__MACH__)
1349 *reply
= rls
->_context
.version1
.perform(msg
, size
, kCFAllocatorSystemDefault
, rls
->_context
.version1
.info
); /* CALLOUT */
1351 rls
->_context
.version1
.perform(rls
->_context
.version1
.info
); /* CALLOUT */
1354 sourceHandled
= true;
1356 __CFRunLoopSourceUnlock(rls
);
1359 __CFRunLoopModeLock(rlm
);
1360 return sourceHandled
;
1363 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1364 Boolean timerHandled
= false;
1365 int64_t oldFireTSR
= 0;
1369 __CFRunLoopModeUnlock(rlm
);
1370 __CFRunLoopTimerLock(rlt
);
1371 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
1372 __CFRunLoopTimerUnsetDidFire(rlt
);
1373 __CFRunLoopTimerSetFiring(rlt
);
1374 __CFRunLoopTimerUnlock(rlt
);
1375 __CFRunLoopTimerFireTSRLock();
1376 oldFireTSR
= rlt
->_fireTSR
;
1377 __CFRunLoopTimerFireTSRUnlock();
1378 rlt
->_callout(rlt
, rlt
->_context
.info
); /* CALLOUT */
1379 __CFRunLoopTimerUnsetFiring(rlt
);
1380 timerHandled
= true;
1382 // If the timer fires while it is firing in a higher activiation,
1383 // it is not allowed to fire, but we have to remember that fact.
1384 // Later, if the timer's fire date is being handled manually, we
1385 // need to re-arm the kernel timer, since it has possibly already
1386 // fired (this firing which is being skipped, say) and the timer
1387 // will permanently stop if we completely drop this firing.
1388 if (__CFRunLoopTimerIsFiring(rlt
)) __CFRunLoopTimerSetDidFire(rlt
);
1389 __CFRunLoopTimerUnlock(rlt
);
1391 if (__CFIsValid(rlt
) && timerHandled
) {
1392 if (0 == rlt
->_intervalTSR
) {
1393 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1395 /* This is just a little bit tricky: we want to support calling
1396 * CFRunLoopTimerSetNextFireDate() from within the callout and
1397 * honor that new time here if it is a later date, otherwise
1398 * it is completely ignored. */
1399 int64_t currentFireTSR
;
1400 __CFRunLoopTimerFireTSRLock();
1401 currentFireTSR
= rlt
->_fireTSR
;
1402 if (oldFireTSR
< currentFireTSR
) {
1403 /* Next fire TSR was set, and set to a date after the previous
1404 * fire date, so we honor it. */
1405 if (__CFRunLoopTimerDidFire(rlt
)) {
1406 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rl
);
1407 __CFRunLoopTimerUnsetDidFire(rlt
);
1410 if ((uint64_t)LLONG_MAX
<= (uint64_t)oldFireTSR
+ (uint64_t)rlt
->_intervalTSR
) {
1411 currentFireTSR
= LLONG_MAX
;
1413 int64_t currentTSR
= (int64_t)__CFReadTSR();
1414 currentFireTSR
= oldFireTSR
;
1415 while (currentFireTSR
<= currentTSR
) {
1416 currentFireTSR
+= rlt
->_intervalTSR
;
1419 rlt
->_fireTSR
= currentFireTSR
;
1420 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rl
);
1422 __CFRunLoopTimerFireTSRUnlock();
1426 __CFRunLoopModeLock(rlm
);
1427 return timerHandled
;
1430 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1431 CFRunLoopModeRef rlm
;
1432 Boolean result
= false;
1433 __CFRunLoopLock(rl
);
1434 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1435 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1438 __CFRunLoopUnlock(rl
);
1439 if (rlm
) __CFRunLoopModeUnlock(rlm
);
1443 // rl is locked, rlm is locked on entry and exit
1444 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPortSet portSet
) {
1446 const void **list
, *buffer
[256];
1448 // Timers and version 1 sources go into the portSet currently
1449 if (NULL
!= rlm
->_sources
) {
1450 cnt
= CFSetGetCount(rlm
->_sources
);
1451 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1452 CFSetGetValues(rlm
->_sources
, list
);
1453 for (idx
= 0; idx
< cnt
; idx
++) {
1454 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1455 if (1 == rls
->_context
.version0
.version
) {
1456 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1457 if (CFPORT_NULL
!= port
) {
1458 __CFPortSetInsert(port
, portSet
);
1460 } else if (2 == rls
->_context
.version0
.version
) {
1461 #if defined(__MACH__)
1462 int kq
= kqueue_from_portset_np(portSet
);
1463 rls
->_context
.version2
.event
.flags
|= EV_ADD
;
1464 int ret
= kevent(kq
, &(rls
->_context
.version2
.event
), 1, NULL
, 0, NULL
);
1465 rls
->_context
.version2
.event
.flags
&= ~EV_ADD
;
1468 CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #3"));
1473 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1475 #if defined(__MACH__)
1476 if (NULL
!= rlm
->_timers
) {
1477 cnt
= CFSetGetCount(rlm
->_timers
);
1478 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1479 CFSetGetValues(rlm
->_timers
, list
);
1480 for (idx
= 0; idx
< cnt
; idx
++) {
1481 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1482 if (MACH_PORT_NULL
!= rlt
->_port
) {
1483 mach_port_insert_member(mach_task_self(), rlt
->_port
, portSet
);
1486 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1489 // iterate over submodes
1490 for (idx
= 0, cnt
= NULL
!= rlm
->_submodes
? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1491 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1492 CFRunLoopModeRef subrlm
;
1493 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1494 if (NULL
!= subrlm
) {
1495 __CFRunLoopModeAddPortsToPortSet(rl
, subrlm
, portSet
);
1496 __CFRunLoopModeUnlock(subrlm
);
1501 static __CFPortSet _LastMainWaitSet
= NULL
;
1503 // return NO if we're the main runloop and there are no messages waiting on the port set
1504 int _CFRunLoopInputsReady(void) {
1505 // XXX_PCB: the following 2 lines aren't safe to call during GC, because another
1506 // thread may have entered CFRunLoopGetMain(), which grabs a spink lock, and then
1507 // is suspended by the GC. We can check for the main thread more directly
1508 // by calling pthread_main_np().
1509 // CFRunLoopRef current = CFRunLoopGetMain()
1510 // if (current != CFRunLoopGetMain()) return true;
1511 #if defined(__MACH__)
1512 if (!pthread_main_np()) return true;
1515 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1516 if (_LastMainWaitSet
== MACH_PORT_NULL
) return false;
1518 // prepare a message header with no space for any data, nor a trailer
1519 mach_msg_header_t msg
;
1520 msg
.msgh_size
= sizeof(msg
); // just the header, ma'am
1521 // need the waitset, actually XXX
1522 msg
.msgh_local_port
= _LastMainWaitSet
;
1523 msg
.msgh_remote_port
= MACH_PORT_NULL
;
1526 kern_return_t ret
= mach_msg(&msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
| MACH_RCV_LARGE
, 0, msg
.msgh_size
, _LastMainWaitSet
, 0, MACH_PORT_NULL
);
1528 return (MACH_RCV_TOO_LARGE
== ret
);
1531 /* rl is unlocked, rlm locked on entrance and exit */
1532 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, Boolean waitIfEmpty
) { /* DOES CALLOUT */
1534 #if defined(__MACH__)
1535 mach_port_name_t timeoutPort
= MACH_PORT_NULL
;
1536 Boolean timeoutPortAdded
= false;
1538 Boolean poll
= false;
1539 Boolean firstPass
= true;
1541 if (__CFRunLoopIsStopped(rl
)) {
1542 return kCFRunLoopRunStopped
;
1543 } else if (rlm
->_stopped
) {
1544 rlm
->_stopped
= false;
1545 return kCFRunLoopRunStopped
;
1547 if (seconds
<= 0.0) {
1549 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < seconds
) {
1550 termTSR
= LLONG_MAX
;
1551 } else if ((uint64_t)LLONG_MAX
<= __CFReadTSR() + (uint64_t)__CFTimeIntervalToTSR(seconds
)) {
1552 termTSR
= LLONG_MAX
;
1554 termTSR
= (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds
);
1555 #if defined(__MACH__)
1556 timeoutPort
= mk_timer_create();
1557 mk_timer_arm(timeoutPort
, __CFUInt64ToAbsoluteTime(termTSR
));
1560 if (seconds
<= 0.0) {
1563 if (rl
== mainLoop
) _LastMainWaitSet
= CFPORT_NULL
;
1565 __CFPortSet waitSet
= CFPORT_NULL
;
1566 waitSet
= CFPORT_NULL
;
1567 Boolean destroyWaitSet
= false;
1568 CFRunLoopSourceRef rls
;
1569 #if defined(__MACH__)
1570 mach_msg_header_t
*msg
;
1572 uint8_t buffer
[1024 + 80]; // large enough for 1k of inline payload
1574 CFArrayRef timersToCall
= NULL
;
1576 int32_t returnValue
= 0;
1577 Boolean sourceHandledThisLoop
= false;
1579 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
1580 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
1582 sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
1584 if (sourceHandledThisLoop
) {
1589 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
1590 __CFRunLoopSetSleeping(rl
);
1592 if (NULL
!= rlm
->_submodes
) {
1593 // !!! what do we do if this doesn't succeed?
1594 waitSet
= __CFPortSetAllocate();
1595 if (CFPORT_NULL
== waitSet
) HALT
;
1596 __CFRunLoopModeUnlock(rlm
);
1597 __CFRunLoopLock(rl
);
1598 __CFRunLoopModeLock(rlm
);
1599 __CFRunLoopModeAddPortsToPortSet(rl
, rlm
, waitSet
);
1600 __CFRunLoopUnlock(rl
);
1601 #if defined(__MACH__)
1602 if (CFPORT_NULL
!= timeoutPort
) {
1603 __CFPortSetInsert(timeoutPort
, waitSet
);
1606 destroyWaitSet
= true;
1608 waitSet
= rlm
->_portSet
;
1609 #if defined(__MACH__)
1610 if (!timeoutPortAdded
&& CFPORT_NULL
!= timeoutPort
) {
1611 __CFPortSetInsert(timeoutPort
, waitSet
);
1612 timeoutPortAdded
= true;
1616 if (rl
== mainLoop
) _LastMainWaitSet
= waitSet
;
1617 __CFRunLoopModeUnlock(rlm
);
1619 #if defined(__MACH__)
1620 msg
= (mach_msg_header_t
*)buffer
;
1621 msg
->msgh_size
= sizeof(buffer
);
1623 /* In that sleep of death what nightmares may come ... */
1626 msg
->msgh_local_port
= waitSet
;
1627 msg
->msgh_remote_port
= MACH_PORT_NULL
;
1629 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
);
1630 if (MACH_RCV_TOO_LARGE
== ret
) {
1631 uint32_t newSize
= round_msg(msg
->msgh_size
) + sizeof(mach_msg_audit_trailer_t
);
1632 if (msg
== (mach_msg_header_t
*)buffer
) msg
= NULL
;
1633 msg
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, msg
, newSize
, 0);
1634 msg
->msgh_size
= newSize
;
1636 } else if (MACH_RCV_TIMED_OUT
== ret
) {
1637 // timeout, for poll
1638 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1640 } else if (MACH_MSG_SUCCESS
!= ret
) {
1643 #elif defined(__WIN32__)
1644 __CFRunLoopModeUnlock(rlm
);
1645 DWORD waitResult
= WAIT_TIMEOUT
;
1646 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
1648 uint32_t handleCount
;
1649 Boolean freeHandles
;
1650 if (destroyWaitSet
) {
1651 // wait set is a local, no one else could modify it, no need to copy handles
1652 handles
= waitSet
->handles
;
1653 handleCount
= waitSet
->used
;
1654 freeHandles
= FALSE
;
1656 // copy out the handles to be safe from other threads at work
1657 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
1658 freeHandles
= (handles
!= handleBuf
);
1660 // should msgQMask be an OR'ing of this and all submodes' masks?
1661 if (0 == GetQueueStatus(rlm
->_msgQMask
)) {
1666 int64_t nextStop
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
1669 else if (nextStop
> termTSR
)
1671 // else the next stop is dictated by the next timer
1672 int64_t timeoutTSR
= nextStop
- __CFReadTSR();
1676 CFTimeInterval timeoutCF
= __CFTSRToTimeInterval(timeoutTSR
) * 1000;
1677 if (timeoutCF
> MAXDWORD
)
1680 timeout
= timeoutCF
;
1683 waitResult
= MsgWaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, timeout
, rlm
->_msgQMask
);
1685 ResetEvent(rl
->_wakeUpPort
);
1687 if (destroyWaitSet
) {
1688 __CFPortSetFree(waitSet
);
1689 if (rl
== mainLoop
) _LastMainWaitSet
= NULL
;
1691 __CFRunLoopLock(rl
);
1692 __CFRunLoopModeLock(rlm
);
1693 __CFRunLoopUnlock(rl
);
1695 __CFRunLoopUnsetSleeping(rl
);
1696 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
1699 __CFRunLoopModeUnlock(rlm
);
1700 __CFRunLoopLock(rl
);
1701 __CFRunLoopModeLock(rlm
);
1703 __CFPort livePort
= CFPORT_NULL
;
1704 #if defined(__MACH__)
1706 livePort
= msg
->msgh_local_port
;
1708 #elif defined(__WIN32__)
1709 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
1710 if (waitResult
== WAIT_TIMEOUT
) {
1711 // do nothing, just return to caller
1712 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
1713 // a handle was signaled
1714 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
1715 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
1716 // windows message received - the CFWindowsMessageQueue will pick this up when
1717 // the v0 RunLoopSources get their chance
1718 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
1719 // an "abandoned mutex object"
1720 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
1722 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
1725 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
1726 timersToCall
= __CFRunLoopTimersToFire(rl
, rlm
);
1729 if (CFPORT_NULL
== livePort
) {
1730 __CFRunLoopUnlock(rl
);
1731 #if defined(__MACH__)
1733 // This must be a kevent, msgh_local_port is MACH_PORT_NULL in that case
1734 struct kevent
*kev
= (void *)msg
+ sizeof(mach_msg_header_t
) + ((msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) ? (sizeof(mach_msg_body_t
) + sizeof(mach_msg_descriptor_t
) * ((mach_msg_base_t
*)msg
)->body
.msgh_descriptor_count
) : 0);
1738 /* Fire a version 2 source */
1740 __CFRunLoopModeUnlock(rlm
);
1741 __CFRunLoopSourceLock(rls
);
1742 if (__CFIsValid(rls
)) {
1743 __CFRunLoopSourceUnsetSignaled(rls
);
1744 __CFRunLoopSourceUnlock(rls
);
1745 if (NULL
!= rls
->_context
.version2
.perform
) {
1746 rls
->_context
.version2
.perform(kev
, rls
->_context
.version2
.info
); /* CALLOUT */
1748 sourceHandledThisLoop
= true;
1750 __CFRunLoopSourceUnlock(rls
);
1753 __CFRunLoopModeLock(rlm
);
1756 } else if (livePort
== rl
->_wakeUpPort
) {
1758 __CFRunLoopUnlock(rl
);
1760 #if defined(__MACH__)
1761 else if (livePort
== timeoutPort
) {
1762 returnValue
= kCFRunLoopRunTimedOut
;
1763 __CFRunLoopUnlock(rl
);
1764 } else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
1765 mach_msg_header_t
*reply
= NULL
;
1766 __CFRunLoopUnlock(rl
);
1767 if (__CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
)) {
1768 sourceHandledThisLoop
= true;
1770 if (NULL
!= reply
) {
1771 ret
= mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
1772 //#warning CF: what should be done with the return value?
1773 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
1776 CFRunLoopTimerRef rlt
;
1777 rlt
= __CFRunLoopModeFindTimerForMachPort(rlm
, livePort
);
1778 __CFRunLoopUnlock(rl
);
1780 __CFRunLoopDoTimer(rl
, rlm
, rlt
);
1783 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1785 else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
1786 __CFRunLoopUnlock(rl
);
1787 if (__CFRunLoopDoSource1(rl
, rlm
, rls
)) {
1788 sourceHandledThisLoop
= true;
1793 #if defined(__WIN32__)
1794 if (NULL
!= timersToCall
) {
1796 for (i
= CFArrayGetCount(timersToCall
)-1; i
>= 0; i
--)
1797 __CFRunLoopDoTimer(rl
, rlm
, (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timersToCall
, i
));
1798 CFRelease(timersToCall
);
1802 __CFRunLoopModeUnlock(rlm
); // locks must be taken in order
1803 __CFRunLoopLock(rl
);
1804 __CFRunLoopModeLock(rlm
);
1805 if (sourceHandledThisLoop
&& stopAfterHandle
) {
1806 returnValue
= kCFRunLoopRunHandledSource
;
1807 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
1808 // internal wakeup signal on the first look at the portset, we'll go around the loop one
1809 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
1810 } else if (0 != returnValue
|| (uint64_t)termTSR
<= __CFReadTSR()) {
1811 returnValue
= kCFRunLoopRunTimedOut
;
1812 } else if (__CFRunLoopIsStopped(rl
)) {
1813 returnValue
= kCFRunLoopRunStopped
;
1814 } else if (rlm
->_stopped
) {
1815 rlm
->_stopped
= false;
1816 returnValue
= kCFRunLoopRunStopped
;
1817 } else if (!waitIfEmpty
&& __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1818 returnValue
= kCFRunLoopRunFinished
;
1820 __CFRunLoopUnlock(rl
);
1821 if (0 != returnValue
) {
1822 #if defined(__MACH__)
1823 if (MACH_PORT_NULL
!= timeoutPort
) {
1824 if (!destroyWaitSet
) __CFPortSetRemove(timeoutPort
, waitSet
);
1825 mk_timer_destroy(timeoutPort
);
1834 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1835 CFRunLoopModeRef currentMode
, previousMode
;
1836 CFIndex
*previousStopped
;
1839 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
1840 __CFRunLoopLock(rl
);
1841 currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
1842 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
)) {
1843 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
1844 __CFRunLoopUnlock(rl
);
1845 return kCFRunLoopRunFinished
;
1847 // We can drop the volatile-ness for the previousStopped ptr
1848 previousStopped
= (CFIndex
*)rl
->_stopped
;
1849 rl
->_stopped
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, 16, 0);
1850 rl
->_stopped
[0] = 0x4346524C;
1851 rl
->_stopped
[1] = 0x4346524C; // 'CFRL'
1852 rl
->_stopped
[2] = 0x00000000; // here the value is stored
1853 rl
->_stopped
[3] = 0x4346524C;
1854 previousMode
= rl
->_currentMode
;
1855 rl
->_currentMode
= currentMode
;
1856 __CFRunLoopUnlock(rl
);
1857 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
1858 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, false);
1859 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
1860 __CFRunLoopModeUnlock(currentMode
);
1861 __CFRunLoopLock(rl
);
1862 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (CFIndex
*)rl
->_stopped
);
1863 rl
->_stopped
= previousStopped
;
1864 rl
->_currentMode
= previousMode
;
1865 __CFRunLoopUnlock(rl
);
1869 void CFRunLoopRun(void) { /* DOES CALLOUT */
1872 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
1873 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
1876 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1877 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
1880 static void __CFRunLoopFindMinTimer(const void *value
, void *ctx
) {
1881 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
1882 if (__CFIsValid(rlt
)) {
1883 CFRunLoopTimerRef
*result
= ctx
;
1884 if (NULL
== *result
|| rlt
->_fireTSR
< (*result
)->_fireTSR
) {
1890 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1891 CFRunLoopTimerRef result
= NULL
;
1892 int64_t fireTime
= 0;
1894 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
1895 __CFRunLoopTimerFireTSRLock();
1896 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
1898 fireTime
= result
->_fireTSR
;
1899 __CFRunLoopTimerFireTSRUnlock();
1901 if (NULL
!= rlm
->_submodes
) {
1903 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
1904 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1905 CFRunLoopModeRef subrlm
;
1906 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1907 if (NULL
!= subrlm
) {
1908 int64_t newFireTime
= __CFRunLoopGetNextTimerFireTSR(rl
, subrlm
);
1909 __CFRunLoopModeUnlock(subrlm
);
1910 if (fireTime
== 0 || (newFireTime
!= 0 && newFireTime
< fireTime
))
1911 fireTime
= newFireTime
;
1915 __CFRunLoopModeUnlock(rlm
);
1920 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
1921 CFRunLoopModeRef rlm
;
1923 __CFRunLoopLock(rl
);
1924 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1925 __CFRunLoopUnlock(rl
);
1926 fireTSR
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
1927 int64_t now2
= (int64_t)mach_absolute_time();
1928 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
1929 return (0 == fireTSR
) ? 0.0 : (now1
+ __CFTSRToTimeInterval(fireTSR
- now2
));
1932 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
1933 return __CFRunLoopIsSleeping(rl
);
1936 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
1937 #if defined(__MACH__)
1939 /* We unconditionally try to send the message, since we don't want
1940 * to lose a wakeup, but the send may fail if there is already a
1941 * wakeup pending, since the queue length is 1. */
1942 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
1943 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
1947 SetEvent(rl
->_wakeUpPort
);
1951 void CFRunLoopStop(CFRunLoopRef rl
) {
1952 __CFRunLoopLock(rl
);
1953 __CFRunLoopSetStopped(rl
);
1954 __CFRunLoopUnlock(rl
);
1955 CFRunLoopWakeUp(rl
);
1958 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1959 CFRunLoopModeRef rlm
;
1960 __CFRunLoopLock(rl
);
1961 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1962 __CFRunLoopUnlock(rl
);
1964 rlm
->_stopped
= true;
1965 __CFRunLoopModeUnlock(rlm
);
1967 CFRunLoopWakeUp(rl
);
1970 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
1971 CFRunLoopModeRef rlm
;
1972 if (modeName
== kCFRunLoopCommonModes
|| candidateContainedName
== kCFRunLoopCommonModes
) {
1974 } else if (CFEqual(modeName
, candidateContainedName
)) {
1977 __CFRunLoopLock(rl
);
1978 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1979 __CFRunLoopUnlock(rl
);
1981 CFArrayRef submodes
;
1982 if (NULL
== rlm
->_submodes
) {
1983 __CFRunLoopModeUnlock(rlm
);
1986 if (CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), candidateContainedName
)) {
1987 __CFRunLoopModeUnlock(rlm
);
1990 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1991 __CFRunLoopModeUnlock(rlm
);
1992 if (NULL
!= submodes
) {
1994 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1995 CFStringRef subname
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1996 if (_CFRunLoopModeContainsMode(rl
, subname
, candidateContainedName
)) {
1997 CFRelease(submodes
);
2001 CFRelease(submodes
);
2007 CF_EXPORT
void _CFRunLoopAddModeToMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef toModeName
) {
2008 CFRunLoopModeRef rlm
;
2009 if (__CFRunLoopIsDeallocating(rl
)) return;
2010 // should really do a recursive check here, to make sure that a cycle isn't
2011 // introduced; of course, if that happens, you aren't going to get very far.
2012 if (modeName
== kCFRunLoopCommonModes
|| toModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, toModeName
)) {
2015 __CFRunLoopLock(rl
);
2016 rlm
= __CFRunLoopFindMode(rl
, toModeName
, true);
2017 __CFRunLoopUnlock(rl
);
2019 if (NULL
== rlm
->_submodes
) {
2020 rlm
->_submodes
= CFArrayCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeArrayCallBacks
);
2022 if (!CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), modeName
)) {
2023 CFArrayAppendValue(rlm
->_submodes
, modeName
);
2025 __CFRunLoopModeUnlock(rlm
);
2030 CF_EXPORT
void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef fromModeName
) {
2031 CFRunLoopModeRef rlm
;
2032 // should really do a recursive check here, to make sure that a cycle isn't
2033 // introduced; of course, if that happens, you aren't going to get very far.
2034 if (modeName
== kCFRunLoopCommonModes
|| fromModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, fromModeName
)) {
2037 __CFRunLoopLock(rl
);
2038 rlm
= __CFRunLoopFindMode(rl
, fromModeName
, true);
2039 __CFRunLoopUnlock(rl
);
2041 if (NULL
!= rlm
->_submodes
) {
2042 CFIndex idx
, cnt
= CFArrayGetCount(rlm
->_submodes
);
2043 idx
= CFArrayGetFirstIndexOfValue(rlm
->_submodes
, CFRangeMake(0, cnt
), modeName
);
2044 if (0 <= idx
) CFArrayRemoveValueAtIndex(rlm
->_submodes
, idx
);
2046 __CFRunLoopModeUnlock(rlm
);
2051 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2052 CFRunLoopModeRef rlm
;
2053 Boolean hasValue
= false;
2054 __CFRunLoopLock(rl
);
2055 if (modeName
== kCFRunLoopCommonModes
) {
2056 if (NULL
!= rl
->_commonModeItems
) {
2057 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2059 __CFRunLoopUnlock(rl
);
2061 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2062 __CFRunLoopUnlock(rl
);
2063 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2064 hasValue
= CFSetContainsValue(rlm
->_sources
, rls
);
2065 __CFRunLoopModeUnlock(rlm
);
2066 } else if (NULL
!= rlm
) {
2067 __CFRunLoopModeUnlock(rlm
);
2073 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2074 CFRunLoopModeRef rlm
;
2075 if (__CFRunLoopIsDeallocating(rl
)) return;
2076 if (!__CFIsValid(rls
)) return;
2077 __CFRunLoopLock(rl
);
2078 if (modeName
== kCFRunLoopCommonModes
) {
2079 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2080 if (NULL
== rl
->_commonModeItems
) {
2081 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2082 _CFSetSetCapacity(rl
->_commonModeItems
, 20);
2084 CFSetAddValue(rl
->_commonModeItems
, rls
);
2085 __CFRunLoopUnlock(rl
);
2087 CFTypeRef context
[2] = {rl
, rls
};
2088 /* add new item to all common-modes */
2089 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2093 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2094 __CFRunLoopUnlock(rl
);
2095 if (NULL
!= rlm
&& NULL
== rlm
->_sources
) {
2096 rlm
->_sources
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2097 _CFSetSetCapacity(rlm
->_sources
, 10);
2099 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources
, rls
)) {
2100 CFSetAddValue(rlm
->_sources
, rls
);
2101 __CFRunLoopModeUnlock(rlm
);
2102 __CFRunLoopSourceSchedule(rls
, rl
, rlm
); /* DOES CALLOUT */
2103 } else if (NULL
!= rlm
) {
2104 __CFRunLoopModeUnlock(rlm
);
2109 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2110 CFRunLoopModeRef rlm
;
2111 __CFRunLoopLock(rl
);
2112 if (modeName
== kCFRunLoopCommonModes
) {
2113 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2114 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2115 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2116 __CFRunLoopUnlock(rl
);
2118 CFTypeRef context
[2] = {rl
, rls
};
2119 /* remove new item from all common-modes */
2120 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2124 __CFRunLoopUnlock(rl
);
2127 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2128 __CFRunLoopUnlock(rl
);
2129 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
&& CFSetContainsValue(rlm
->_sources
, rls
)) {
2131 CFSetRemoveValue(rlm
->_sources
, rls
);
2132 __CFRunLoopModeUnlock(rlm
);
2133 __CFRunLoopSourceCancel(rls
, rl
, rlm
); /* DOES CALLOUT */
2135 } else if (NULL
!= rlm
) {
2136 __CFRunLoopModeUnlock(rlm
);
2141 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2142 CFRunLoopModeRef rlm
;
2143 Boolean hasValue
= false;
2144 __CFRunLoopLock(rl
);
2145 if (modeName
== kCFRunLoopCommonModes
) {
2146 if (NULL
!= rl
->_commonModeItems
) {
2147 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2149 __CFRunLoopUnlock(rl
);
2151 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2152 __CFRunLoopUnlock(rl
);
2153 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2154 hasValue
= CFSetContainsValue(rlm
->_observers
, rlo
);
2155 __CFRunLoopModeUnlock(rlm
);
2156 } else if (NULL
!= rlm
) {
2157 __CFRunLoopModeUnlock(rlm
);
2163 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2164 CFRunLoopModeRef rlm
;
2165 if (__CFRunLoopIsDeallocating(rl
)) return;
2166 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2167 __CFRunLoopLock(rl
);
2168 if (modeName
== kCFRunLoopCommonModes
) {
2169 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2170 if (NULL
== rl
->_commonModeItems
) {
2171 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2173 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2174 __CFRunLoopUnlock(rl
);
2176 CFTypeRef context
[2] = {rl
, rlo
};
2177 /* add new item to all common-modes */
2178 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2182 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2183 __CFRunLoopUnlock(rl
);
2184 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2185 rlm
->_observers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2187 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_observers
, rlo
)) {
2188 CFSetAddValue(rlm
->_observers
, rlo
);
2189 __CFRunLoopModeUnlock(rlm
);
2190 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
2191 } else if (NULL
!= rlm
) {
2192 __CFRunLoopModeUnlock(rlm
);
2197 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2198 CFRunLoopModeRef rlm
;
2199 __CFRunLoopLock(rl
);
2200 if (modeName
== kCFRunLoopCommonModes
) {
2201 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
2202 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2203 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
2204 __CFRunLoopUnlock(rl
);
2206 CFTypeRef context
[2] = {rl
, rlo
};
2207 /* remove new item from all common-modes */
2208 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2212 __CFRunLoopUnlock(rl
);
2215 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2216 __CFRunLoopUnlock(rl
);
2217 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
&& CFSetContainsValue(rlm
->_observers
, rlo
)) {
2219 CFSetRemoveValue(rlm
->_observers
, rlo
);
2220 __CFRunLoopModeUnlock(rlm
);
2221 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
2223 } else if (NULL
!= rlm
) {
2224 __CFRunLoopModeUnlock(rlm
);
2229 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2230 CFRunLoopModeRef rlm
;
2231 Boolean hasValue
= false;
2232 __CFRunLoopLock(rl
);
2233 if (modeName
== kCFRunLoopCommonModes
) {
2234 if (NULL
!= rl
->_commonModeItems
) {
2235 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
2237 __CFRunLoopUnlock(rl
);
2239 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2240 __CFRunLoopUnlock(rl
);
2241 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2242 hasValue
= CFSetContainsValue(rlm
->_timers
, rlt
);
2243 __CFRunLoopModeUnlock(rlm
);
2244 } else if (NULL
!= rlm
) {
2245 __CFRunLoopModeUnlock(rlm
);
2251 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2252 CFRunLoopModeRef rlm
;
2253 if (__CFRunLoopIsDeallocating(rl
)) return;
2254 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
2255 __CFRunLoopLock(rl
);
2256 if (modeName
== kCFRunLoopCommonModes
) {
2257 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2258 if (NULL
== rl
->_commonModeItems
) {
2259 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2261 CFSetAddValue(rl
->_commonModeItems
, rlt
);
2262 __CFRunLoopUnlock(rl
);
2264 CFTypeRef context
[2] = {rl
, rlt
};
2265 /* add new item to all common-modes */
2266 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2270 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2271 __CFRunLoopUnlock(rl
);
2272 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
2273 rlm
->_timers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2275 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_timers
, rlt
)) {
2276 CFSetAddValue(rlm
->_timers
, rlt
);
2277 __CFRunLoopModeUnlock(rlm
);
2278 __CFRunLoopTimerSchedule(rlt
, rl
, rlm
);
2279 } else if (NULL
!= rlm
) {
2280 __CFRunLoopModeUnlock(rlm
);
2285 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2286 CFRunLoopModeRef rlm
;
2287 __CFRunLoopLock(rl
);
2288 if (modeName
== kCFRunLoopCommonModes
) {
2289 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
2290 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2291 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
2292 __CFRunLoopUnlock(rl
);
2294 CFTypeRef context
[2] = {rl
, rlt
};
2295 /* remove new item from all common-modes */
2296 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2300 __CFRunLoopUnlock(rl
);
2303 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2304 __CFRunLoopUnlock(rl
);
2305 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
&& CFSetContainsValue(rlm
->_timers
, rlt
)) {
2307 CFSetRemoveValue(rlm
->_timers
, rlt
);
2308 __CFRunLoopModeUnlock(rlm
);
2309 __CFRunLoopTimerCancel(rlt
, rl
, rlm
);
2311 } else if (NULL
!= rlm
) {
2312 __CFRunLoopModeUnlock(rlm
);
2318 /* CFRunLoopSource */
2320 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
2321 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
2322 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
2323 if (rls1
== rls2
) return true;
2324 if (rls1
->_order
!= rls2
->_order
) return false;
2325 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
2326 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
2327 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
2328 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
2329 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
2330 if (2 == rls1
->_context
.version0
.version
&& rls1
->_context
.version2
.perform
!= rls2
->_context
.version2
.perform
) return false;
2331 if (2 == rls1
->_context
.version0
.version
&& !(rls1
->_context
.version2
.event
.ident
== rls2
->_context
.version2
.event
.ident
&& rls1
->_context
.version2
.event
.filter
== rls2
->_context
.version2
.event
.filter
)) return false;
2332 if (rls1
->_context
.version0
.equal
)
2333 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
2334 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
2337 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
2338 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2339 if (rls
->_context
.version0
.hash
)
2340 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
2341 return (CFHashCode
)rls
->_context
.version0
.info
;
2344 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2345 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2347 CFStringRef contextDesc
= NULL
;
2348 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
2349 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
2351 if (NULL
== contextDesc
) {
2352 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource context %p>"), rls
->_context
.version0
.info
);
2354 result
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signaled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), rls
->_lock
? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
2355 CFRelease(contextDesc
);
2359 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2360 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2361 CFRunLoopSourceInvalidate(rls
);
2362 if (rls
->_context
.version0
.release
) {
2363 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
2367 static const CFRuntimeClass __CFRunLoopSourceClass
= {
2368 _kCFRuntimeScannedObject
,
2372 __CFRunLoopSourceDeallocate
,
2373 __CFRunLoopSourceEqual
,
2374 __CFRunLoopSourceHash
,
2376 __CFRunLoopSourceCopyDescription
2379 __private_extern__
void __CFRunLoopSourceInitialize(void) {
2380 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
2383 CFTypeID
CFRunLoopSourceGetTypeID(void) {
2384 return __kCFRunLoopSourceTypeID
;
2387 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
2388 CFRunLoopSourceRef memory
;
2390 if (NULL
== context
) HALT
;
2391 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
2392 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
2393 if (NULL
== memory
) {
2396 __CFSetValid(memory
);
2397 __CFRunLoopSourceUnsetSignaled(memory
);
2400 memory
->_order
= order
;
2401 memory
->_runLoops
= NULL
;
2403 switch (context
->version
) {
2405 size
= sizeof(CFRunLoopSourceContext
);
2408 size
= sizeof(CFRunLoopSourceContext1
);
2411 size
= sizeof(CFRunLoopSourceContext2
);
2414 CF_WRITE_BARRIER_MEMMOVE(&memory
->_context
, context
, size
);
2415 if (2 == memory
->_context
.version0
.version
) {
2416 memory
->_context
.version2
.event
.udata
= memory
;
2417 memory
->_context
.version2
.event
.flags
&= ~(EV_SYSFLAGS
| 0xFF0F); // clear all but a few flags
2419 if (context
->retain
) {
2420 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
2425 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
2426 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2430 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
2431 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
2432 CFTypeRef
*params
= context
;
2433 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
2436 if (rl
== params
[1]) return;
2437 array
= CFRunLoopCopyAllModes(rl
);
2438 for (idx
= CFArrayGetCount(array
); idx
--;) {
2439 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2440 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2442 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
2447 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
2448 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2450 __CFRunLoopSourceLock(rls
);
2451 if (__CFIsValid(rls
)) {
2452 __CFUnsetValid(rls
);
2453 if (NULL
!= rls
->_runLoops
) {
2454 CFTypeRef params
[2] = {rls
, NULL
};
2455 CFBagRef bag
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
2456 CFRelease(rls
->_runLoops
);
2457 rls
->_runLoops
= NULL
;
2458 __CFRunLoopSourceUnlock(rls
);
2459 CFBagApplyFunction(bag
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
2462 __CFRunLoopSourceUnlock(rls
);
2464 /* for hashing- and equality-use purposes, can't actually release the context here */
2466 __CFRunLoopSourceUnlock(rls
);
2471 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
2472 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2473 return __CFIsValid(rls
);
2476 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
2477 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2478 CFAssert1(0 == context
->version
|| 1 == context
->version
|| 2 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
2480 switch (context
->version
) {
2482 size
= sizeof(CFRunLoopSourceContext
);
2485 size
= sizeof(CFRunLoopSourceContext1
);
2488 size
= sizeof(CFRunLoopSourceContext2
);
2491 memmove(context
, &rls
->_context
, size
);
2494 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
2495 __CFRunLoopSourceLock(rls
);
2496 if (__CFIsValid(rls
)) {
2497 __CFRunLoopSourceSetSignaled(rls
);
2499 __CFRunLoopSourceUnlock(rls
);
2503 /* CFRunLoopObserver */
2505 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2506 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2508 CFStringRef contextDesc
= NULL
;
2509 if (NULL
!= rlo
->_context
.copyDescription
) {
2510 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
2513 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlo
), NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
2515 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
);
2516 CFRelease(contextDesc
);
2520 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2521 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2522 CFRunLoopObserverInvalidate(rlo
);
2525 static const CFRuntimeClass __CFRunLoopObserverClass
= {
2527 "CFRunLoopObserver",
2530 __CFRunLoopObserverDeallocate
,
2534 __CFRunLoopObserverCopyDescription
2537 __private_extern__
void __CFRunLoopObserverInitialize(void) {
2538 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
2541 CFTypeID
CFRunLoopObserverGetTypeID(void) {
2542 return __kCFRunLoopObserverTypeID
;
2545 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
2546 CFRunLoopObserverRef memory
;
2548 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
2549 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
2550 if (NULL
== memory
) {
2553 __CFSetValid(memory
);
2554 __CFRunLoopObserverUnsetFiring(memory
);
2556 __CFRunLoopObserverSetRepeats(memory
);
2558 __CFRunLoopObserverUnsetRepeats(memory
);
2561 memory
->_runLoop
= NULL
;
2562 memory
->_rlCount
= 0;
2563 memory
->_activities
= activities
;
2564 memory
->_order
= order
;
2565 memory
->_callout
= callout
;
2567 if (context
->retain
) {
2568 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2570 memory
->_context
.info
= context
->info
;
2572 memory
->_context
.retain
= context
->retain
;
2573 memory
->_context
.release
= context
->release
;
2574 memory
->_context
.copyDescription
= context
->copyDescription
;
2576 memory
->_context
.info
= 0;
2577 memory
->_context
.retain
= 0;
2578 memory
->_context
.release
= 0;
2579 memory
->_context
.copyDescription
= 0;
2584 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
2585 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2586 return rlo
->_activities
;
2589 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
2590 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2594 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
2595 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2596 return __CFRunLoopObserverRepeats(rlo
);
2599 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
2600 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2602 __CFRunLoopObserverLock(rlo
);
2603 if (__CFIsValid(rlo
)) {
2604 CFRunLoopRef rl
= rlo
->_runLoop
;
2605 __CFUnsetValid(rlo
);
2606 __CFRunLoopObserverUnlock(rlo
);
2610 array
= CFRunLoopCopyAllModes(rl
);
2611 for (idx
= CFArrayGetCount(array
); idx
--;) {
2612 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2613 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
2615 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
2618 if (rlo
->_context
.release
)
2619 rlo
->_context
.release(rlo
->_context
.info
); /* CALLOUT */
2620 rlo
->_context
.info
= NULL
;
2622 __CFRunLoopObserverUnlock(rlo
);
2627 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
2628 return __CFIsValid(rlo
);
2631 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
2632 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2633 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2634 *context
= rlo
->_context
;
2637 /* CFRunLoopTimer */
2639 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2640 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2642 CFStringRef contextDesc
= NULL
;
2644 __CFRunLoopTimerFireTSRLock();
2645 fireTime
= rlt
->_fireTSR
;
2646 __CFRunLoopTimerFireTSRUnlock();
2647 if (NULL
!= rlt
->_context
.copyDescription
) {
2648 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
2650 if (NULL
== contextDesc
) {
2651 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlt
), NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
2653 int64_t now2
= (int64_t)mach_absolute_time();
2654 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2655 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
), now1
+ __CFTSRToTimeInterval(fireTime
- now2
), rlt
->_order
, rlt
->_callout
, contextDesc
);
2656 CFRelease(contextDesc
);
2660 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2661 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2662 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
2665 static const CFRuntimeClass __CFRunLoopTimerClass
= {
2670 __CFRunLoopTimerDeallocate
,
2674 __CFRunLoopTimerCopyDescription
2677 __private_extern__
void __CFRunLoopTimerInitialize(void) {
2678 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
2681 CFTypeID
CFRunLoopTimerGetTypeID(void) {
2682 return __kCFRunLoopTimerTypeID
;
2685 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
2686 CFRunLoopTimerRef memory
;
2688 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
2689 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
2690 if (NULL
== memory
) {
2693 __CFSetValid(memory
);
2694 __CFRunLoopTimerUnsetFiring(memory
);
2695 __CFRunLoopTimerUnsetDidFire(memory
);
2697 memory
->_runLoop
= NULL
;
2698 memory
->_rlCount
= 0;
2699 #if defined(__MACH__)
2700 memory
->_port
= MACH_PORT_NULL
;
2702 memory
->_order
= order
;
2703 int64_t now2
= (int64_t)mach_absolute_time();
2704 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2705 if (fireDate
< now1
) {
2706 memory
->_fireTSR
= now2
;
2707 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
2708 memory
->_fireTSR
= LLONG_MAX
;
2710 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
2712 if (interval
<= 0.0) {
2713 memory
->_intervalTSR
= 0;
2714 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < interval
) {
2715 memory
->_intervalTSR
= LLONG_MAX
;
2717 memory
->_intervalTSR
= __CFTimeIntervalToTSR(interval
);
2719 memory
->_callout
= callout
;
2720 if (NULL
!= context
) {
2721 if (context
->retain
) {
2722 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2724 memory
->_context
.info
= context
->info
;
2726 memory
->_context
.retain
= context
->retain
;
2727 memory
->_context
.release
= context
->release
;
2728 memory
->_context
.copyDescription
= context
->copyDescription
;
2730 memory
->_context
.info
= 0;
2731 memory
->_context
.retain
= 0;
2732 memory
->_context
.release
= 0;
2733 memory
->_context
.copyDescription
= 0;
2738 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
2739 int64_t fireTime
, result
= 0;
2740 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, rlt
, "_cffireTime");
2741 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2742 __CFRunLoopTimerFireTSRLock();
2743 fireTime
= rlt
->_fireTSR
;
2744 __CFRunLoopTimerFireTSRUnlock();
2745 __CFRunLoopTimerLock(rlt
);
2746 if (__CFIsValid(rlt
)) {
2749 __CFRunLoopTimerUnlock(rlt
);
2750 int64_t now2
= (int64_t)mach_absolute_time();
2751 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2752 return (0 == result
) ? 0.0 : now1
+ __CFTSRToTimeInterval(result
- now2
);
2755 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
2756 __CFRunLoopTimerFireTSRLock();
2757 int64_t now2
= (int64_t)mach_absolute_time();
2758 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2759 if (fireDate
< now1
) {
2760 rlt
->_fireTSR
= now2
;
2761 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
2762 rlt
->_fireTSR
= LLONG_MAX
;
2764 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
2766 if (rlt
->_runLoop
!= NULL
) {
2767 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rlt
->_runLoop
);
2769 __CFRunLoopTimerFireTSRUnlock();
2772 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
2773 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFTimeInterval
, rlt
, "timeInterval");
2774 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2775 return __CFTSRToTimeInterval(rlt
->_intervalTSR
);
2778 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
2779 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2780 return (0 != rlt
->_intervalTSR
);
2783 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
2784 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFIndex
, rlt
, "order");
2785 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2789 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
2790 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, void, rlt
, "invalidate");
2791 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2793 __CFRunLoopTimerLock(rlt
);
2794 if (__CFIsValid(rlt
)) {
2795 CFRunLoopRef rl
= rlt
->_runLoop
;
2796 void *info
= rlt
->_context
.info
;
2797 __CFUnsetValid(rlt
);
2798 #if defined(__MACH__)
2799 __CFRunLoopTimerPortMapLock();
2800 if (NULL
!= __CFRLTPortMap
) {
2801 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)rlt
->_port
);
2803 __CFRunLoopTimerPortMapUnlock();
2804 mk_timer_destroy(rlt
->_port
);
2805 rlt
->_port
= MACH_PORT_NULL
;
2807 rlt
->_context
.info
= NULL
;
2808 __CFRunLoopTimerUnlock(rlt
);
2812 array
= CFRunLoopCopyAllModes(rl
);
2813 for (idx
= CFArrayGetCount(array
); idx
--;) {
2814 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2815 CFRunLoopRemoveTimer(rl
, rlt
, modeName
);
2817 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
2820 if (NULL
!= rlt
->_context
.release
) {
2821 rlt
->_context
.release(info
); /* CALLOUT */
2824 __CFRunLoopTimerUnlock(rlt
);
2829 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
2830 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, Boolean
, rlt
, "isValid");
2831 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2832 return __CFIsValid(rlt
);
2835 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
2836 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2837 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2838 *context
= rlt
->_context
;
2842 CFRunLoopRef rl
; // not retained
2843 CFStringRef mode
; // not retained
2846 static Boolean
__CFRLPKeyEqual(const void *value1
, const void *value2
) {
2847 const struct rlpair
*s1
= value1
;
2848 const struct rlpair
*s2
= value2
;
2849 return (s1
->rl
== s2
->rl
) && CFEqual(s1
->mode
, s2
->mode
);
2852 static CFHashCode
__CFRLPKeyHash(const void *value
) {
2853 const struct rlpair
*s
= value
;
2854 return (CFHashCode
)s
->rl
+ CFHash(s
->mode
);
2857 static CFSpinLock_t __CFRunLoopPerformLock
= 0;
2858 static CFMutableDictionaryRef __CFRunLoopPerformSources
= NULL
;
2860 struct performentry
{
2861 CFRunLoopPerformCallBack callout
;
2865 struct performinfo
{
2867 CFRunLoopSourceRef source
;
2872 struct performentry
*entries
;
2875 static void __CFRunLoopPerformCancel(void *info
, CFRunLoopRef rl
, CFStringRef mode
) {
2876 // we don't ever remove the source, so we know the run loop is dying
2877 struct rlpair key
, *pair
;
2878 struct performinfo
*pinfo
= info
;
2879 __CFSpinLock(&__CFRunLoopPerformLock
);
2882 if (CFDictionaryGetKeyIfPresent(__CFRunLoopPerformSources
, &key
, (const void **)&pair
)) {
2883 CFDictionaryRemoveValue(__CFRunLoopPerformSources
, pair
);
2884 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pair
);
2886 CFRunLoopSourceInvalidate(pinfo
->source
);
2887 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pinfo
->entries
);
2888 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, pinfo
);
2889 // We can free pinfo here, even though the source isn't freed and still has
2890 // a weak pointer to it, because the hash and equal callbacks of the source
2891 // don't indirect into the info for their operations.
2892 __CFSpinUnlock(&__CFRunLoopPerformLock
);
2895 static void __CFRunLoopPerformPerform(void *info
) {
2896 struct performinfo
*pinfo
= info
;
2897 struct performentry
*entries
;
2899 __CFSpinLock(&(pinfo
->lock
));
2900 entries
= pinfo
->entries
;
2902 pinfo
->entries
= NULL
;
2905 __CFSpinUnlock(&(pinfo
->lock
));
2906 for (idx
= 0; idx
< cnt
; idx
++) {
2907 entries
[idx
].callout(entries
[idx
].info
);
2909 // done with this list
2910 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, entries
);
2911 // don't need to check to see if there's still something in the queue,
2912 // and resignal here, since anything added during the callouts,
2913 // from this or another thread, would have caused resignalling
2916 // retaining and freeing the info pointer and stuff inside is completely
2917 // the caller's (and probably the callout's) responsibility
2918 void _CFRunLoopPerformEnqueue(CFRunLoopRef rl
, CFStringRef mode
, CFRunLoopPerformCallBack callout
, void *info
) {
2919 CFRunLoopSourceContext context
= {0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
2920 CFRunLoopSourceRef source
;
2922 struct performinfo
*pinfo
;
2923 __CFSpinLock(&__CFRunLoopPerformLock
);
2924 if (!__CFRunLoopPerformSources
) {
2925 CFDictionaryKeyCallBacks kcb
= {0, NULL
, NULL
, NULL
, __CFRLPKeyEqual
, __CFRLPKeyHash
};
2926 __CFRunLoopPerformSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kcb
, &kCFTypeDictionaryValueCallBacks
);
2930 if (!CFDictionaryGetValueIfPresent(__CFRunLoopPerformSources
, &key
, (const void **)&source
)) {
2931 struct rlpair
*pair
;
2932 context
.info
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct performinfo
), 0);
2933 pinfo
= context
.info
;
2939 pinfo
->entries
= NULL
;
2940 context
.cancel
= __CFRunLoopPerformCancel
;
2941 context
.perform
= __CFRunLoopPerformPerform
;
2942 source
= CFRunLoopSourceCreate(kCFAllocatorSystemDefault
, 0, &context
);
2943 pair
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(*pair
), 0);
2945 CFDictionarySetValue(__CFRunLoopPerformSources
, pair
, source
);
2946 pinfo
->source
= source
;
2947 CFRunLoopAddSource(rl
, source
, mode
);
2950 CFRunLoopSourceGetContext(source
, &context
);
2951 pinfo
= context
.info
;
2953 __CFSpinLock(&(pinfo
->lock
));
2954 __CFSpinUnlock(&__CFRunLoopPerformLock
);
2955 if (pinfo
->count
== pinfo
->size
) {
2956 pinfo
->size
= (0 == pinfo
->size
? 3 : 2 * pinfo
->size
);
2957 pinfo
->entries
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, pinfo
->entries
, pinfo
->size
* sizeof(struct performentry
), 0);
2959 pinfo
->entries
[pinfo
->count
].callout
= callout
;
2960 pinfo
->entries
[pinfo
->count
].info
= info
;
2962 __CFSpinUnlock(&(pinfo
->lock
));
2963 CFRunLoopSourceSignal(source
);
2964 CFRunLoopWakeUp(rl
);