2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #include <CoreFoundation/CFRunLoop.h>
30 #include <CoreFoundation/CFSet.h>
31 #include <CoreFoundation/CFBag.h>
32 #include "CFInternal.h"
36 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
37 #include <dispatch/dispatch.h>
38 #include <mach/mach.h>
39 #include <mach/clock_types.h>
40 #include <mach/clock.h>
43 extern mach_port_t
_dispatch_get_main_queue_port_4CF(void);
44 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t
*msg
);
47 #define __CFReadTSR() mach_absolute_time()
51 static int _LogCFRunLoop
= 0;
53 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
54 #define TIMER_DATE_LIMIT 4039289856.0
55 #define TIMER_INTERVAL_LIMIT 504911232.0
57 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
59 #if DEPLOYMENT_TARGET_WINDOWS
60 static pthread_t kNilPthreadT
= { nil
, nil
};
61 #define pthreadPointer(a) a.p
63 static DWORD __CFTSDKeyRunLoopKey
= ~0;
65 // See function below.
66 bool gMARRY_MESSAGE_QUEUE
= FALSE
;
68 // vod __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled)
70 // This function will exist for a while until code is written
71 // by the WebKit folks to handle the new RunLoop message-queue
73 CF_EXPORT
void __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled
) {
74 gMARRY_MESSAGE_QUEUE
= bEnabled
;
76 bool __CFIsNonMachRunLoopMarryMsgQueueEnabled(void) {
77 return gMARRY_MESSAGE_QUEUE
;
82 static pthread_t kNilPthreadT
= (pthread_t
)0;
83 #define pthreadPointer(a) a
84 #define lockCount(a) a
87 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
88 #include <sys/types.h>
89 #include <sys/event.h>
94 const void *(*retain
)(const void *info
);
95 void (*release
)(const void *info
);
96 CFStringRef (*copyDescription
)(const void *info
);
97 Boolean (*equal
)(const void *info1
, const void *info2
);
98 CFHashCode (*hash
)(const void *info
);
99 void (*perform
)(const struct kevent
*kev
, void *info
);
101 } CFRunLoopSourceContext2
;
103 // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR.
104 // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop.
105 // There is no way to EV_ENABLE or EV_DISABLE a kevent.
106 // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet.
107 // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet.
108 // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos).
111 CF_EXPORT
bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
113 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
114 // simple abstraction layer spanning Mach ports and Windows HANDLES
115 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
117 typedef mach_port_t __CFPort
;
118 #define CFPORT_NULL MACH_PORT_NULL
119 typedef mach_port_t __CFPortSet
;
121 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
122 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) { HALT
; };
124 static __CFPort
__CFPortAllocate(void) {
125 __CFPort result
= CFPORT_NULL
;
127 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
128 if (KERN_SUCCESS
== ret
) {
129 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
131 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret
);
133 if (KERN_SUCCESS
== ret
) {
134 mach_port_limits_t limits
;
135 limits
.mpl_qlimit
= 1;
136 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
138 if (KERN_SUCCESS
!= ret
) mach_port_destroy(mach_task_self(), result
);
139 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
142 CF_INLINE
void __CFPortFree(__CFPort port
) {
143 mach_port_destroy(mach_task_self(), port
);
146 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
147 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) { HALT
; };
149 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
151 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
152 if (KERN_SUCCESS
!= ret
) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret
); }
153 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
156 CF_INLINE Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
157 kern_return_t ret
= mach_port_insert_member(mach_task_self(), port
, portSet
);
158 return (KERN_SUCCESS
== ret
);
161 CF_INLINE Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
162 kern_return_t ret
= mach_port_extract_member(mach_task_self(), port
, portSet
);
163 return (KERN_SUCCESS
== ret
);
166 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
168 mach_port_name_array_t array
;
169 mach_msg_type_number_t idx
, number
;
171 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
172 if (KERN_SUCCESS
== ret
) {
173 for (idx
= 0; idx
< number
; idx
++) {
174 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
176 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
178 mach_port_destroy(mach_task_self(), portSet
);
181 #elif DEPLOYMENT_TARGET_WINDOWS
183 typedef HANDLE __CFPort
;
184 #define CFPORT_NULL NULL
186 // A simple dynamic array of HANDLEs, which grows to a high-water mark
187 typedef struct ___CFPortSet
{
191 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
194 CF_INLINE __CFPort
__CFPortAllocate(void) {
195 return CreateEventA(NULL
, true, false, NULL
);
198 CF_INLINE
void __CFPortFree(__CFPort port
) {
202 static __CFPortSet
__CFPortSetAllocate(void) {
203 __CFPortSet result
= (__CFPortSet
)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
206 result
->handles
= (HANDLE
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
207 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
211 static void __CFPortSetFree(__CFPortSet portSet
) {
212 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
213 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
216 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
217 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
218 __CFSpinLock(&(portSet
->lock
));
219 __CFPort
*result
= portBuf
;
220 if (bufSize
< portSet
->used
)
221 result
= (__CFPort
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
222 if (portSet
->used
> 1) {
223 // rotate the ports to vaguely simulate round-robin behaviour
224 uint16_t lastPort
= portSet
->used
- 1;
225 HANDLE swapHandle
= portSet
->handles
[0];
226 memmove(portSet
->handles
, &portSet
->handles
[1], lastPort
* sizeof(HANDLE
));
227 portSet
->handles
[lastPort
] = swapHandle
;
229 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
230 *portsUsed
= portSet
->used
;
231 __CFSpinUnlock(&(portSet
->lock
));
235 static Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
236 __CFSpinLock(&(portSet
->lock
));
237 if (portSet
->used
>= portSet
->size
) {
239 portSet
->handles
= (HANDLE
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
241 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
)
242 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
243 portSet
->handles
[portSet
->used
++] = port
;
244 __CFSpinUnlock(&(portSet
->lock
));
248 static Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
250 __CFSpinLock(&(portSet
->lock
));
251 for (i
= 0; i
< portSet
->used
; i
++) {
252 if (portSet
->handles
[i
] == port
) {
253 for (j
= i
+1; j
< portSet
->used
; j
++) {
254 portSet
->handles
[j
-1] = portSet
->handles
[j
];
257 __CFSpinUnlock(&(portSet
->lock
));
261 __CFSpinUnlock(&(portSet
->lock
));
267 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
268 extern mach_port_name_t
mk_timer_create(void);
269 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
270 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
271 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
273 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
276 a
.lo
= x
& (int64_t)0xFFFFFFFF;
280 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
281 kern_return_t result
;
282 mach_msg_header_t header
;
283 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
284 header
.msgh_size
= sizeof(mach_msg_header_t
);
285 header
.msgh_remote_port
= port
;
286 header
.msgh_local_port
= MACH_PORT_NULL
;
287 header
.msgh_id
= msg_id
;
288 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
289 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
294 /* unlock a run loop and modes before doing callouts/sleeping */
295 /* never try to take the run loop lock with a mode locked */
296 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
297 /* run loop mode structures should never be deallocated, even if they become empty */
299 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
300 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
301 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
302 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
303 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
305 #if DEPLOYMENT_TARGET_WINDOWS
306 // The MSG identifier for the Windows message injected in the message queue to wake the run loop
307 static unsigned int __kCFRunLoopWakeUpMessage
= 0;
308 static unsigned int __kCFRunLoopV1SourceReadyMessage
= 0;
311 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
313 struct __CFRunLoopMode
{
315 CFSpinLock_t _lock
; /* must have the run loop locked before locking this */
319 CFMutableSetRef _sources
;
320 CFMutableSetRef _observers
;
321 CFMutableSetRef _timers
;
322 CFMutableDictionaryRef _portToV1SourceMap
;
323 CFMutableArrayRef _submodes
; // names of the submodes
324 __CFPortSet _portSet
;
325 CFIndex _observerMask
;
326 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
329 #if DEPLOYMENT_TARGET_WINDOWS
334 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
335 __CFSpinLock(&(rlm
->_lock
));
338 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
339 __CFSpinUnlock(&(rlm
->_lock
));
342 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
343 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
344 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
345 return CFEqual(rlm1
->_name
, rlm2
->_name
);
348 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
349 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
350 return CFHash(rlm
->_name
);
353 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
354 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
355 CFMutableStringRef result
;
356 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
357 #if DEPLOYMENT_TARGET_WINDOWS
358 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, "unknown");
360 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, lockCount(rlm
->_lock
) ? "true" : "false");
362 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p,"), rlm
->_portSet
);
363 #if DEPLOYMENT_TARGET_WINDOWS
364 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p,"), rlm
->_msgQMask
);
366 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm
->_sources
, rlm
->_observers
, rlm
->_timers
);
370 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
371 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
372 if (NULL
!= rlm
->_sources
) CFRelease(rlm
->_sources
);
373 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
374 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
375 if (NULL
!= rlm
->_submodes
) CFRelease(rlm
->_submodes
);
376 if (NULL
!= rlm
->_portToV1SourceMap
) CFRelease(rlm
->_portToV1SourceMap
);
377 CFRelease(rlm
->_name
);
378 __CFPortSetFree(rlm
->_portSet
);
379 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
380 if (-1 != rlm
->_kq
) close(rlm
->_kq
);
382 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x7C, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
));
386 struct _block_item
*_next
;
387 CFTypeRef _mode
; // CFString or CFSet or CFRunLoopTimer
388 void (^_block
)(void);
393 CFSpinLock_t _lock
; /* locked for accessing mode list */
394 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
395 volatile uint32_t *_stopped
;
397 CFMutableSetRef _commonModes
;
398 CFMutableSetRef _commonModeItems
;
399 CFRunLoopModeRef _currentMode
;
400 CFMutableSetRef _modes
;
401 struct _block_item
*_blocks_head
;
402 struct _block_item
*_blocks_tail
;
403 #if DEPLOYMENT_TARGET_WINDOWS
405 __CFPort _msgUpdatePort
;
407 CFTypeRef _counterpart
;
410 #if DEPLOYMENT_TARGET_WINDOWS
411 void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl
);
412 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl
);
413 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
);
414 CF_EXPORT LRESULT CALLBACK
pumpRunLoopFromMessageQueue(int nCode
, WPARAM wParam
, LPARAM lParam
);
417 /* Bit 0 of the base reserved bits is used for stopped state */
418 /* Bit 1 of the base reserved bits is used for sleeping state */
419 /* Bit 2 of the base reserved bits is used for deallocating state */
421 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
422 return (rl
->_stopped
&& rl
->_stopped
[2]) ? true : false;
425 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
427 rl
->_stopped
= (uint32_t volatile *)CFAllocatorAllocate(kCFAllocatorSystemDefault
, 4 * sizeof(uint32_t), 0);
428 rl
->_stopped
[0] = 0x4346524C;
429 rl
->_stopped
[1] = 0x4346524C; // 'CFRL'
430 rl
->_stopped
[2] = 0x00000000; // here the value is stored
431 rl
->_stopped
[3] = 0x4346524C;
433 if (rl
->_stopped
) rl
->_stopped
[2] = 0x53544F50; // 'STOP'
436 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
437 if (rl
->_stopped
) rl
->_stopped
[2] = 0x0;
440 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
441 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
444 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
445 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
448 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
449 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
452 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
453 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
456 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
457 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
460 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
461 __CFSpinLock(&(((CFRunLoopRef
)rl
)->_lock
));
464 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
465 __CFSpinUnlock(&(((CFRunLoopRef
)rl
)->_lock
));
468 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
469 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
470 CFMutableStringRef result
;
471 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
472 #if DEPLOYMENT_TARGET_WINDOWS
473 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), "unknown", rl
->_wakeUpPort
, (rl
->_stopped
&& *(rl
->_stopped
)) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
475 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), lockCount(rl
->_lock
) ? "true" : "false", rl
->_wakeUpPort
, (rl
->_stopped
&& (rl
->_stopped
[2] == 0x53544F50)) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
477 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
481 __private_extern__
void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
482 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
485 /* call with rl locked */
486 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
488 CFRunLoopModeRef rlm
;
489 struct __CFRunLoopMode srlm
;
490 memset(&srlm
, 0, sizeof(srlm
));
491 srlm
._base
._cfisa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
492 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
493 srlm
._name
= modeName
;
494 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
496 __CFRunLoopModeLock(rlm
);
502 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
506 CF_SPINLOCK_INIT_FOR_STRUCTS(rlm
->_lock
);
507 rlm
->_name
= CFStringCreateCopy(kCFAllocatorSystemDefault
, modeName
);
508 rlm
->_stopped
= false;
509 rlm
->_portToV1SourceMap
= NULL
;
510 rlm
->_sources
= NULL
;
511 rlm
->_observers
= NULL
;
513 rlm
->_submodes
= NULL
;
514 rlm
->_observerMask
= 0;
515 rlm
->_portSet
= __CFPortSetAllocate();
516 if (!__CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
)) HALT
;
517 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
520 #if DEPLOYMENT_TARGET_WINDOWS
523 CFSetAddValue(rl
->_modes
, rlm
);
525 __CFRunLoopModeLock(rlm
); /* return mode locked */
530 // expects rl and rlm locked
531 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopModeRef previousMode
) {
533 if (NULL
== rlm
) return true;
534 #if DEPLOYMENT_TARGET_WINDOWS
535 if (0 != rlm
->_msgQMask
) return false;
537 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
538 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ
)));
539 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) return false; // represents the libdispatch main queue
541 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
542 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
544 struct _block_item
*item
= rl
->_blocks_head
;
546 struct _block_item
*curr
= item
;
548 Boolean doit
= false;
549 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
550 doit
= CFEqual(curr
->_mode
, rlm
->_name
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
552 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, rlm
->_name
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
554 if (doit
) return false;
557 if (NULL
!= rlm
->_submodes
) {
559 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
560 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
561 CFRunLoopModeRef subrlm
;
563 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
564 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
, previousMode
) : true;
565 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
566 if (!subIsEmpty
) return false;
572 #if DEPLOYMENT_TARGET_WINDOWS
573 DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
574 CFRunLoopModeRef rlm
;
577 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
579 result
= rlm
->_msgQMask
;
580 __CFRunLoopModeUnlock(rlm
);
582 __CFRunLoopUnlock(rl
);
586 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef modeName
) {
587 CFRunLoopModeRef rlm
;
589 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
590 rlm
->_msgQMask
= mask
;
591 __CFRunLoopModeUnlock(rlm
);
592 __CFRunLoopUnlock(rl
);
596 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
598 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
599 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
602 CF_INLINE
void __CFSetValid(void *cf
) {
603 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
606 CF_INLINE
void __CFUnsetValid(void *cf
) {
607 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
610 struct __CFRunLoopSource
{
614 CFIndex _order
; /* immutable */
615 CFMutableBagRef _runLoops
;
617 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
618 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
622 /* Bit 1 of the base reserved bits is used for signalled state */
624 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
625 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
628 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
629 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
632 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
633 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
636 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
637 __CFSpinLock(&(rls
->_lock
));
640 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
641 __CFSpinUnlock(&(rls
->_lock
));
644 /* rlm is not locked */
645 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
646 //printf("Scheduling source %p with mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
647 __CFRunLoopSourceLock(rls
);
648 if (NULL
== rls
->_runLoops
) {
649 rls
->_runLoops
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeBagCallBacks
); // sources retain run loops!
651 CFBagAddValue(rls
->_runLoops
, rl
);
652 __CFRunLoopSourceUnlock(rls
); // have to unlock before the callout -- cannot help clients with safety
653 if (0 == rls
->_context
.version0
.version
) {
654 if (NULL
!= rls
->_context
.version0
.schedule
) {
655 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, rlm
->_name
);
657 } else if (1 == rls
->_context
.version0
.version
) {
658 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
659 if (CFPORT_NULL
!= port
) {
660 __CFPortSetInsert(port
, rlm
->_portSet
);
662 #if DEPLOYMENT_TARGET_WINDOWS
664 //#warning Bug here - if rl->_currentMode is NULL and rlm == the default mode, we should also update
665 if (rl
->_currentMode
== rlm
) {
666 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
667 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
669 __CFRunLoopUpdateMsgWait(rl
);
671 __CFRunLoopUnlock(rl
);
676 /* rlm is not locked */
677 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
678 //printf("Cancelling source %p from mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
679 __CFRunLoopSourceLock(rls
);
680 if (NULL
!= rls
->_runLoops
) {
681 CFBagRemoveValue(rls
->_runLoops
, rl
);
683 __CFRunLoopSourceUnlock(rls
);
684 if (0 == rls
->_context
.version0
.version
) {
685 if (NULL
!= rls
->_context
.version0
.cancel
) {
686 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
688 } else if (1 == rls
->_context
.version0
.version
) {
689 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
690 if (CFPORT_NULL
!= port
) {
691 __CFPortSetRemove(port
, rlm
->_portSet
);
693 #if DEPLOYMENT_TARGET_WINDOWS
695 //#warning Bug here - must also update if rl->_currentMode == NULL and rlm == default mode
696 if (rl
->_currentMode
== rlm
&& rl
->_msgUpdatePort
!= CFPORT_NULL
) {
697 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
698 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
700 __CFRunLoopUpdateMsgWait(rl
);
702 __CFRunLoopUnlock(rl
);
707 struct __CFRunLoopObserver
{
710 CFRunLoopRef _runLoop
;
712 CFOptionFlags _activities
; /* immutable */
713 CFIndex _order
; /* immutable */
714 CFRunLoopObserverCallBack _callout
; /* immutable */
715 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
718 /* Bit 0 of the base reserved bits is used for firing state */
719 /* Bit 1 of the base reserved bits is used for repeats state */
721 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
722 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
725 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
726 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
729 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
730 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
733 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
734 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
737 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
738 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
741 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
742 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
745 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
746 __CFSpinLock(&(rlo
->_lock
));
749 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
750 __CFSpinUnlock(&(rlo
->_lock
));
753 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
754 __CFRunLoopObserverLock(rlo
);
755 if (0 == rlo
->_rlCount
) {
759 __CFRunLoopObserverUnlock(rlo
);
762 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
763 __CFRunLoopObserverLock(rlo
);
765 if (0 == rlo
->_rlCount
) {
766 rlo
->_runLoop
= NULL
;
768 __CFRunLoopObserverUnlock(rlo
);
771 struct __CFRunLoopTimer
{
774 CFRunLoopRef _runLoop
;
775 CFMutableSetRef _rlModes
;
776 CFAbsoluteTime _nextFireDate
;
777 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
778 mach_port_name_t _port
;
779 int64_t _fireTSR
; /* TSR units */
780 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
781 #elif DEPLOYMENT_TARGET_WINDOWS
783 int64_t _fireTSR
; /* TSR units */
784 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
786 CFTimeInterval _interval
; /* immutable */
787 CFIndex _order
; /* immutable */
788 CFRunLoopTimerCallBack _callout
; /* immutable */
789 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
792 /* Bit 0 of the base reserved bits is used for firing state */
793 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
795 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
796 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
799 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
800 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
803 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
804 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
807 CF_INLINE Boolean
__CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt
) {
808 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
811 CF_INLINE
void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt
) {
812 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
815 CF_INLINE
void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt
) {
816 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
819 CF_INLINE Boolean
__CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt
) {
820 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
823 CF_INLINE
void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt
) {
824 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
827 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
828 __CFSpinLock(&(rlt
->_lock
));
831 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
832 __CFSpinUnlock(&(rlt
->_lock
));
835 static CFSpinLock_t __CFRLTFireTSRLock
= CFSpinLockInit
;
837 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
838 __CFSpinLock(&__CFRLTFireTSRLock
);
841 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
842 __CFSpinUnlock(&__CFRLTFireTSRLock
);
845 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
846 static CFMutableDictionaryRef __CFRLTPortMap
= NULL
;
847 static CFSpinLock_t __CFRLTPortMapLock
= CFSpinLockInit
;
849 CF_INLINE
void __CFRunLoopTimerPortMapLock(void) {
850 __CFSpinLock(&__CFRLTPortMapLock
);
853 CF_INLINE
void __CFRunLoopTimerPortMapUnlock(void) {
854 __CFSpinUnlock(&__CFRLTPortMapLock
);
858 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
);
860 // called with timer locked in libdispatch mode
861 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt
) {
862 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
863 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
867 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
868 //CFLog(4, CFSTR("__CFRunLoopTimerSchedule(%p, loop %p, mode %@) [%p, %p]"), rlt, rl, rlm->_name, rlt->_runLoop, rlt->_port);
869 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
870 __CFRunLoopTimerLock(rlt
);
871 if (NULL
== rlt
->_runLoop
) {
873 if (MACH_PORT_NULL
== rlt
->_port
) {
874 rlt
->_port
= mk_timer_create();
876 __CFRunLoopTimerPortMapLock();
877 if (NULL
== __CFRLTPortMap
) {
878 __CFRLTPortMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
880 CFDictionarySetValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
, rlt
);
881 __CFRunLoopTimerPortMapUnlock();
882 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
884 mach_port_insert_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
885 CFSetAddValue(rlt
->_rlModes
, rlm
->_name
);
886 __CFRunLoopTimerUnlock(rlt
);
887 #elif DEPLOYMENT_TARGET_WINDOWS
888 if (0 == rlt
->_rlCount
) {
895 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
896 //CFLog(6, CFSTR("__CFRunLoopTimerCancel(rlt %p, rl %p, rlm %@)"), rlt, rl, rlm->_name);
897 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
898 __CFRunLoopTimerLock(rlt
);
899 CFSetRemoveValue(rlt
->_rlModes
, rlm
->_name
);
900 __CFPortSetRemove(rlt
->_port
, rlm
->_portSet
);
901 if (0 == CFSetGetCount(rlt
->_rlModes
)) {
902 __CFRunLoopTimerPortMapLock();
903 if (NULL
!= __CFRLTPortMap
) {
904 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
906 __CFRunLoopTimerPortMapUnlock();
907 mk_timer_cancel(rlt
->_port
, NULL
);
908 rlt
->_runLoop
= NULL
;
910 __CFRunLoopTimerUnlock(rlt
);
911 #elif DEPLOYMENT_TARGET_WINDOWS
916 #if DEPLOYMENT_TARGET_WINDOWS
918 struct _collectTimersContext
{
919 CFMutableArrayRef results
;
923 static void __CFRunLoopCollectTimers(const void *value
, void *ctx
) {
924 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
925 struct _collectTimersContext
*context
= (struct _collectTimersContext
*)ctx
;
926 if (rlt
->_fireTSR
<= context
->cutoffTSR
) {
927 if (NULL
== context
->results
)
928 context
->results
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
929 CFArrayAppendValue(context
->results
, rlt
);
933 // RunLoop and RunLoopMode must be locked
934 static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, struct _collectTimersContext
*ctxt
) {
935 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
936 __CFRunLoopTimerFireTSRLock();
937 CFSetApplyFunction(rlm
->_timers
, __CFRunLoopCollectTimers
, ctxt
);
938 __CFRunLoopTimerFireTSRUnlock();
940 if (NULL
!= rlm
->_submodes
) {
942 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
943 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
944 CFRunLoopModeRef subrlm
;
945 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
946 if (NULL
!= subrlm
) {
947 __CFRunLoopTimersToFireRecursive(rl
, subrlm
, ctxt
);
948 __CFRunLoopModeUnlock(subrlm
);
954 // RunLoop and RunLoopMode must be locked
955 static CFArrayRef
__CFRunLoopTimersToFire(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
956 struct _collectTimersContext ctxt
= {NULL
, __CFReadTSR()};
957 __CFRunLoopTimersToFireRecursive(rl
, rlm
, &ctxt
);
964 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
965 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
967 // call with rl and rlm locked
968 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
970 CFRunLoopSourceRef found
= rlm
->_portToV1SourceMap
? (CFRunLoopSourceRef
)CFDictionaryGetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)port
) : NULL
;
971 if (NULL
== found
&& NULL
!= rlm
->_submodes
) {
973 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
974 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
975 CFRunLoopModeRef subrlm
;
976 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
977 if (NULL
!= subrlm
) {
978 found
= __CFRunLoopModeFindSourceForMachPort(rl
, subrlm
, port
);
979 __CFRunLoopModeUnlock(subrlm
);
989 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
990 // call with rl and rlm locked
991 static CFRunLoopTimerRef
__CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm
, __CFPort port
) {
993 CFRunLoopTimerRef result
= NULL
;
994 __CFRunLoopTimerPortMapLock();
995 if (NULL
!= __CFRLTPortMap
) {
996 result
= (CFRunLoopTimerRef
)CFDictionaryGetValue(__CFRLTPortMap
, (void *)(uintptr_t)port
);
998 __CFRunLoopTimerPortMapUnlock();
1003 // Remove backreferences the mode's sources have to the rl (context);
1004 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1005 // the source from the run loops it is in, but during deallocation of a
1006 // run loop, we already know that the sources are going to be punted
1007 // from it, so invalidation of sources does not need to remove from a
1008 // deallocating run loop.
1009 static void __CFRunLoopCleanseSources(const void *value
, void *context
) {
1010 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1011 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1013 const void **list
, *buffer
[256];
1014 if (NULL
== rlm
->_sources
) return;
1015 cnt
= CFSetGetCount(rlm
->_sources
);
1016 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1017 CFSetGetValues(rlm
->_sources
, list
);
1018 for (idx
= 0; idx
< cnt
; idx
++) {
1019 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1020 __CFRunLoopSourceLock(rls
);
1021 if (NULL
!= rls
->_runLoops
) {
1022 CFBagRemoveValue(rls
->_runLoops
, rl
);
1024 __CFRunLoopSourceUnlock(rls
);
1026 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1029 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
1030 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1031 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1033 const void **list
, *buffer
[256];
1034 if (NULL
== rlm
->_sources
) return;
1035 cnt
= CFSetGetCount(rlm
->_sources
);
1036 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1037 CFSetGetValues(rlm
->_sources
, list
);
1038 for (idx
= 0; idx
< cnt
; idx
++) {
1039 CFRetain(list
[idx
]);
1041 CFSetRemoveAllValues(rlm
->_sources
);
1042 for (idx
= 0; idx
< cnt
; idx
++) {
1043 __CFRunLoopSourceCancel((CFRunLoopSourceRef
)list
[idx
], rl
, rlm
);
1044 CFRelease(list
[idx
]);
1046 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1049 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
1050 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1051 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1053 const void **list
, *buffer
[256];
1054 if (NULL
== rlm
->_observers
) return;
1055 cnt
= CFSetGetCount(rlm
->_observers
);
1056 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1057 CFSetGetValues(rlm
->_observers
, list
);
1058 for (idx
= 0; idx
< cnt
; idx
++) {
1059 CFRetain(list
[idx
]);
1061 CFSetRemoveAllValues(rlm
->_observers
);
1062 for (idx
= 0; idx
< cnt
; idx
++) {
1063 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
1064 CFRelease(list
[idx
]);
1066 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1069 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
1070 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1071 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1073 const void **list
, *buffer
[256];
1074 if (NULL
== rlm
->_timers
) return;
1075 cnt
= CFSetGetCount(rlm
->_timers
);
1076 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1077 CFSetGetValues(rlm
->_timers
, list
);
1078 for (idx
= 0; idx
< cnt
; idx
++) {
1079 CFRetain(list
[idx
]);
1081 CFSetRemoveAllValues(rlm
->_timers
);
1082 for (idx
= 0; idx
< cnt
; idx
++) {
1083 __CFRunLoopTimerCancel((CFRunLoopTimerRef
)list
[idx
], rl
, rlm
);
1084 CFRelease(list
[idx
]);
1086 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1089 CF_EXPORT pthread_t _CFMainPThread
;
1090 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
);
1092 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
1093 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
1095 if (_CFRunLoopGet0b(_CFMainPThread
) == cf
) HALT
;
1097 /* We try to keep the run loop in a valid state as long as possible,
1098 since sources may have non-retained references to the run loop.
1099 Another reason is that we don't want to lock the run loop for
1100 callback reasons, if we can get away without that. We start by
1101 eliminating the sources, since they are the most likely to call
1102 back into the run loop during their "cancellation". Common mode
1103 items will be removed from the mode indirectly by the following
1105 __CFRunLoopSetDeallocating(rl
);
1106 if (NULL
!= rl
->_modes
) {
1107 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopCleanseSources
), rl
); // remove references to rl
1108 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
1109 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
1110 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
1112 __CFRunLoopLock(rl
);
1113 struct _block_item
*item
= rl
->_blocks_head
;
1115 struct _block_item
*curr
= item
;
1117 CFRelease(curr
->_mode
);
1118 Block_release(curr
->_block
);
1121 if (NULL
!= rl
->_commonModeItems
) {
1122 CFRelease(rl
->_commonModeItems
);
1124 if (NULL
!= rl
->_commonModes
) {
1125 CFRelease(rl
->_commonModes
);
1127 if (NULL
!= rl
->_modes
) {
1128 CFRelease(rl
->_modes
);
1130 __CFPortFree(rl
->_wakeUpPort
);
1131 rl
->_wakeUpPort
= CFPORT_NULL
;
1132 #if DEPLOYMENT_TARGET_WINDOWS
1133 __CFPortFree(rl
->_msgUpdatePort
);
1134 rl
->_msgUpdatePort
= CFPORT_NULL
;
1136 __CFRunLoopUnlock(rl
);
1137 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x8C, sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
));
1140 static const CFRuntimeClass __CFRunLoopModeClass
= {
1145 __CFRunLoopModeDeallocate
,
1146 __CFRunLoopModeEqual
,
1147 __CFRunLoopModeHash
,
1149 __CFRunLoopModeCopyDescription
1152 static const CFRuntimeClass __CFRunLoopClass
= {
1157 __CFRunLoopDeallocate
,
1161 __CFRunLoopCopyDescription
1164 static void __CFFinalizeRunLoop(uintptr_t data
);
1166 __private_extern__
void __CFRunLoopInitialize(void) {
1167 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
1168 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
1169 #if DEPLOYMENT_TARGET_WINDOWS
1170 __kCFRunLoopWakeUpMessage
= RegisterWindowMessageW((LPCWSTR
)L
"CFRunLoopWakeup");
1171 __kCFRunLoopV1SourceReadyMessage
= RegisterWindowMessageW((LPCWSTR
)L
"CFRunLoopV1Ready");
1173 #if DEPLOYMENT_TARGET_WINDOWS
1174 if (~0 == __CFTSDKeyRunLoopKey
) __CFTSDKeyRunLoopKey
= TlsAlloc();
1176 pthread_key_init_np(__CFTSDKeyRunLoop
, NULL
);
1177 pthread_key_init_np(__CFTSDKeyRunLoopCntr
, (void *)__CFFinalizeRunLoop
);
1181 CFTypeID
CFRunLoopGetTypeID(void) {
1182 return __kCFRunLoopTypeID
;
1185 static CFRunLoopRef
__CFRunLoopCreate(pthread_t t
) {
1186 CFRunLoopRef loop
= NULL
;
1187 CFRunLoopModeRef rlm
;
1188 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
1189 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
1193 loop
->_stopped
= NULL
;
1194 CF_SPINLOCK_INIT_FOR_STRUCTS(loop
->_lock
);
1195 loop
->_wakeUpPort
= __CFPortAllocate();
1196 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
1197 #if DEPLOYMENT_TARGET_WINDOWS
1198 loop
->_msgUpdatePort
= CFPORT_NULL
;
1200 loop
->_commonModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1201 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
1202 loop
->_commonModeItems
= NULL
;
1203 loop
->_currentMode
= NULL
;
1204 loop
->_modes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1205 _CFSetSetCapacity(loop
->_modes
, 10);
1206 loop
->_blocks_head
= NULL
;
1207 loop
->_blocks_tail
= NULL
;
1208 loop
->_counterpart
= NULL
;
1210 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
1211 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
1215 static CFMutableDictionaryRef __CFRunLoops
= NULL
;
1216 static CFSpinLock_t loopsLock
= CFSpinLockInit
;
1218 // should only be called by Foundation
1219 // t==0 is a synonym for "main thread" that always works
1220 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0(pthread_t t
) {
1221 if (pthread_equal(t
, kNilPthreadT
)) {
1224 __CFSpinLock(&loopsLock
);
1225 if (!__CFRunLoops
) {
1226 __CFSpinUnlock(&loopsLock
);
1227 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1228 CFRunLoopRef mainLoop
= __CFRunLoopCreate(_CFMainPThread
);
1229 CFDictionarySetValue(dict
, pthreadPointer(_CFMainPThread
), mainLoop
);
1230 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, dict
, (void * volatile *)&__CFRunLoops
)) {
1233 CFRelease(mainLoop
);
1234 __CFSpinLock(&loopsLock
);
1236 CFRunLoopRef loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1238 __CFSpinUnlock(&loopsLock
);
1239 CFRunLoopRef newLoop
= __CFRunLoopCreate(t
);
1240 __CFSpinLock(&loopsLock
);
1241 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1243 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(t
), newLoop
);
1248 if (pthread_equal(t
, pthread_self())) {
1249 #if DEPLOYMENT_TARGET_WINDOWS
1250 TlsSetValue(__CFTSDKeyRunLoopKey
, (LPVOID
)(PTHREAD_DESTRUCTOR_ITERATIONS
-1));
1252 pthread_setspecific(__CFTSDKeyRunLoop
, (void *)loop
);
1253 if (0 == pthread_getspecific(__CFTSDKeyRunLoopCntr
)) {
1254 pthread_setspecific(__CFTSDKeyRunLoopCntr
, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS
-1));
1257 #if DEPLOYMENT_TARGET_WINDOWS
1258 // Install our message hook so we can spin the runloop
1259 loop
->_threadID
= GetCurrentThreadId();
1260 //#if MARRY_MESSAGE_QUEUE
1261 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) {
1263 __CFGetThreadSpecificData_inline()->_messageHook
= SetWindowsHookExW(WH_GETMESSAGE
, (HOOKPROC
)pumpRunLoopFromMessageQueue
, GetModuleHandleW((LPCWSTR
)L
"CoreFoundation_debug.dll"), loop
->_threadID
);
1265 __CFGetThreadSpecificData_inline()->_messageHook
= SetWindowsHookExW(WH_GETMESSAGE
, (HOOKPROC
)pumpRunLoopFromMessageQueue
, GetModuleHandleW((LPCWSTR
)L
"CoreFoundation.dll"), loop
->_threadID
);
1271 __CFSpinUnlock(&loopsLock
);
1275 // should only be called by Foundation
1276 CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
) {
1277 if (pthread_equal(t
, kNilPthreadT
)) {
1280 __CFSpinLock(&loopsLock
);
1281 CFRunLoopRef loop
= NULL
;
1283 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1285 __CFSpinUnlock(&loopsLock
);
1289 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
);
1291 // Called for each thread as it exits
1292 static void __CFFinalizeRunLoop(uintptr_t data
) {
1293 CFRunLoopRef rl
= NULL
;
1295 __CFSpinLock(&loopsLock
);
1297 rl
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1298 if (rl
) CFRetain(rl
);
1299 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1301 __CFSpinUnlock(&loopsLock
);
1303 #if DEPLOYMENT_TARGET_WINDOWS
1304 TlsSetValue(__CFTSDKeyRunLoopKey
, (LPVOID
)(data
- 1));
1306 pthread_setspecific(__CFTSDKeyRunLoopCntr
, (void *)(data
- 1));
1309 if (rl
&& CFRunLoopGetMain() != rl
) { // protect against cooperative threads
1310 if (NULL
!= rl
->_counterpart
) {
1311 CFRelease(rl
->_counterpart
);
1312 rl
->_counterpart
= NULL
;
1314 // purge all sources before deallocation
1315 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
1316 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
1317 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
1318 __CFRunLoopRemoveAllSources(rl
, modeName
);
1320 __CFRunLoopRemoveAllSources(rl
, kCFRunLoopCommonModes
);
1323 if (rl
) CFRelease(rl
);
1326 pthread_t
_CFRunLoopGet1(CFRunLoopRef rl
) {
1327 return rl
->_pthread
;
1330 // should only be called by Foundation
1331 CF_EXPORT CFTypeRef
_CFRunLoopGet2(CFRunLoopRef rl
) {
1332 CFTypeRef ret
= NULL
;
1333 __CFSpinLock(&loopsLock
);
1334 if (NULL
== rl
->_counterpart
) {
1335 Class cls
= (Class
)objc_lookUpClass("NSRunLoop");
1338 CF_OBJC_CALL1(char, hasMethod
, cls
, "respondsToSelector:", sel_registerName("_new:"));
1341 CF_OBJC_CALL1(void *, ns
, cls
, "_new:", rl
);
1342 rl
->_counterpart
= ns
? CFRetain(ns
) : NULL
;
1346 ret
= rl
->_counterpart
;
1347 __CFSpinUnlock(&loopsLock
);
1351 // should only be called by Foundation
1352 CF_EXPORT CFTypeRef
_CFRunLoopGet2b(CFRunLoopRef rl
) {
1353 return rl
->_counterpart
;
1356 #if DEPLOYMENT_TARGET_MACOSX
1357 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1358 if (pthread_main_np()) return;
1359 CFRunLoopRef currentLoop
= CFRunLoopGetCurrent();
1360 if (rl
!= currentLoop
) {
1361 CFRetain(currentLoop
); // avoid a deallocation of the currentLoop inside the lock
1362 __CFSpinLock(&loopsLock
);
1364 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(pthread_self()), rl
);
1366 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1368 __CFSpinUnlock(&loopsLock
);
1369 CFRelease(currentLoop
);
1370 pthread_setspecific(__CFTSDKeyRunLoop
, NULL
);
1371 pthread_setspecific(__CFTSDKeyRunLoopCntr
, 0);
1376 CFRunLoopRef
CFRunLoopGetMain(void) {
1378 static CFRunLoopRef __main
= NULL
; // no retain needed
1379 if (!__main
) __main
= _CFRunLoopGet0(_CFMainPThread
); // no CAS needed
1383 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1385 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1386 CFRunLoopRef rl
= (CFRunLoopRef
)pthread_getspecific(__CFTSDKeyRunLoop
);
1389 return _CFRunLoopGet0(pthread_self());
1392 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1394 CFStringRef result
= NULL
;
1395 __CFRunLoopLock(rl
);
1396 if (NULL
!= rl
->_currentMode
) {
1397 result
= (CFStringRef
)CFRetain(rl
->_currentMode
->_name
);
1399 __CFRunLoopUnlock(rl
);
1403 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1404 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1405 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1406 CFArrayAppendValue(array
, rlm
->_name
);
1409 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1411 CFMutableArrayRef array
;
1412 __CFRunLoopLock(rl
);
1413 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1414 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1415 __CFRunLoopUnlock(rl
);
1419 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1420 CFTypeRef item
= (CFTypeRef
)value
;
1421 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1422 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1423 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1424 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1425 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1426 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1427 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1428 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1432 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1433 CFStringRef modeName
= (CFStringRef
)value
;
1434 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1435 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1436 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1437 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1438 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1439 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1440 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1441 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1445 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1446 CFStringRef modeName
= (CFStringRef
)value
;
1447 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1448 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1449 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1450 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1451 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1452 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1453 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1454 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1458 CF_EXPORT Boolean
_CFRunLoop01(CFRunLoopRef rl
, CFStringRef modeName
) {
1459 __CFRunLoopLock(rl
);
1460 Boolean present
= CFSetContainsValue(rl
->_commonModes
, modeName
);
1461 __CFRunLoopUnlock(rl
);
1465 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1467 if (__CFRunLoopIsDeallocating(rl
)) return;
1468 __CFRunLoopLock(rl
);
1469 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1470 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1471 CFSetAddValue(rl
->_commonModes
, modeName
);
1472 __CFRunLoopUnlock(rl
);
1474 CFTypeRef context
[2] = {rl
, modeName
};
1475 /* add all common-modes items to new mode */
1476 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1480 __CFRunLoopUnlock(rl
);
1484 static Boolean
__CFRunLoopDoBlocks(CFRunLoopRef rl
, CFStringRef curMode
) { // Call with rl locked
1485 if (!rl
->_blocks_head
) return false;
1486 if (!curMode
) return false;
1487 Boolean did
= false;
1488 CFAbsoluteTime deadline
= CFAbsoluteTimeGetCurrent() + 0.0009765625;
1489 struct _block_item
*head
= rl
->_blocks_head
;
1490 struct _block_item
*tail
= rl
->_blocks_tail
;
1491 rl
->_blocks_head
= NULL
;
1492 rl
->_blocks_tail
= NULL
;
1493 CFSetRef commonModes
= rl
->_commonModes
;
1494 __CFRunLoopUnlock(rl
);
1495 struct _block_item
*prev
= NULL
;
1496 struct _block_item
*item
= head
;
1497 while (item
&& CFAbsoluteTimeGetCurrent() < deadline
) {
1498 struct _block_item
*curr
= item
;
1500 Boolean doit
= false;
1501 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
1502 doit
= CFEqual(curr
->_mode
, curMode
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1504 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, curMode
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1506 if (!doit
) prev
= curr
;
1508 if (prev
) prev
->_next
= item
;
1509 if (curr
== head
) head
= item
;
1510 if (curr
== tail
) tail
= prev
;
1511 void (^block
)(void) = curr
->_block
;
1512 CFRelease(curr
->_mode
);
1515 block(); // rl is not locked, mode is not locked
1518 Block_release(block
); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1521 __CFRunLoopLock(rl
);
1523 tail
->_next
= rl
->_blocks_head
;
1524 rl
->_blocks_head
= head
;
1525 if (!rl
->_blocks_tail
) rl
->_blocks_tail
= tail
;
1530 static CFComparisonResult
__CFRunLoopObserverQSortComparator(const void *val1
, const void *val2
, void *context
) {
1531 CFRunLoopObserverRef o1
= *((CFRunLoopObserverRef
*)val1
);
1532 CFRunLoopObserverRef o2
= *((CFRunLoopObserverRef
*)val2
);
1534 return (!o2
) ? kCFCompareEqualTo
: kCFCompareLessThan
;
1537 return kCFCompareGreaterThan
;
1539 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1540 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1541 return kCFCompareEqualTo
;
1545 /* rl is unlocked, rlm is locked on entrance and exit */
1546 /* ALERT: this should collect all the candidate observers from the top level
1547 * and all submodes, recursively, THEN start calling them, in order to obey
1548 * the ordering parameter. */
1549 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1552 CFArrayRef submodes
;
1554 /* Fire the observers */
1555 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1556 if (NULL
!= rlm
->_observers
) {
1557 cnt
= CFSetGetCount(rlm
->_observers
);
1559 STACK_BUFFER_DECL(CFRunLoopObserverRef
, buffer
, (cnt
<= 1024) ? cnt
: 1);
1560 CFRunLoopObserverRef
*collectedObservers
= (CFRunLoopObserverRef
*)((cnt
<= 1024) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(CFRunLoopObserverRef
), 0));
1561 CFSetGetValues(rlm
->_observers
, (const void **)collectedObservers
);
1562 for (idx
= 0; idx
< cnt
; idx
++) {
1563 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1564 if (0 != (rlo
->_activities
& activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1567 /* We're not interested in this one - set it to NULL so we don't process it later */
1568 collectedObservers
[idx
] = NULL
;
1571 __CFRunLoopModeUnlock(rlm
);
1572 CFQSortArray(collectedObservers
, cnt
, sizeof(CFRunLoopObserverRef
), __CFRunLoopObserverQSortComparator
, NULL
);
1573 for (idx
= 0; idx
< cnt
; idx
++) {
1574 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1576 __CFRunLoopObserverLock(rlo
);
1577 if (__CFIsValid(rlo
)) {
1578 __CFRunLoopObserverUnlock(rlo
);
1579 __CFRunLoopObserverSetFiring(rlo
);
1580 rlo
->_callout(rlo
, activity
, rlo
->_context
.info
); /* CALLOUT */
1581 __CFRunLoopObserverUnsetFiring(rlo
);
1582 if (!__CFRunLoopObserverRepeats(rlo
)) {
1583 CFRunLoopObserverInvalidate(rlo
);
1586 __CFRunLoopObserverUnlock(rlo
);
1591 __CFRunLoopModeLock(rlm
);
1592 if (collectedObservers
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, collectedObservers
);
1595 if (NULL
!= submodes
) {
1596 __CFRunLoopModeUnlock(rlm
);
1597 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1598 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1599 CFRunLoopModeRef subrlm
;
1600 __CFRunLoopLock(rl
);
1601 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1602 __CFRunLoopUnlock(rl
);
1603 if (NULL
!= subrlm
) {
1604 __CFRunLoopDoObservers(rl
, subrlm
, activity
);
1605 __CFRunLoopModeUnlock(subrlm
);
1608 CFRelease(submodes
);
1609 __CFRunLoopModeLock(rlm
);
1613 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1614 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1615 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1616 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1617 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1618 return kCFCompareEqualTo
;
1621 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1622 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1623 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1624 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1625 if (NULL
== *sources
) {
1626 *sources
= CFRetain(rls
);
1627 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1628 CFTypeRef oldrls
= *sources
;
1629 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1630 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1631 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1634 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1639 /* rl is unlocked, rlm is locked on entrance and exit */
1640 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1642 CFTypeRef sources
= NULL
;
1643 Boolean sourceHandled
= false;
1646 __CFRunLoopModeUnlock(rlm
); // locks have to be taken in order
1647 __CFRunLoopLock(rl
);
1648 __CFRunLoopModeLock(rlm
);
1649 /* Fire the version 0 sources */
1650 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) {
1651 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1653 for (idx
= 0, cnt
= (NULL
!= rlm
->_submodes
) ? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1654 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1655 CFRunLoopModeRef subrlm
;
1656 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1657 if (NULL
!= subrlm
) {
1658 if (NULL
!= subrlm
->_sources
&& 0 < CFSetGetCount(subrlm
->_sources
)) {
1659 CFSetApplyFunction(subrlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1661 __CFRunLoopModeUnlock(subrlm
);
1664 __CFRunLoopUnlock(rl
);
1665 if (NULL
!= sources
) {
1666 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1667 __CFRunLoopModeUnlock(rlm
);
1668 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1669 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1670 __CFRunLoopSourceLock(rls
);
1671 #if DEPLOYMENT_TARGET_WINDOWS
1672 if (__CFRunLoopSourceIsSignaled(rls
)) {
1674 __CFRunLoopSourceUnsetSignaled(rls
);
1675 if (__CFIsValid(rls
)) {
1676 __CFRunLoopSourceUnlock(rls
);
1677 if (NULL
!= rls
->_context
.version0
.perform
) {
1678 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1681 sourceHandled
= true;
1683 __CFRunLoopSourceUnlock(rls
);
1685 #if DEPLOYMENT_TARGET_WINDOWS
1687 __CFRunLoopSourceUnlock(rls
);
1691 cnt
= CFArrayGetCount((CFArrayRef
)sources
);
1692 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1693 for (idx
= 0; idx
< cnt
; idx
++) {
1694 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex((CFArrayRef
)sources
, idx
);
1695 __CFRunLoopSourceLock(rls
);
1696 #if DEPLOYMENT_TARGET_WINDOWS
1697 if (__CFRunLoopSourceIsSignaled(rls
)) {
1699 __CFRunLoopSourceUnsetSignaled(rls
);
1700 if (__CFIsValid(rls
)) {
1701 __CFRunLoopSourceUnlock(rls
);
1702 if (NULL
!= rls
->_context
.version0
.perform
) {
1703 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1706 sourceHandled
= true;
1708 __CFRunLoopSourceUnlock(rls
);
1710 #if DEPLOYMENT_TARGET_WINDOWS
1712 __CFRunLoopSourceUnlock(rls
);
1715 if (stopAfterHandle
&& sourceHandled
) {
1721 __CFRunLoopModeLock(rlm
);
1723 return sourceHandled
;
1726 // msg, size and reply are unused on Windows
1727 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1728 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1729 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1731 ) { /* DOES CALLOUT */
1733 Boolean sourceHandled
= false;
1735 /* Fire a version 1 source */
1737 __CFRunLoopModeUnlock(rlm
);
1738 __CFRunLoopSourceLock(rls
);
1739 if (__CFIsValid(rls
)) {
1740 __CFRunLoopSourceUnsetSignaled(rls
);
1741 __CFRunLoopSourceUnlock(rls
);
1742 if (NULL
!= rls
->_context
.version1
.perform
) {
1743 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1744 *reply
= rls
->_context
.version1
.perform(msg
, size
, kCFAllocatorSystemDefault
, rls
->_context
.version1
.info
); /* CALLOUT */
1747 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1748 rls
->_context
.version1
.perform(rls
->_context
.version1
.info
); /* CALLOUT */
1752 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); }
1754 sourceHandled
= true;
1756 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1757 __CFRunLoopSourceUnlock(rls
);
1760 __CFRunLoopModeLock(rlm
);
1761 return sourceHandled
;
1764 // mode is locked on entry and exit
1765 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1766 Boolean timerHandled
= false, timerEarly
= false;
1767 int64_t oldFireTSR
= 0;
1771 __CFRunLoopModeUnlock(rlm
);
1772 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
1773 void *context_info
= NULL
;
1774 void (*context_release
)(const void *) = NULL
;
1775 if (rlt
->_context
.retain
) {
1776 context_info
= (void *)rlt
->_context
.retain(rlt
->_context
.info
);
1777 context_release
= rlt
->_context
.release
;
1779 context_info
= rlt
->_context
.info
;
1781 __CFRunLoopTimerUnsetDidFire(rlt
);
1782 __CFRunLoopTimerSetFiring(rlt
);
1783 //CFLog(4, CFSTR("Firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1784 __CFRunLoopTimerFireTSRLock();
1785 oldFireTSR
= rlt
->_fireTSR
;
1786 __CFRunLoopTimerFireTSRUnlock();
1787 if (0 && CFAbsoluteTimeGetCurrent() < rlt
->_nextFireDate
) { // not enabled at this time -- causes trouble when clock goes backwards
1790 rlt
->_callout(rlt
, context_info
); /* CALLOUT */
1792 timerHandled
= true;
1794 //CFLog(4, CFSTR("Done firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1795 __CFRunLoopTimerUnsetFiring(rlt
);
1796 if (context_release
) {
1797 context_release(context_info
);
1800 // If the timer fires while it is firing in a higher activiation,
1801 // it is not allowed to fire, but we have to remember that fact.
1802 // Later, if the timer's fire date is being handled manually, we
1803 // need to re-arm the kernel timer, since it has possibly already
1804 // fired (this firing which is being skipped, say) and the timer
1805 // will permanently stop if we completely drop this firing.
1806 if (__CFRunLoopTimerIsFiring(rlt
)) __CFRunLoopTimerSetDidFire(rlt
);
1808 if (__CFIsValid(rlt
) && timerHandled
) {
1809 if (0.0 == rlt
->_interval
) {
1810 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1812 /* This is just a little bit tricky: we want to support calling
1813 * CFRunLoopTimerSetNextFireDate() from within the callout and
1814 * honor that new time here if it is a later date, otherwise
1815 * it is completely ignored. */
1816 __CFRunLoopTimerFireTSRLock();
1817 int64_t currentFireTSR
= rlt
->_fireTSR
;
1818 if (oldFireTSR
< currentFireTSR
) {
1819 /* Next fire TSR was set, and set to a date after the previous
1820 * fire date, so we honor it. */
1821 if (__CFRunLoopTimerDidFire(rlt
)) {
1822 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1823 __CFRunLoopTimerUnsetDidFire(rlt
);
1826 if ((uint64_t)LLONG_MAX
<= (uint64_t)oldFireTSR
+ (uint64_t)rlt
->_intervalTSR
) {
1827 currentFireTSR
= LLONG_MAX
;
1829 int64_t currentTSR
= (int64_t)__CFReadTSR();
1830 currentFireTSR
= oldFireTSR
;
1831 while (currentFireTSR
<= currentTSR
) {
1832 currentFireTSR
+= rlt
->_intervalTSR
;
1835 rlt
->_fireTSR
= currentFireTSR
;
1836 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1838 __CFRunLoopTimerFireTSRUnlock();
1841 if (__CFIsValid(rlt
) && timerEarly
) {
1842 int64_t now2
= (int64_t)mach_absolute_time();
1843 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
1844 __CFRunLoopTimerFireTSRLock();
1845 if (rlt
->_nextFireDate
< now1
) {
1846 rlt
->_fireTSR
= now2
;
1847 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < rlt
->_nextFireDate
) {
1848 rlt
->_fireTSR
= LLONG_MAX
;
1850 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(rlt
->_nextFireDate
- now1
);
1852 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1853 __CFRunLoopTimerFireTSRUnlock();
1856 __CFRunLoopModeLock(rlm
);
1857 return timerHandled
;
1860 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1862 CFRunLoopModeRef rlm
;
1863 Boolean result
= false;
1864 __CFRunLoopLock(rl
);
1865 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1866 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
, NULL
)) {
1869 __CFRunLoopUnlock(rl
);
1870 if (rlm
) __CFRunLoopModeUnlock(rlm
);
1874 // rl is locked, rlm is locked on entry and exit
1875 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPortSet portSet
) {
1877 const void **list
, *buffer
[256];
1879 // Timers and version 1 sources go into the portSet currently
1880 if (NULL
!= rlm
->_sources
) {
1881 cnt
= CFSetGetCount(rlm
->_sources
);
1882 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1883 CFSetGetValues(rlm
->_sources
, list
);
1884 for (idx
= 0; idx
< cnt
; idx
++) {
1885 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1886 if (1 == rls
->_context
.version0
.version
) {
1887 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1888 if (CFPORT_NULL
!= port
) {
1889 __CFPortSetInsert(port
, portSet
);
1893 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1895 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1896 if (NULL
!= rlm
->_timers
) {
1897 cnt
= CFSetGetCount(rlm
->_timers
);
1898 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1899 CFSetGetValues(rlm
->_timers
, list
);
1900 for (idx
= 0; idx
< cnt
; idx
++) {
1901 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1902 if (MACH_PORT_NULL
!= rlt
->_port
) {
1903 mach_port_insert_member(mach_task_self(), rlt
->_port
, portSet
);
1906 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1909 // iterate over submodes
1910 for (idx
= 0, cnt
= NULL
!= rlm
->_submodes
? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1911 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1912 CFRunLoopModeRef subrlm
;
1913 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1914 if (NULL
!= subrlm
) {
1915 __CFRunLoopModeAddPortsToPortSet(rl
, subrlm
, portSet
);
1916 __CFRunLoopModeUnlock(subrlm
);
1921 static __CFPortSet _LastMainWaitSet
= 0;
1923 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1924 // return NO if we're the main runloop and there are no messages waiting on the port set
1925 int _CFRunLoopInputsReady(void) {
1927 if (!pthread_main_np()) return true;
1929 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1930 if (_LastMainWaitSet
== MACH_PORT_NULL
) return false;
1932 // prepare a message header with no space for any data, nor a trailer
1933 mach_msg_header_t msg
;
1934 msg
.msgh_size
= sizeof(msg
); // just the header, ma'am
1935 // need the waitset, actually XXX
1936 msg
.msgh_local_port
= _LastMainWaitSet
;
1937 msg
.msgh_remote_port
= MACH_PORT_NULL
;
1940 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
);
1942 return (MACH_RCV_TOO_LARGE
== ret
);
1948 static void print_msg_scan_header(void) {
1949 printf("======== ======== ======== ========\n");
1950 printf("description\tport\tport type\t\treferences\n");
1953 static void print_one_port_info(const char *desc
, mach_port_t port
, mach_msg_type_name_t type
) {
1954 mach_port_urefs_t refs
;
1955 kern_return_t ret
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs
);
1956 if (ret
!= KERN_SUCCESS
) refs
= 0;
1957 const char *type_name
= "???";
1959 case MACH_MSG_TYPE_MOVE_SEND
: type_name
= "MACH_MSG_TYPE_MOVE_SEND"; break;
1960 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break;
1961 case MACH_MSG_TYPE_MOVE_RECEIVE
: type_name
= "MACH_MSG_TYPE_MOVE_RECEIVE"; break;
1962 case MACH_MSG_TYPE_MAKE_SEND
: type_name
= "MACH_MSG_TYPE_MAKE_SEND"; break;
1963 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break;
1965 printf("%s\t%p\t%-20s\t%u\n", desc
, port
, type_name
, refs
);
1968 static void mach_msg_scan(mach_msg_header_t
*msg
, int clean
) {
1969 Boolean printed_header
= false;
1971 * The msgh_local_port field doesn't hold a port right.
1972 * The receive operation consumes the destination port right.
1974 if (MACH_PORT_NULL
!= msg
->msgh_remote_port
) {
1975 if (! printed_header
) print_msg_scan_header();
1976 printed_header
= true;
1977 print_one_port_info("msg->msgh_remote_port", msg
->msgh_remote_port
, MACH_MSGH_BITS_REMOTE(msg
->msgh_bits
));
1979 if (msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
1980 mach_msg_body_t
*body
= (mach_msg_body_t
*) (msg
+ 1);
1981 mach_msg_descriptor_t
*saddr
= (mach_msg_descriptor_t
*) ((mach_msg_base_t
*) msg
+ 1);
1982 mach_msg_descriptor_t
*eaddr
= saddr
+ body
->msgh_descriptor_count
;
1983 for ( ; saddr
< eaddr
; saddr
++) {
1984 switch (saddr
->type
.type
) {
1985 case MACH_MSG_PORT_DESCRIPTOR
:;
1986 mach_msg_port_descriptor_t
*dsc
= &saddr
->port
;
1987 if (! printed_header
) print_msg_scan_header();
1988 printed_header
= true;
1989 print_one_port_info("port in body", dsc
->name
, dsc
->disposition
);
1990 // if (clean) mach_port_deallocate(mach_task_self(), dsc->name);
1992 case MACH_MSG_OOL_PORTS_DESCRIPTOR
:;
1993 mach_msg_ool_ports_descriptor_t
*dsc2
= &saddr
->ool_ports
;
1994 mach_port_t
*ports
= (mach_port_t
*) dsc2
->address
;
1995 for (mach_msg_type_number_t j
= 0; j
< dsc2
->count
; j
++, ports
++) {
1996 if (! printed_header
) print_msg_scan_header();
1997 printed_header
= true;
1998 print_one_port_info("port in OOL ports", *ports
, dsc2
->disposition
);
2007 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
, Boolean waitIfEmpty
) __attribute__((noinline
));
2008 #if DEPLOYMENT_TARGET_WINDOWS
2009 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
);
2012 /* rl is unlocked, rlm locked on entrance and exit */
2013 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
, Boolean waitIfEmpty
) { /* DOES CALLOUT */
2015 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2016 mach_port_name_t timeoutPort
= MACH_PORT_NULL
;
2017 mach_port_name_t dispatchPort
= MACH_PORT_NULL
;
2018 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ
)));
2019 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) dispatchPort
= _dispatch_get_main_queue_port_4CF();
2021 Boolean poll
= false;
2022 Boolean firstPass
= true;
2024 if (__CFRunLoopIsStopped(rl
)) {
2025 __CFRunLoopUnsetStopped(rl
);
2026 return kCFRunLoopRunStopped
;
2027 } else if (rlm
->_stopped
) {
2028 rlm
->_stopped
= false;
2029 return kCFRunLoopRunStopped
;
2031 if (seconds
<= 0.0) {
2033 } else if (TIMER_INTERVAL_LIMIT
< seconds
) {
2034 termTSR
= LLONG_MAX
;
2036 termTSR
= (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds
);
2037 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2038 timeoutPort
= mk_timer_create();
2039 mk_timer_arm(timeoutPort
, __CFUInt64ToAbsoluteTime(termTSR
));
2042 if (seconds
<= 0.0) {
2045 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= CFPORT_NULL
;
2047 __CFPortSet waitSet
= CFPORT_NULL
;
2048 Boolean destroyWaitSet
= false;
2049 CFRunLoopSourceRef rls
;
2050 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2051 mach_msg_header_t
*msg
;
2053 uint8_t buffer
[2048];
2055 CFArrayRef timersToCall
= NULL
;
2057 int32_t returnValue
= 0;
2058 Boolean sourceHandledThisLoop
= false;
2060 // Do not handle blocks here, as there is already a handling at
2061 // the end of this loop, and that just makes for two handlings
2062 // in a row when the loop cycles.
2063 if (rlm
->_observerMask
& kCFRunLoopBeforeTimers
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
2064 if (rlm
->_observerMask
& kCFRunLoopBeforeSources
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
2065 if (rl
->_blocks_head
) {
2066 __CFRunLoopModeUnlock(rlm
);
2067 __CFRunLoopLock(rl
);
2068 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2069 __CFRunLoopModeLock(rlm
);
2070 __CFRunLoopUnlock(rl
);
2073 sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
) || sourceHandledThisLoop
;
2075 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2076 if (MACH_PORT_NULL
!= dispatchPort
) {
2077 msg
= (mach_msg_header_t
*)buffer
;
2078 msg
->msgh_size
= sizeof(buffer
);
2080 msg
->msgh_local_port
= dispatchPort
;
2081 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2083 ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|MACH_RCV_TIMEOUT
|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV
), 0, msg
->msgh_size
, dispatchPort
, 0, MACH_PORT_NULL
);
2085 if (MACH_MSG_SUCCESS
== ret
) {
2086 __CFRunLoopModeUnlock(rlm
);
2087 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)3);
2088 _dispatch_main_queue_callback_4CF(msg
);
2089 sourceHandledThisLoop
= true;
2090 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)0);
2091 __CFRunLoopLock(rl
);
2092 __CFRunLoopModeLock(rlm
);
2093 __CFRunLoopUnlock(rl
);
2094 } else if (MACH_RCV_TIMED_OUT
== ret
) {
2102 if (sourceHandledThisLoop
) {
2104 if (rl
->_blocks_head
) {
2105 __CFRunLoopModeUnlock(rlm
);
2106 __CFRunLoopLock(rl
);
2107 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2108 __CFRunLoopModeLock(rlm
);
2109 __CFRunLoopUnlock(rl
);
2114 if (rlm
->_observerMask
& kCFRunLoopBeforeWaiting
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
2115 // do not do any user callouts after this point (after notifying of sleeping)
2116 __CFRunLoopSetSleeping(rl
);
2118 if (NULL
!= rlm
->_submodes
) {
2119 // !!! what do we do if this doesn't succeed?
2120 waitSet
= __CFPortSetAllocate();
2121 if (CFPORT_NULL
== waitSet
) HALT
;
2122 __CFRunLoopModeUnlock(rlm
);
2123 __CFRunLoopLock(rl
);
2124 __CFRunLoopModeLock(rlm
);
2125 __CFRunLoopModeAddPortsToPortSet(rl
, rlm
, waitSet
);
2126 __CFRunLoopUnlock(rl
);
2127 destroyWaitSet
= true;
2129 waitSet
= rlm
->_portSet
;
2131 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2132 if (CFPORT_NULL
!= timeoutPort
) {
2133 __CFPortSetInsert(timeoutPort
, waitSet
);
2135 if (CFPORT_NULL
!= dispatchPort
) {
2136 __CFPortSetInsert(dispatchPort
, waitSet
);
2139 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= waitSet
;
2140 __CFRunLoopModeUnlock(rlm
);
2142 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2143 if (kCFUseCollectableAllocator
&& !poll
) {
2144 memset(buffer
, 0, sizeof(buffer
));
2145 objc_clear_stack(0);
2148 msg
= (mach_msg_header_t
*)buffer
;
2149 msg
->msgh_size
= sizeof(buffer
);
2151 //static uint64_t _last_value = 0;
2152 //uint64_t new_val = mach_absolute_time();
2153 //printf(". %d before %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2154 //_last_value = new_val;
2156 /* In that sleep of death what nightmares may come ... */
2159 msg
->msgh_local_port
= waitSet
;
2160 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2162 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_AV
), 0, msg
->msgh_size
, waitSet
, 0, MACH_PORT_NULL
);
2164 if (MACH_RCV_TOO_LARGE
== ret
) {
2165 uint32_t newSize
= round_msg(msg
->msgh_size
+ MAX_TRAILER_SIZE
);
2166 if (msg
== (mach_msg_header_t
*)buffer
) msg
= NULL
;
2167 msg
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, msg
, newSize
, 0);
2168 msg
->msgh_size
= newSize
;
2170 } else if (MACH_RCV_TIMED_OUT
== ret
) {
2171 // timeout, for poll
2172 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
2174 } else if (MACH_MSG_SUCCESS
!= ret
) {
2177 //new_val = mach_absolute_time();
2178 //printf(". %d after %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2179 //_last_value = new_val;
2180 #elif DEPLOYMENT_TARGET_WINDOWS
2181 DWORD waitResult
= WAIT_TIMEOUT
;
2182 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
2184 uint32_t handleCount
;
2185 Boolean freeHandles
;
2186 if (destroyWaitSet
) {
2187 // wait set is a local, no one else could modify it, no need to copy handles
2188 handles
= waitSet
->handles
;
2189 handleCount
= waitSet
->used
;
2190 freeHandles
= FALSE
;
2192 // copy out the handles to be safe from other threads at work
2193 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
2194 freeHandles
= (handles
!= handleBuf
);
2196 // should msgQMask be an OR'ing of this and all submodes' masks?
2197 if (0 == GetQueueStatus(rlm
->_msgQMask
)) {
2203 __CFRunLoopModeLock(rlm
);
2204 nextStop
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
2207 else if (nextStop
> termTSR
)
2209 // else the next stop is dictated by the next timer
2210 int64_t timeoutTSR
= nextStop
- __CFReadTSR();
2214 CFTimeInterval timeoutCF
= __CFTSRToTimeInterval(timeoutTSR
) * 1000;
2215 if (timeoutCF
> MAXDWORD
)
2218 timeout
= (DWORD
)timeoutCF
;
2221 waitResult
= WaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, timeout
);
2223 ResetEvent(rl
->_wakeUpPort
);
2225 __CFRunLoopLock(rl
);
2226 __CFRunLoopModeLock(rlm
);
2227 __CFRunLoopUnlock(rl
);
2228 if (destroyWaitSet
) {
2229 __CFPortSetFree(waitSet
);
2230 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= 0;
2232 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2233 if (CFPORT_NULL
!= timeoutPort
) {
2234 __CFPortSetRemove(timeoutPort
, waitSet
);
2236 if (CFPORT_NULL
!= dispatchPort
) {
2237 __CFPortSetRemove(dispatchPort
, waitSet
);
2243 __CFRunLoopUnsetSleeping(rl
);
2244 if (rlm
->_observerMask
& kCFRunLoopAfterWaiting
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
2247 __CFRunLoopModeUnlock(rlm
);
2248 __CFRunLoopLock(rl
);
2249 __CFRunLoopModeLock(rlm
);
2251 __CFPort livePort
= CFPORT_NULL
;
2252 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2254 livePort
= msg
->msgh_local_port
;
2256 #elif DEPLOYMENT_TARGET_WINDOWS
2257 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
2258 if (waitResult
== WAIT_TIMEOUT
) {
2259 // do nothing, just return to caller
2260 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
2261 // a handle was signaled
2262 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
2263 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
2264 // windows message received - the CFWindowsMessageQueue will pick this up when
2265 // the v0 RunLoopSources get their chance
2266 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
2267 // an "abandoned mutex object"
2268 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
2270 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
2273 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
2274 timersToCall
= __CFRunLoopTimersToFire(rl
, rlm
);
2277 if (CFPORT_NULL
== livePort
) {
2278 __CFRunLoopUnlock(rl
);
2279 } else if (livePort
== rl
->_wakeUpPort
) {
2281 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("wakeupPort was signalled")); }
2282 __CFRunLoopUnlock(rl
); // leave run loop unlocked
2284 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2285 else if (livePort
== timeoutPort
) {
2286 returnValue
= kCFRunLoopRunTimedOut
;
2287 __CFRunLoopUnlock(rl
);
2288 } else if (dispatchPort
== livePort
) {
2289 __CFRunLoopModeUnlock(rlm
);
2290 __CFRunLoopUnlock(rl
);
2291 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)3);
2292 _dispatch_main_queue_callback_4CF(msg
);
2293 sourceHandledThisLoop
= true;
2294 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)0);
2295 __CFRunLoopLock(rl
);
2296 __CFRunLoopModeLock(rlm
);
2297 __CFRunLoopUnlock(rl
); // leave run loop unlocked
2298 } else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
2299 mach_msg_header_t
*reply
= NULL
;
2300 __CFRunLoopUnlock(rl
);
2301 // mach_msg_scan(msg, 0);
2302 if (__CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
)) {
2303 sourceHandledThisLoop
= true;
2305 // mach_msg_scan(msg, 1);
2306 if (NULL
!= reply
) {
2307 ret
= mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
2308 //#warning CF: what should be done with the return value?
2309 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
2312 CFRunLoopTimerRef rlt
;
2313 rlt
= __CFRunLoopModeFindTimerForMachPort(rlm
, livePort
);
2314 __CFRunLoopUnlock(rl
);
2316 __CFRunLoopDoTimer(rl
, rlm
, rlt
);
2319 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
2321 else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
2322 __CFRunLoopUnlock(rl
);
2323 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("Source %@ was signalled"), rls
); }
2324 if (__CFRunLoopDoSource1(rl
, rlm
, rls
)) {
2325 sourceHandledThisLoop
= true;
2330 #if DEPLOYMENT_TARGET_WINDOWS
2331 if (NULL
!= timersToCall
) {
2333 for (i
= CFArrayGetCount(timersToCall
)-1; i
>= 0; i
--)
2334 __CFRunLoopDoTimer(rl
, rlm
, (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timersToCall
, i
));
2335 CFRelease(timersToCall
);
2339 if (rl
->_blocks_head
) {
2340 __CFRunLoopModeUnlock(rlm
); // locks must be taken in order
2341 __CFRunLoopLock(rl
);
2342 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2343 __CFRunLoopModeLock(rlm
);
2344 __CFRunLoopUnlock(rl
);
2346 if (sourceHandledThisLoop
&& stopAfterHandle
) {
2347 returnValue
= kCFRunLoopRunHandledSource
;
2348 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
2349 // internal wakeup signal on the first look at the portset, we'll go around the loop one
2350 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
2351 } else if (0 != returnValue
|| (uint64_t)termTSR
<= __CFReadTSR()) {
2352 returnValue
= kCFRunLoopRunTimedOut
;
2353 } else if (__CFRunLoopIsStopped(rl
)) {
2354 __CFRunLoopUnsetStopped(rl
);
2355 returnValue
= kCFRunLoopRunStopped
;
2356 } else if (rlm
->_stopped
) {
2357 rlm
->_stopped
= false;
2358 returnValue
= kCFRunLoopRunStopped
;
2359 } else if (!waitIfEmpty
&& __CFRunLoopModeIsEmpty(rl
, rlm
, previousMode
)) {
2360 returnValue
= kCFRunLoopRunFinished
;
2362 if (0 != returnValue
) {
2363 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2364 if (MACH_PORT_NULL
!= timeoutPort
) {
2365 mk_timer_destroy(timeoutPort
);
2374 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2376 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
2377 __CFRunLoopLock(rl
);
2378 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
2379 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
, rl
->_currentMode
)) {
2380 Boolean did
= false;
2381 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2383 if (rl
->_blocks_head
) {
2384 __CFRunLoopDoBlocks(rl
, modeName
);
2387 __CFRunLoopUnlock(rl
);
2388 return did
? kCFRunLoopRunHandledSource
: kCFRunLoopRunFinished
;
2390 uint32_t *previousStopped
= (uint32_t *)rl
->_stopped
;
2391 rl
->_stopped
= NULL
;
2392 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
2393 rl
->_currentMode
= currentMode
;
2394 #if DEPLOYMENT_TARGET_WINDOWS
2395 if (previousMode
&& currentMode
!= previousMode
) {
2396 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2397 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
2399 __CFRunLoopUpdateMsgWait(rl
);
2402 __CFRunLoopUnlock(rl
);
2405 if (currentMode
->_observerMask
& kCFRunLoopEntry
|| currentMode
->_submodes
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
2406 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, previousMode
, false);
2407 if (currentMode
->_observerMask
& kCFRunLoopExit
|| currentMode
->_submodes
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
2409 // this kvetches if an exception was raised during a run loop callout, because the mode is not locked
2410 if (0 != currentMode
->_lock
) {
2411 __CFRunLoopModeUnlock(currentMode
);
2413 __CFRunLoopLock(rl
);
2414 if (rl
->_stopped
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (uint32_t *)rl
->_stopped
);
2415 rl
->_stopped
= previousStopped
;
2416 rl
->_currentMode
= previousMode
;
2417 #if DEPLOYMENT_TARGET_WINDOWS
2418 if (previousMode
&& currentMode
!= previousMode
) {
2419 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2420 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
2422 __CFRunLoopUpdateMsgWait(rl
);
2425 __CFRunLoopUnlock(rl
);
2430 void CFRunLoopRun(void) { /* DOES CALLOUT */
2433 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
2435 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
2438 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2440 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
2443 static void __CFRunLoopFindMinTimer(const void *value
, void *ctx
) {
2444 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
2445 if (__CFIsValid(rlt
)) {
2446 CFRunLoopTimerRef
*result
= (CFRunLoopTimerRef
*)ctx
;
2447 if (NULL
== *result
|| rlt
->_fireTSR
< (*result
)->_fireTSR
) {
2453 #if DEPLOYMENT_TARGET_WINDOWS
2454 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
2455 CFRunLoopTimerRef result
= NULL
;
2456 int64_t fireTime
= 0;
2458 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
2459 __CFRunLoopTimerFireTSRLock();
2460 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
2462 fireTime
= result
->_fireTSR
;
2463 __CFRunLoopTimerFireTSRUnlock();
2465 if (NULL
!= rlm
->_submodes
) {
2467 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
2468 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
2469 CFRunLoopModeRef subrlm
;
2470 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2471 if (NULL
!= subrlm
) {
2472 int64_t newFireTime
= __CFRunLoopGetNextTimerFireTSR(rl
, subrlm
);
2473 __CFRunLoopModeUnlock(subrlm
);
2474 if (fireTime
== 0 || (newFireTime
!= 0 && newFireTime
< fireTime
))
2475 fireTime
= newFireTime
;
2479 __CFRunLoopModeUnlock(rlm
);
2485 // called with rlm locked, if not NULL
2486 static CFAbsoluteTime
__CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
2487 CFRunLoopTimerRef result
= NULL
;
2488 CFAbsoluteTime fireDate
= 0.0;
2489 int64_t now2
= (int64_t)mach_absolute_time();
2490 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2492 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
2493 __CFRunLoopTimerFireTSRLock();
2494 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
2496 fireDate
= (0 == result
->_fireTSR
) ? 0.0 : (now1
+ __CFTSRToTimeInterval(result
->_fireTSR
- now2
));
2498 __CFRunLoopTimerFireTSRUnlock();
2500 if (NULL
!= rlm
->_submodes
) {
2502 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
2503 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
2504 CFRunLoopModeRef subrlm
;
2505 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2506 if (NULL
!= subrlm
) {
2507 CFAbsoluteTime newFireDate
= __CFRunLoopGetNextTimerFireDate(rl
, subrlm
);
2508 __CFRunLoopModeUnlock(subrlm
);
2509 if (fireDate
== 0 || (newFireDate
!= 0.0 && newFireDate
< fireDate
))
2510 fireDate
= newFireDate
;
2514 __CFRunLoopModeUnlock(rlm
);
2519 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
2521 CFRunLoopModeRef rlm
;
2522 __CFRunLoopLock(rl
);
2523 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2524 __CFRunLoopUnlock(rl
);
2525 return __CFRunLoopGetNextTimerFireDate(rl
, rlm
);
2528 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
2530 return __CFRunLoopIsSleeping(rl
);
2533 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
2535 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2537 /* We unconditionally try to send the message, since we don't want
2538 * to lose a wakeup, but the send may fail if there is already a
2539 * wakeup pending, since the queue length is 1. */
2540 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
2541 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
2545 SetEvent(rl
->_wakeUpPort
);
2546 __CFRunLoopLock(rl
);
2547 if (rl
->_threadID
== GetCurrentThreadId()) {
2548 PostMessageW(NULL
, __kCFRunLoopWakeUpMessage
, NULL
, NULL
);
2550 PostThreadMessageW(rl
->_threadID
, __kCFRunLoopWakeUpMessage
, NULL
, NULL
);
2552 __CFRunLoopUnlock(rl
);
2556 void CFRunLoopStop(CFRunLoopRef rl
) {
2557 Boolean doWake
= false;
2559 __CFRunLoopLock(rl
);
2560 if (rl
->_currentMode
) {
2561 __CFRunLoopSetStopped(rl
);
2564 __CFRunLoopUnlock(rl
);
2566 CFRunLoopWakeUp(rl
);
2570 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
2572 CFRunLoopModeRef rlm
;
2573 __CFRunLoopLock(rl
);
2574 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2575 __CFRunLoopUnlock(rl
);
2577 rlm
->_stopped
= true;
2578 __CFRunLoopModeUnlock(rlm
);
2580 CFRunLoopWakeUp(rl
);
2583 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2585 CFRunLoopModeRef rlm
;
2586 if (modeName
== kCFRunLoopCommonModes
|| candidateContainedName
== kCFRunLoopCommonModes
) {
2588 } else if (CFEqual(modeName
, candidateContainedName
)) {
2591 __CFRunLoopLock(rl
);
2592 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2593 __CFRunLoopUnlock(rl
);
2595 CFArrayRef submodes
;
2596 if (NULL
== rlm
->_submodes
) {
2597 __CFRunLoopModeUnlock(rlm
);
2600 if (CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), candidateContainedName
)) {
2601 __CFRunLoopModeUnlock(rlm
);
2604 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
2605 __CFRunLoopModeUnlock(rlm
);
2606 if (NULL
!= submodes
) {
2608 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
2609 CFStringRef subname
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
2610 if (_CFRunLoopModeContainsMode(rl
, subname
, candidateContainedName
)) {
2611 CFRelease(submodes
);
2615 CFRelease(submodes
);
2621 CF_EXPORT
void _CFRunLoopAddModeToMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef toModeName
) {
2623 CFRunLoopModeRef rlm
;
2624 if (__CFRunLoopIsDeallocating(rl
)) return;
2625 // should really do a recursive check here, to make sure that a cycle isn't
2626 // introduced; of course, if that happens, you aren't going to get very far.
2627 if (modeName
== kCFRunLoopCommonModes
|| toModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, toModeName
)) {
2630 __CFRunLoopLock(rl
);
2631 rlm
= __CFRunLoopFindMode(rl
, toModeName
, true);
2632 __CFRunLoopUnlock(rl
);
2634 if (NULL
== rlm
->_submodes
) {
2635 rlm
->_submodes
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2637 if (!CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), modeName
)) {
2638 CFArrayAppendValue(rlm
->_submodes
, modeName
);
2640 __CFRunLoopModeUnlock(rlm
);
2645 CF_EXPORT
void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef fromModeName
) {
2647 CFRunLoopModeRef rlm
;
2648 // should really do a recursive check here, to make sure that a cycle isn't
2649 // introduced; of course, if that happens, you aren't going to get very far.
2650 if (modeName
== kCFRunLoopCommonModes
|| fromModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, fromModeName
)) {
2653 __CFRunLoopLock(rl
);
2654 rlm
= __CFRunLoopFindMode(rl
, fromModeName
, true);
2655 __CFRunLoopUnlock(rl
);
2657 if (NULL
!= rlm
->_submodes
) {
2658 CFIndex idx
, cnt
= CFArrayGetCount(rlm
->_submodes
);
2659 idx
= CFArrayGetFirstIndexOfValue(rlm
->_submodes
, CFRangeMake(0, cnt
), modeName
);
2660 if (0 <= idx
) CFArrayRemoveValueAtIndex(rlm
->_submodes
, idx
);
2662 __CFRunLoopModeUnlock(rlm
);
2667 void CFRunLoopPerformBlock(CFRunLoopRef rl
, CFTypeRef mode
, void (^block
)(void)) {
2669 if (CFStringGetTypeID() == CFGetTypeID(mode
)) {
2670 mode
= CFStringCreateCopy(kCFAllocatorSystemDefault
, (CFStringRef
)mode
);
2671 __CFRunLoopLock(rl
);
2672 // ensure mode exists
2673 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)mode
, true);
2674 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2675 __CFRunLoopUnlock(rl
);
2676 } else if (CFArrayGetTypeID() == CFGetTypeID(mode
)) {
2677 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)mode
);
2678 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2679 CFArrayGetValues((CFArrayRef
)mode
, CFRangeMake(0, cnt
), values
);
2680 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2681 __CFRunLoopLock(rl
);
2682 // ensure modes exist
2683 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2684 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2685 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2687 __CFRunLoopUnlock(rl
);
2689 } else if (CFSetGetTypeID() == CFGetTypeID(mode
)) {
2690 CFIndex cnt
= CFSetGetCount((CFSetRef
)mode
);
2691 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2692 CFSetGetValues((CFSetRef
)mode
, values
);
2693 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2694 __CFRunLoopLock(rl
);
2695 // ensure modes exist
2696 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2697 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2698 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2700 __CFRunLoopUnlock(rl
);
2705 #if DEPLOYMENT_TARGET_WINDOWS
2706 // <rdar://problem/6496715> Block.h uses "typeof", which is not available when using Visual Studio on Windows
2707 block
= (void (^)(void))_Block_copy(block
);
2709 block
= Block_copy(block
);
2711 if (!mode
|| !block
) {
2712 if (mode
) CFRelease(mode
);
2713 if (block
) Block_release(block
);
2716 __CFRunLoopLock(rl
);
2717 struct _block_item
*new_item
= (struct _block_item
*)malloc(sizeof(struct _block_item
));
2718 new_item
->_next
= NULL
;
2719 new_item
->_mode
= mode
;
2720 new_item
->_block
= block
;
2721 if (!rl
->_blocks_tail
) {
2722 rl
->_blocks_head
= new_item
;
2724 rl
->_blocks_tail
->_next
= new_item
;
2726 rl
->_blocks_tail
= new_item
;
2727 __CFRunLoopUnlock(rl
);
2730 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2732 CFRunLoopModeRef rlm
;
2733 Boolean hasValue
= false;
2734 __CFRunLoopLock(rl
);
2735 if (modeName
== kCFRunLoopCommonModes
) {
2736 if (NULL
!= rl
->_commonModeItems
) {
2737 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2739 __CFRunLoopUnlock(rl
);
2741 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2742 __CFRunLoopUnlock(rl
);
2743 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2744 hasValue
= CFSetContainsValue(rlm
->_sources
, rls
);
2745 __CFRunLoopModeUnlock(rlm
);
2746 } else if (NULL
!= rlm
) {
2747 __CFRunLoopModeUnlock(rlm
);
2753 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2755 CFRunLoopModeRef rlm
;
2756 if (__CFRunLoopIsDeallocating(rl
)) return;
2757 if (!__CFIsValid(rls
)) return;
2758 __CFRunLoopLock(rl
);
2759 if (modeName
== kCFRunLoopCommonModes
) {
2760 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2761 if (NULL
== rl
->_commonModeItems
) {
2762 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2763 _CFSetSetCapacity(rl
->_commonModeItems
, 20);
2765 CFSetAddValue(rl
->_commonModeItems
, rls
);
2766 __CFRunLoopUnlock(rl
);
2768 CFTypeRef context
[2] = {rl
, rls
};
2769 /* add new item to all common-modes */
2770 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2774 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2775 __CFRunLoopUnlock(rl
);
2776 if (NULL
!= rlm
&& NULL
== rlm
->_sources
) {
2777 rlm
->_sources
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2778 rlm
->_portToV1SourceMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
2779 _CFSetSetCapacity(rlm
->_sources
, 10);
2781 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources
, rls
)) {
2782 CFSetAddValue(rlm
->_sources
, rls
);
2783 if (1 == rls
->_context
.version0
.version
) {
2784 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2785 CFDictionarySetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
, rls
);
2787 __CFRunLoopModeUnlock(rlm
);
2788 __CFRunLoopSourceSchedule(rls
, rl
, rlm
); /* DOES CALLOUT */
2789 } else if (NULL
!= rlm
) {
2790 __CFRunLoopModeUnlock(rlm
);
2795 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2797 CFRunLoopModeRef rlm
;
2798 __CFRunLoopLock(rl
);
2799 if (modeName
== kCFRunLoopCommonModes
) {
2800 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2801 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2802 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2803 __CFRunLoopUnlock(rl
);
2805 CFTypeRef context
[2] = {rl
, rls
};
2806 /* remove new item from all common-modes */
2807 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2811 __CFRunLoopUnlock(rl
);
2814 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2815 __CFRunLoopUnlock(rl
);
2816 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
&& CFSetContainsValue(rlm
->_sources
, rls
)) {
2818 if (1 == rls
->_context
.version0
.version
) {
2819 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2820 CFDictionaryRemoveValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
);
2822 CFSetRemoveValue(rlm
->_sources
, rls
);
2823 __CFRunLoopModeUnlock(rlm
);
2824 __CFRunLoopSourceCancel(rls
, rl
, rlm
); /* DOES CALLOUT */
2826 } else if (NULL
!= rlm
) {
2827 __CFRunLoopModeUnlock(rlm
);
2832 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value
, void *ctx
) {
2833 CFStringRef modeName
= (CFStringRef
)value
;
2834 CFRunLoopRef rl
= (CFRunLoopRef
)ctx
;
2835 __CFRunLoopRemoveAllSources(rl
, modeName
);
2838 static void __CFRunLoopRemoveSourceFromMode(const void *value
, void *ctx
) {
2839 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
2840 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
2841 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
2842 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2845 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
) {
2847 CFRunLoopModeRef rlm
;
2848 __CFRunLoopLock(rl
);
2849 if (modeName
== kCFRunLoopCommonModes
) {
2850 if (NULL
!= rl
->_commonModeItems
) {
2851 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2852 __CFRunLoopUnlock(rl
);
2854 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourcesFromCommonMode
), (void *)rl
);
2858 __CFRunLoopUnlock(rl
);
2861 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2862 __CFRunLoopUnlock(rl
);
2863 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2864 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources
);
2865 __CFRunLoopModeUnlock(rlm
);
2866 CFTypeRef context
[2] = {rl
, modeName
};
2867 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2869 } else if (NULL
!= rlm
) {
2870 __CFRunLoopModeUnlock(rlm
);
2875 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2877 CFRunLoopModeRef rlm
;
2878 Boolean hasValue
= false;
2879 __CFRunLoopLock(rl
);
2880 if (modeName
== kCFRunLoopCommonModes
) {
2881 if (NULL
!= rl
->_commonModeItems
) {
2882 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2884 __CFRunLoopUnlock(rl
);
2886 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2887 __CFRunLoopUnlock(rl
);
2888 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2889 hasValue
= CFSetContainsValue(rlm
->_observers
, rlo
);
2890 __CFRunLoopModeUnlock(rlm
);
2891 } else if (NULL
!= rlm
) {
2892 __CFRunLoopModeUnlock(rlm
);
2898 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2900 CFRunLoopModeRef rlm
;
2901 if (__CFRunLoopIsDeallocating(rl
)) return;
2902 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2903 __CFRunLoopLock(rl
);
2904 if (modeName
== kCFRunLoopCommonModes
) {
2905 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2906 if (NULL
== rl
->_commonModeItems
) {
2907 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2909 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2910 __CFRunLoopUnlock(rl
);
2912 CFTypeRef context
[2] = {rl
, rlo
};
2913 /* add new item to all common-modes */
2914 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2918 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2919 __CFRunLoopUnlock(rl
);
2920 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2921 rlm
->_observers
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2923 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_observers
, rlo
)) {
2924 CFSetAddValue(rlm
->_observers
, rlo
);
2925 rlm
->_observerMask
|= rlo
->_activities
;
2926 __CFRunLoopModeUnlock(rlm
);
2927 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
2928 } else if (NULL
!= rlm
) {
2929 __CFRunLoopModeUnlock(rlm
);
2934 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2936 CFRunLoopModeRef rlm
;
2937 __CFRunLoopLock(rl
);
2938 if (modeName
== kCFRunLoopCommonModes
) {
2939 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
2940 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2941 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
2942 __CFRunLoopUnlock(rl
);
2944 CFTypeRef context
[2] = {rl
, rlo
};
2945 /* remove new item from all common-modes */
2946 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2950 __CFRunLoopUnlock(rl
);
2953 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2954 __CFRunLoopUnlock(rl
);
2955 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
&& CFSetContainsValue(rlm
->_observers
, rlo
)) {
2957 CFSetRemoveValue(rlm
->_observers
, rlo
);
2958 __CFRunLoopModeUnlock(rlm
);
2959 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
2961 } else if (NULL
!= rlm
) {
2962 __CFRunLoopModeUnlock(rlm
);
2967 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2969 CFRunLoopModeRef rlm
;
2970 Boolean hasValue
= false;
2971 __CFRunLoopLock(rl
);
2972 if (modeName
== kCFRunLoopCommonModes
) {
2973 if (NULL
!= rl
->_commonModeItems
) {
2974 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
2976 __CFRunLoopUnlock(rl
);
2978 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2979 __CFRunLoopUnlock(rl
);
2980 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2981 hasValue
= CFSetContainsValue(rlm
->_timers
, rlt
);
2982 __CFRunLoopModeUnlock(rlm
);
2983 } else if (NULL
!= rlm
) {
2984 __CFRunLoopModeUnlock(rlm
);
2990 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2992 //CFLog(4, CFSTR("CFRunLoopAddTimer(%p, timer %p, %@)"), rl, rlt, modeName);
2993 CFRunLoopModeRef rlm
;
2994 if (__CFRunLoopIsDeallocating(rl
)) return;
2995 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
2996 __CFRunLoopLock(rl
);
2997 if (modeName
== kCFRunLoopCommonModes
) {
2998 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2999 if (NULL
== rl
->_commonModeItems
) {
3000 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3002 CFSetAddValue(rl
->_commonModeItems
, rlt
);
3003 __CFRunLoopUnlock(rl
);
3005 CFTypeRef context
[2] = {rl
, rlt
};
3006 /* add new item to all common-modes */
3007 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
3011 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
3012 __CFRunLoopUnlock(rl
);
3013 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
3014 rlm
->_timers
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3016 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_timers
, rlt
)) {
3017 CFSetAddValue(rlm
->_timers
, rlt
);
3018 __CFRunLoopModeUnlock(rlm
);
3019 __CFRunLoopTimerSchedule(rlt
, rl
, rlm
);
3020 } else if (NULL
!= rlm
) {
3021 __CFRunLoopModeUnlock(rlm
);
3026 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3028 //CFLog(4, CFSTR("CFRunLoopRemoveTimer(%p, timer %p, %@)"), rl, rlt, modeName);
3029 CFRunLoopModeRef rlm
;
3030 __CFRunLoopLock(rl
);
3031 if (modeName
== kCFRunLoopCommonModes
) {
3032 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
3033 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3034 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
3035 __CFRunLoopUnlock(rl
);
3037 CFTypeRef context
[2] = {rl
, rlt
};
3038 /* remove new item from all common-modes */
3039 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3043 __CFRunLoopUnlock(rl
);
3046 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3047 __CFRunLoopUnlock(rl
);
3048 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
&& CFSetContainsValue(rlm
->_timers
, rlt
)) {
3050 CFSetRemoveValue(rlm
->_timers
, rlt
);
3051 __CFRunLoopModeUnlock(rlm
);
3052 __CFRunLoopTimerCancel(rlt
, rl
, rlm
);
3054 } else if (NULL
!= rlm
) {
3055 __CFRunLoopModeUnlock(rlm
);
3061 /* CFRunLoopSource */
3063 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
3064 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
3065 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
3066 if (rls1
== rls2
) return true;
3067 if (__CFIsValid(rls1
) != __CFIsValid(rls2
)) return false;
3068 if (rls1
->_order
!= rls2
->_order
) return false;
3069 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
3070 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
3071 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
3072 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
3073 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
3074 if (rls1
->_context
.version0
.equal
)
3075 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
3076 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
3079 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
3080 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3081 if (rls
->_context
.version0
.hash
)
3082 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
3083 return (CFHashCode
)rls
->_context
.version0
.info
;
3086 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3087 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3089 CFStringRef contextDesc
= NULL
;
3090 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
3091 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
3093 if (NULL
== contextDesc
) {
3094 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
3095 #if DEPLOYMENT_TARGET_WINDOWS
3096 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, addr
);
3097 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3099 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3100 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
3102 #error Unknown or unspecified DEPLOYMENT_TARGET
3105 #if DEPLOYMENT_TARGET_WINDOWS
3106 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), "unknown", __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
3108 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), lockCount(rls
->_lock
) ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
3110 CFRelease(contextDesc
);
3114 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3115 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3116 CFRunLoopSourceInvalidate(rls
);
3117 if (rls
->_context
.version0
.release
) {
3118 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
3120 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0, sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
));
3123 static const CFRuntimeClass __CFRunLoopSourceClass
= {
3124 _kCFRuntimeScannedObject
,
3128 __CFRunLoopSourceDeallocate
,
3129 __CFRunLoopSourceEqual
,
3130 __CFRunLoopSourceHash
,
3132 __CFRunLoopSourceCopyDescription
3135 __private_extern__
void __CFRunLoopSourceInitialize(void) {
3136 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
3139 CFTypeID
CFRunLoopSourceGetTypeID(void) {
3140 return __kCFRunLoopSourceTypeID
;
3143 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
3145 CFRunLoopSourceRef memory
;
3147 if (NULL
== context
) HALT
;
3148 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
3149 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
3150 if (NULL
== memory
) {
3153 __CFSetValid(memory
);
3154 __CFRunLoopSourceUnsetSignaled(memory
);
3155 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3157 memory
->_order
= order
;
3158 memory
->_runLoops
= NULL
;
3160 switch (context
->version
) {
3162 size
= sizeof(CFRunLoopSourceContext
);
3165 size
= sizeof(CFRunLoopSourceContext1
);
3167 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3169 size
= sizeof(CFRunLoopSourceContext2
);
3173 objc_memmove_collectable(&memory
->_context
, context
, size
);
3174 if (context
->retain
) {
3175 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
3180 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
3182 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3186 static void __CFRunLoopSourceWakeUpLoop(const void *value
, void *context
) {
3187 CFRunLoopWakeUp((CFRunLoopRef
)value
);
3190 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
3191 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
3192 CFTypeRef
*params
= (CFTypeRef
*)context
;
3193 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
3196 if (rl
== params
[1]) return;
3197 array
= CFRunLoopCopyAllModes(rl
);
3198 for (idx
= CFArrayGetCount(array
); idx
--;) {
3199 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3200 CFRunLoopRemoveSource(rl
, rls
, modeName
);
3202 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
3207 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
3209 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3211 __CFRunLoopSourceLock(rls
);
3212 if (__CFIsValid(rls
)) {
3213 __CFUnsetValid(rls
);
3214 __CFRunLoopSourceUnsetSignaled(rls
);
3215 if (NULL
!= rls
->_runLoops
) {
3216 CFTypeRef params
[2] = {rls
, NULL
};
3217 CFBagRef bag
= rls
->_runLoops
;
3218 rls
->_runLoops
= NULL
;
3219 __CFRunLoopSourceUnlock(rls
);
3220 CFBagApplyFunction(bag
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
3223 __CFRunLoopSourceUnlock(rls
);
3225 /* for hashing- and equality-use purposes, can't actually release the context here */
3227 __CFRunLoopSourceUnlock(rls
);
3232 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
3234 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3235 return __CFIsValid(rls
);
3238 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
3240 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3241 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
3243 switch (context
->version
) {
3245 size
= sizeof(CFRunLoopSourceContext
);
3248 size
= sizeof(CFRunLoopSourceContext1
);
3250 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3252 size
= sizeof(CFRunLoopSourceContext2
);
3256 memmove(context
, &rls
->_context
, size
);
3259 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
3261 __CFRunLoopSourceLock(rls
);
3262 if (__CFIsValid(rls
)) {
3263 __CFRunLoopSourceSetSignaled(rls
);
3265 __CFRunLoopSourceUnlock(rls
);
3268 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
3270 __CFRunLoopSourceLock(rls
);
3271 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
3272 __CFRunLoopSourceUnlock(rls
);
3276 __private_extern__
void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
) {
3277 __CFRunLoopSourceLock(rls
);
3278 if (__CFIsValid(rls
) && NULL
!= rls
->_runLoops
) {
3279 CFBagApplyFunction(rls
->_runLoops
, __CFRunLoopSourceWakeUpLoop
, NULL
);
3281 __CFRunLoopSourceUnlock(rls
);
3284 /* CFRunLoopObserver */
3286 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3287 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3289 CFStringRef contextDesc
= NULL
;
3290 if (NULL
!= rlo
->_context
.copyDescription
) {
3291 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
3294 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
3296 #if DEPLOYMENT_TARGET_WINDOWS
3297 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf
, CFGetAllocator(rlo
), "unknown", __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, rlo
->_callout
, contextDesc
);
3298 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3299 void *addr
= rlo
->_callout
;
3301 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3302 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlo
), lockCount(rlo
->_lock
) ? "Yes" : "No", __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, name
, addr
, contextDesc
);
3304 #error Unknown or unspecified DEPLOYMENT_TARGET
3306 CFRelease(contextDesc
);
3310 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3311 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3312 CFRunLoopObserverInvalidate(rlo
);
3315 static const CFRuntimeClass __CFRunLoopObserverClass
= {
3317 "CFRunLoopObserver",
3320 __CFRunLoopObserverDeallocate
,
3324 __CFRunLoopObserverCopyDescription
3327 __private_extern__
void __CFRunLoopObserverInitialize(void) {
3328 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
3331 CFTypeID
CFRunLoopObserverGetTypeID(void) {
3332 return __kCFRunLoopObserverTypeID
;
3335 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
3337 CFRunLoopObserverRef memory
;
3339 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
3340 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
3341 if (NULL
== memory
) {
3344 __CFSetValid(memory
);
3345 __CFRunLoopObserverUnsetFiring(memory
);
3347 __CFRunLoopObserverSetRepeats(memory
);
3349 __CFRunLoopObserverUnsetRepeats(memory
);
3351 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3352 memory
->_runLoop
= NULL
;
3353 memory
->_rlCount
= 0;
3354 memory
->_activities
= activities
;
3355 memory
->_order
= order
;
3356 memory
->_callout
= callout
;
3358 if (context
->retain
) {
3359 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3361 memory
->_context
.info
= context
->info
;
3363 memory
->_context
.retain
= context
->retain
;
3364 memory
->_context
.release
= context
->release
;
3365 memory
->_context
.copyDescription
= context
->copyDescription
;
3367 memory
->_context
.info
= 0;
3368 memory
->_context
.retain
= 0;
3369 memory
->_context
.release
= 0;
3370 memory
->_context
.copyDescription
= 0;
3375 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
3377 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3378 return rlo
->_activities
;
3381 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
3383 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3387 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
3389 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3390 return __CFRunLoopObserverRepeats(rlo
);
3393 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
3395 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3397 __CFRunLoopObserverLock(rlo
);
3398 if (__CFIsValid(rlo
)) {
3399 CFRunLoopRef rl
= rlo
->_runLoop
;
3400 __CFUnsetValid(rlo
);
3401 __CFRunLoopObserverUnlock(rlo
);
3405 array
= CFRunLoopCopyAllModes(rl
);
3406 for (idx
= CFArrayGetCount(array
); idx
--;) {
3407 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3408 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
3410 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
3413 if (rlo
->_context
.release
)
3414 rlo
->_context
.release(rlo
->_context
.info
); /* CALLOUT */
3415 rlo
->_context
.info
= NULL
;
3417 __CFRunLoopObserverUnlock(rlo
);
3422 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
3424 return __CFIsValid(rlo
);
3427 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
3429 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3430 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3431 *context
= rlo
->_context
;
3434 /* CFRunLoopTimer */
3436 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3437 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3439 int64_t now2
= (int64_t)mach_absolute_time();
3440 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3441 __CFRunLoopTimerFireTSRLock();
3442 int64_t fireTime
= rlt
->_fireTSR
;
3443 __CFRunLoopTimerFireTSRUnlock();
3444 CFAbsoluteTime fireDate
= now1
+ __CFTSRToTimeInterval(fireTime
- now2
);
3445 CFStringRef contextDesc
= NULL
;
3446 if (NULL
!= rlt
->_context
.copyDescription
) {
3447 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
3449 if (NULL
== contextDesc
) {
3450 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
3452 #if DEPLOYMENT_TARGET_WINDOWS
3453 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf
, CFGetAllocator(rlt
), "unknown", __CFIsValid(rlt
) ? "Yes" : "No", __CFTSRToTimeInterval(rlt
->_intervalTSR
), now1
+ __CFTSRToTimeInterval(fireTime
- now2
), rlt
->_order
, rlt
->_callout
, contextDesc
);
3454 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3455 void *addr
= rlt
->_callout
;
3457 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3458 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlt
), lockCount(rlt
->_lock
) ? "Yes" : "No", __CFIsValid(rlt
) ? "Yes" : "No", rlt
->_interval
, fireDate
, rlt
->_order
, name
, addr
, contextDesc
);
3460 #error Unknown or unspecified DEPLOYMENT_TARGET
3462 CFRelease(contextDesc
);
3466 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3467 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3468 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3469 __CFRunLoopTimerSetDeallocating(rlt
);
3470 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
3471 CFRelease(rlt
->_rlModes
);
3472 rlt
->_rlModes
= NULL
;
3475 static const CFRuntimeClass __CFRunLoopTimerClass
= {
3480 __CFRunLoopTimerDeallocate
,
3484 __CFRunLoopTimerCopyDescription
3487 __private_extern__
void __CFRunLoopTimerInitialize(void) {
3488 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
3491 CFTypeID
CFRunLoopTimerGetTypeID(void) {
3492 return __kCFRunLoopTimerTypeID
;
3495 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
3497 CFRunLoopTimerRef memory
;
3499 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
3500 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
3501 if (NULL
== memory
) {
3504 __CFSetValid(memory
);
3505 __CFRunLoopTimerUnsetFiring(memory
);
3506 __CFRunLoopTimerUnsetDidFire(memory
);
3507 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3508 memory
->_runLoop
= NULL
;
3509 memory
->_rlModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3510 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3511 memory
->_port
= MACH_PORT_NULL
;
3513 memory
->_order
= order
;
3514 if (interval
< 0.0) interval
= 0.0;
3515 memory
->_interval
= interval
;
3516 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3517 if (TIMER_INTERVAL_LIMIT
< interval
) interval
= TIMER_INTERVAL_LIMIT
;
3518 memory
->_nextFireDate
= fireDate
;
3519 int64_t now2
= (int64_t)mach_absolute_time();
3520 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3521 if (fireDate
< now1
) {
3522 memory
->_fireTSR
= now2
;
3523 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
3524 memory
->_fireTSR
= LLONG_MAX
;
3526 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3528 if (interval
<= 0.0) {
3529 memory
->_intervalTSR
= 0;
3530 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < interval
) {
3531 memory
->_intervalTSR
= LLONG_MAX
;
3533 memory
->_intervalTSR
= __CFTimeIntervalToTSR(interval
);
3535 memory
->_callout
= callout
;
3536 if (NULL
!= context
) {
3537 if (context
->retain
) {
3538 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3540 memory
->_context
.info
= context
->info
;
3542 memory
->_context
.retain
= context
->retain
;
3543 memory
->_context
.release
= context
->release
;
3544 memory
->_context
.copyDescription
= context
->copyDescription
;
3546 memory
->_context
.info
= 0;
3547 memory
->_context
.retain
= 0;
3548 memory
->_context
.release
= 0;
3549 memory
->_context
.copyDescription
= 0;
3551 //CFLog(4, CFSTR("CFRunLoopTimerCreate(%p, %f, %f, 0x%lx, %ld, %p, %p) => %p"), allocator, fireDate, interval, flags, order, callout, context, memory);
3555 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
3557 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, rlt
, "_cffireTime");
3558 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3559 int64_t fireTime
, result
= 0;
3560 __CFRunLoopTimerFireTSRLock();
3561 fireTime
= rlt
->_fireTSR
;
3562 __CFRunLoopTimerFireTSRUnlock();
3563 __CFRunLoopTimerLock(rlt
);
3564 if (__CFIsValid(rlt
)) {
3567 __CFRunLoopTimerUnlock(rlt
);
3568 int64_t now2
= (int64_t)mach_absolute_time();
3569 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3570 return (0 == result
) ? 0.0 : now1
+ __CFTSRToTimeInterval(result
- now2
);
3573 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
3574 //CFLog(6, CFSTR("CFRunLoopTimerSetNextFireDate(rlt %p, fireDate %f)"), rlt, fireDate);
3576 //CFLog(4, CFSTR("CFRunLoopTimerSetNextFireDate(%p, %f) [limit: %f]"), rlt, fireDate, TIMER_DATE_LIMIT);
3577 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3578 rlt
->_nextFireDate
= fireDate
;
3579 int64_t now2
= (int64_t)mach_absolute_time();
3580 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3581 __CFRunLoopTimerFireTSRLock();
3582 if (fireDate
< now1
) {
3583 rlt
->_fireTSR
= now2
;
3584 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
3585 rlt
->_fireTSR
= LLONG_MAX
;
3587 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3589 if (rlt
->_runLoop
!= NULL
) {
3590 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
3592 __CFRunLoopTimerFireTSRUnlock();
3595 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
3597 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFTimeInterval
, rlt
, "timeInterval");
3598 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3599 return rlt
->_interval
;
3602 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
3604 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3605 return (0.0 < rlt
->_interval
);
3608 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
3610 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFIndex
, rlt
, "order");
3611 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3615 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
3617 //CFLog(4, CFSTR("CFRunLoopTimerInvalidate(%p)"), rlt);
3618 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, void, rlt
, "invalidate");
3619 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3620 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3623 __CFRunLoopTimerLock(rlt
);
3624 if (__CFIsValid(rlt
)) {
3625 CFRunLoopRef rl
= rlt
->_runLoop
;
3626 void *info
= rlt
->_context
.info
;
3627 __CFUnsetValid(rlt
);
3628 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3629 __CFRunLoopTimerPortMapLock();
3630 if (NULL
!= __CFRLTPortMap
) {
3631 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
3633 __CFRunLoopTimerPortMapUnlock();
3634 mk_timer_destroy(rlt
->_port
);
3635 rlt
->_port
= MACH_PORT_NULL
;
3637 rlt
->_context
.info
= NULL
;
3638 __CFRunLoopTimerUnlock(rlt
);
3640 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3641 STACK_BUFFER_DECL(CFStringRef
, modes
, cnt
);
3642 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3643 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3644 CFRunLoopRemoveTimer(rl
, rlt
, modes
[idx
]);
3646 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
3648 if (NULL
!= rlt
->_context
.release
) {
3649 rlt
->_context
.release(info
); /* CALLOUT */
3652 __CFRunLoopTimerUnlock(rlt
);
3654 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3659 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
3661 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, Boolean
, rlt
, "isValid");
3662 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3663 return __CFIsValid(rlt
);
3666 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
3668 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3669 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3670 *context
= rlt
->_context
;
3674 #if DEPLOYMENT_TARGET_WINDOWS
3676 //#if MARRY_MESSAGE_QUEUE
3678 // Do we need to make sure it's not CFRunLoopRun processing the message queue?
3679 CF_EXPORT LRESULT CALLBACK
pumpRunLoopFromMessageQueue(int nCode
, WPARAM wParam
, LPARAM lParam
) {
3680 //if nCode < 0, we're supposed to blindly call CallNexthookEx instead of processing the message ourselves
3682 MSG
*msgPtr
= (MSG
*)lParam
;
3683 CFRunLoopRef rl
= CFRunLoopGetCurrent();
3684 CFStringRef currMode
;
3686 if (msgPtr
->message
== __kCFRunLoopV1SourceReadyMessage
) {
3687 CFRunLoopModeRef rlm
;
3688 CFRunLoopSourceRef rls
;
3689 __CFRunLoopLock(rl
);
3690 rlm
= rl
->_currentMode
;
3692 rlm
= __CFRunLoopFindMode(rl
, kCFRunLoopDefaultMode
, true); // returns the mode locked
3694 __CFRunLoopModeLock(rlm
);
3696 rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, (__CFPort
)msgPtr
->lParam
);
3697 __CFRunLoopUnlock(rl
);
3699 // Must still hold the mode lock when calling DoSource1
3700 __CFRunLoopDoSource1(rl
, rlm
, rls
);
3702 __CFRunLoopModeUnlock(rlm
);
3704 if (msgPtr
->message
== __kCFRunLoopV1SourceReadyMessage
|| msgPtr
->message
== __kCFRunLoopWakeUpMessage
) {
3705 // Must always pump the RL regardless of whether we received the wakeup message because whomever processed the v1 source may be assuming that the RL is running and will see further callouts.
3706 currMode
= CFRunLoopCopyCurrentMode(rl
);
3708 currMode
= kCFRunLoopDefaultMode
;
3711 while (CFRunLoopRunInMode(currMode
, 0.0, true) == kCFRunLoopRunHandledSource
) {
3714 CFRelease(currMode
);
3717 return CallNextHookEx(__CFGetThreadSpecificData_inline()->_messageHook
, nCode
, wParam
, lParam
);
3720 void __CFRunLoopMsgWaitThread(void *theRL
) {
3721 CFRunLoopRef rl
= (CFRunLoopRef
)theRL
;
3722 Boolean allDone
= FALSE
;
3726 CFRunLoopModeRef rlm
;
3727 __CFPortSet waitSet
;
3728 DWORD waitResult
= WAIT_TIMEOUT
;
3730 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
3731 HANDLE
*handles
, *currHandle
;
3732 uint32_t handleCount
, handleIndex
;
3733 Boolean freeHandles
;
3735 __CFRunLoopLock(rl
);
3736 rlm
= rl
->_currentMode
;
3738 rlm
= __CFRunLoopFindMode(rl
, kCFRunLoopDefaultMode
, true); // Returns a locked mode
3740 __CFRunLoopModeLock(rlm
);
3743 waitSet
= rlm
->_portSet
;
3745 // copy out the handles to be safe from other threads at work
3746 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
3747 freeHandles
= (handles
!= handleBuf
);
3748 // Replace the wakeup port with our own update port
3749 for (handleIndex
= 0, currHandle
= handles
; handleIndex
< handleCount
; handleIndex
++, currHandle
++) {
3750 if (*currHandle
== rl
->_wakeUpPort
) {
3751 *currHandle
= rl
->_msgUpdatePort
;
3756 // Not sure what to do with this....
3757 // handles[handleCount] = rl->_msgShutdownPort;
3760 qMask
= rlm
->_msgQMask
;
3763 Boolean shuttingDown
= false;
3764 __CFRunLoopModeUnlock(rlm
);
3765 __CFRunLoopUnlock(rl
);
3767 // What do we do if there are more than MAXIMUM_WAIT_OBJECTS
3768 //waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE, qMask);
3769 waitResult
= WaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, INFINITE
);
3770 // Need to poll here to see if we've been told to die; if so, we must not touch rl. I think.
3771 __CFRunLoopLock(rl
);
3772 __CFRunLoopModeLock(rlm
);
3773 ResetEvent(rl
->_msgUpdatePort
);
3775 __CFPort livePort
= CFPORT_NULL
;
3776 if (waitResult
== WAIT_FAILED
) {
3777 DWORD error
= GetLastError();
3778 if (error
== ERROR_INVALID_HANDLE
) {
3779 // A handle got freed out from underneath us. Force an update of our handle watch list.
3780 livePort
= rl
->_msgUpdatePort
;
3782 CFAssert2(true, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects\n", __PRETTY_FUNCTION__
,error
);
3785 if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
3786 // a handle was signaled
3787 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
3788 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
3789 // an "abandoned mutex object"
3790 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
3793 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
3796 if (livePort
== rl
->_msgUpdatePort
) {
3798 // } else if (livePort == rl->_msgShutdownPort) {
3802 // OutputDebugStr(L"Posting v1 source ready msg\n");
3803 ResetEvent(livePort
);
3804 PostThreadMessageW(rl
->_threadID
, __kCFRunLoopV1SourceReadyMessage
, NULL
, (LPARAM
)livePort
);
3807 __CFRunLoopModeUnlock(rlm
);
3809 __CFRunLoopUnlock(rl
);
3815 // Called while holding the run loop lock
3817 //#if MARRY_MESSAGE_QUEUE
3819 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl
) {
3820 if (rl
->_msgUpdatePort
== CFPORT_NULL
) {
3821 rl
->_msgUpdatePort
= __CFPortAllocate();
3822 if (CFPORT_NULL
== rl
->_msgUpdatePort
) HALT
;
3824 // Kick off the MsgWaitThread
3825 _beginthread(__CFRunLoopMsgWaitThread
, 0, rl
);
3827 SetEvent(rl
->_msgUpdatePort
);
3830 CF_INLINE
void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl
) {}