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@
24 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFRunLoop.h>
29 #include <CoreFoundation/CFSet.h>
30 #include <CoreFoundation/CFBag.h>
31 #include "CFInternal.h"
35 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
36 #include <dispatch/dispatch.h>
37 #include <mach/mach.h>
38 #include <mach/clock_types.h>
39 #include <mach/clock.h>
42 extern mach_port_t
_dispatch_get_main_queue_port_4CF(void);
43 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t
*msg
);
46 #define __CFReadTSR() mach_absolute_time()
50 static int _LogCFRunLoop
= 0;
52 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
53 #define TIMER_DATE_LIMIT 4039289856.0
54 #define TIMER_INTERVAL_LIMIT 504911232.0
56 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
58 #if DEPLOYMENT_TARGET_WINDOWS
59 static pthread_t kNilPthreadT
= { nil
, nil
};
60 #define pthreadPointer(a) a.p
62 static DWORD __CFTSDKeyRunLoopKey
= ~0;
64 // See function below.
65 bool gMARRY_MESSAGE_QUEUE
= FALSE
;
67 // vod __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled)
69 // This function will exist for a while until code is written
70 // by the WebKit folks to handle the new RunLoop message-queue
72 CF_EXPORT
void __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled
) {
73 gMARRY_MESSAGE_QUEUE
= bEnabled
;
75 bool __CFIsNonMachRunLoopMarryMsgQueueEnabled(void) {
76 return gMARRY_MESSAGE_QUEUE
;
81 static pthread_t kNilPthreadT
= (pthread_t
)0;
82 #define pthreadPointer(a) a
83 #define lockCount(a) a
86 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
87 #include <sys/types.h>
88 #include <sys/event.h>
93 const void *(*retain
)(const void *info
);
94 void (*release
)(const void *info
);
95 CFStringRef (*copyDescription
)(const void *info
);
96 Boolean (*equal
)(const void *info1
, const void *info2
);
97 CFHashCode (*hash
)(const void *info
);
98 void (*perform
)(const struct kevent
*kev
, void *info
);
100 } CFRunLoopSourceContext2
;
102 // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR.
103 // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop.
104 // There is no way to EV_ENABLE or EV_DISABLE a kevent.
105 // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet.
106 // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet.
107 // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos).
110 CF_EXPORT
bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
112 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
113 // simple abstraction layer spanning Mach ports and Windows HANDLES
114 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
116 typedef mach_port_t __CFPort
;
117 #define CFPORT_NULL MACH_PORT_NULL
118 typedef mach_port_t __CFPortSet
;
120 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
121 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) { HALT
; };
123 static __CFPort
__CFPortAllocate(void) {
124 __CFPort result
= CFPORT_NULL
;
126 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
127 if (KERN_SUCCESS
== ret
) {
128 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
130 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret
);
132 if (KERN_SUCCESS
== ret
) {
133 mach_port_limits_t limits
;
134 limits
.mpl_qlimit
= 1;
135 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
137 if (KERN_SUCCESS
!= ret
) mach_port_destroy(mach_task_self(), result
);
138 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
141 CF_INLINE
void __CFPortFree(__CFPort port
) {
142 mach_port_destroy(mach_task_self(), port
);
145 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
146 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) { HALT
; };
148 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
150 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
151 if (KERN_SUCCESS
!= ret
) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret
); }
152 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
155 CF_INLINE Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
156 kern_return_t ret
= mach_port_insert_member(mach_task_self(), port
, portSet
);
157 return (KERN_SUCCESS
== ret
);
160 CF_INLINE Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
161 kern_return_t ret
= mach_port_extract_member(mach_task_self(), port
, portSet
);
162 return (KERN_SUCCESS
== ret
);
165 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
167 mach_port_name_array_t array
;
168 mach_msg_type_number_t idx
, number
;
170 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
171 if (KERN_SUCCESS
== ret
) {
172 for (idx
= 0; idx
< number
; idx
++) {
173 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
175 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
177 mach_port_destroy(mach_task_self(), portSet
);
180 #elif DEPLOYMENT_TARGET_WINDOWS
182 typedef HANDLE __CFPort
;
183 #define CFPORT_NULL NULL
185 // A simple dynamic array of HANDLEs, which grows to a high-water mark
186 typedef struct ___CFPortSet
{
190 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
193 CF_INLINE __CFPort
__CFPortAllocate(void) {
194 return CreateEventA(NULL
, true, false, NULL
);
197 CF_INLINE
void __CFPortFree(__CFPort port
) {
201 static __CFPortSet
__CFPortSetAllocate(void) {
202 __CFPortSet result
= (__CFPortSet
)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
205 result
->handles
= (HANDLE
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
206 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
210 static void __CFPortSetFree(__CFPortSet portSet
) {
211 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
212 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
215 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
216 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
217 __CFSpinLock(&(portSet
->lock
));
218 __CFPort
*result
= portBuf
;
219 if (bufSize
< portSet
->used
)
220 result
= (__CFPort
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
221 if (portSet
->used
> 1) {
222 // rotate the ports to vaguely simulate round-robin behaviour
223 uint16_t lastPort
= portSet
->used
- 1;
224 HANDLE swapHandle
= portSet
->handles
[0];
225 memmove(portSet
->handles
, &portSet
->handles
[1], lastPort
* sizeof(HANDLE
));
226 portSet
->handles
[lastPort
] = swapHandle
;
228 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
229 *portsUsed
= portSet
->used
;
230 __CFSpinUnlock(&(portSet
->lock
));
234 static Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
235 __CFSpinLock(&(portSet
->lock
));
236 if (portSet
->used
>= portSet
->size
) {
238 portSet
->handles
= (HANDLE
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
240 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
)
241 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
242 portSet
->handles
[portSet
->used
++] = port
;
243 __CFSpinUnlock(&(portSet
->lock
));
247 static Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
249 __CFSpinLock(&(portSet
->lock
));
250 for (i
= 0; i
< portSet
->used
; i
++) {
251 if (portSet
->handles
[i
] == port
) {
252 for (j
= i
+1; j
< portSet
->used
; j
++) {
253 portSet
->handles
[j
-1] = portSet
->handles
[j
];
256 __CFSpinUnlock(&(portSet
->lock
));
260 __CFSpinUnlock(&(portSet
->lock
));
266 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
267 extern mach_port_name_t
mk_timer_create(void);
268 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
269 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
270 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
272 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
275 a
.lo
= x
& (int64_t)0xFFFFFFFF;
279 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
280 kern_return_t result
;
281 mach_msg_header_t header
;
282 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
283 header
.msgh_size
= sizeof(mach_msg_header_t
);
284 header
.msgh_remote_port
= port
;
285 header
.msgh_local_port
= MACH_PORT_NULL
;
286 header
.msgh_id
= msg_id
;
287 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
288 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
293 /* unlock a run loop and modes before doing callouts/sleeping */
294 /* never try to take the run loop lock with a mode locked */
295 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
296 /* run loop mode structures should never be deallocated, even if they become empty */
298 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
299 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
300 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
301 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
302 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
304 #if DEPLOYMENT_TARGET_WINDOWS
305 // The MSG identifier for the Windows message injected in the message queue to wake the run loop
306 static unsigned int __kCFRunLoopWakeUpMessage
= 0;
307 static unsigned int __kCFRunLoopV1SourceReadyMessage
= 0;
310 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
312 struct __CFRunLoopMode
{
314 CFSpinLock_t _lock
; /* must have the run loop locked before locking this */
318 CFMutableSetRef _sources
;
319 CFMutableSetRef _observers
;
320 CFMutableSetRef _timers
;
321 CFMutableDictionaryRef _portToV1SourceMap
;
322 CFMutableArrayRef _submodes
; // names of the submodes
323 __CFPortSet _portSet
;
324 CFIndex _observerMask
;
325 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
328 #if DEPLOYMENT_TARGET_WINDOWS
333 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
334 __CFSpinLock(&(rlm
->_lock
));
337 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
338 __CFSpinUnlock(&(rlm
->_lock
));
341 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
342 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
343 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
344 return CFEqual(rlm1
->_name
, rlm2
->_name
);
347 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
348 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
349 return CFHash(rlm
->_name
);
352 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
353 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
354 CFMutableStringRef result
;
355 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
356 #if DEPLOYMENT_TARGET_WINDOWS
357 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, "unknown");
359 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, lockCount(rlm
->_lock
) ? "true" : "false");
361 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p,"), rlm
->_portSet
);
362 #if DEPLOYMENT_TARGET_WINDOWS
363 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p,"), rlm
->_msgQMask
);
365 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm
->_sources
, rlm
->_observers
, rlm
->_timers
);
369 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
370 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
371 if (NULL
!= rlm
->_sources
) CFRelease(rlm
->_sources
);
372 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
373 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
374 if (NULL
!= rlm
->_submodes
) CFRelease(rlm
->_submodes
);
375 if (NULL
!= rlm
->_portToV1SourceMap
) CFRelease(rlm
->_portToV1SourceMap
);
376 CFRelease(rlm
->_name
);
377 __CFPortSetFree(rlm
->_portSet
);
378 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
379 if (-1 != rlm
->_kq
) close(rlm
->_kq
);
381 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x7C, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
));
385 struct _block_item
*_next
;
386 CFTypeRef _mode
; // CFString or CFSet or CFRunLoopTimer
387 void (^_block
)(void);
392 CFSpinLock_t _lock
; /* locked for accessing mode list */
393 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
394 volatile uint32_t *_stopped
;
396 CFMutableSetRef _commonModes
;
397 CFMutableSetRef _commonModeItems
;
398 CFRunLoopModeRef _currentMode
;
399 CFMutableSetRef _modes
;
400 struct _block_item
*_blocks_head
;
401 struct _block_item
*_blocks_tail
;
402 #if DEPLOYMENT_TARGET_WINDOWS
404 __CFPort _msgUpdatePort
;
406 CFTypeRef _counterpart
;
409 #if DEPLOYMENT_TARGET_WINDOWS
410 void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl
);
411 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl
);
412 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
);
413 CF_EXPORT LRESULT CALLBACK
pumpRunLoopFromMessageQueue(int nCode
, WPARAM wParam
, LPARAM lParam
);
416 /* Bit 0 of the base reserved bits is used for stopped state */
417 /* Bit 1 of the base reserved bits is used for sleeping state */
418 /* Bit 2 of the base reserved bits is used for deallocating state */
420 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
421 return (rl
->_stopped
&& rl
->_stopped
[2]) ? true : false;
424 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
426 rl
->_stopped
= (uint32_t volatile *)CFAllocatorAllocate(kCFAllocatorSystemDefault
, 4 * sizeof(uint32_t), 0);
427 rl
->_stopped
[0] = 0x4346524C;
428 rl
->_stopped
[1] = 0x4346524C; // 'CFRL'
429 rl
->_stopped
[2] = 0x00000000; // here the value is stored
430 rl
->_stopped
[3] = 0x4346524C;
432 if (rl
->_stopped
) rl
->_stopped
[2] = 0x53544F50; // 'STOP'
435 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
436 if (rl
->_stopped
) rl
->_stopped
[2] = 0x0;
439 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
440 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
443 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
444 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
447 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
448 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
451 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
452 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
455 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
456 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
459 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
460 __CFSpinLock(&(((CFRunLoopRef
)rl
)->_lock
));
463 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
464 __CFSpinUnlock(&(((CFRunLoopRef
)rl
)->_lock
));
467 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
468 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
469 CFMutableStringRef result
;
470 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
471 #if DEPLOYMENT_TARGET_WINDOWS
472 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)"));
474 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)"));
476 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
480 __private_extern__
void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
481 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
484 /* call with rl locked */
485 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
487 CFRunLoopModeRef rlm
;
488 struct __CFRunLoopMode srlm
;
489 memset(&srlm
, 0, sizeof(srlm
));
490 srlm
._base
._cfisa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
491 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
492 srlm
._name
= modeName
;
493 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
495 __CFRunLoopModeLock(rlm
);
501 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
505 CF_SPINLOCK_INIT_FOR_STRUCTS(rlm
->_lock
);
506 rlm
->_name
= CFStringCreateCopy(kCFAllocatorSystemDefault
, modeName
);
507 rlm
->_stopped
= false;
508 rlm
->_portToV1SourceMap
= NULL
;
509 rlm
->_sources
= NULL
;
510 rlm
->_observers
= NULL
;
512 rlm
->_submodes
= NULL
;
513 rlm
->_observerMask
= 0;
514 rlm
->_portSet
= __CFPortSetAllocate();
515 if (!__CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
)) HALT
;
516 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
519 #if DEPLOYMENT_TARGET_WINDOWS
522 CFSetAddValue(rl
->_modes
, rlm
);
524 __CFRunLoopModeLock(rlm
); /* return mode locked */
529 // expects rl and rlm locked
530 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopModeRef previousMode
) {
532 if (NULL
== rlm
) return true;
533 #if DEPLOYMENT_TARGET_WINDOWS
534 if (0 != rlm
->_msgQMask
) return false;
536 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
537 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ
)));
538 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) return false; // represents the libdispatch main queue
540 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
541 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
543 struct _block_item
*item
= rl
->_blocks_head
;
545 struct _block_item
*curr
= item
;
547 Boolean doit
= false;
548 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
549 doit
= CFEqual(curr
->_mode
, rlm
->_name
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
551 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, rlm
->_name
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
553 if (doit
) return false;
556 if (NULL
!= rlm
->_submodes
) {
558 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
559 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
560 CFRunLoopModeRef subrlm
;
562 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
563 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
, previousMode
) : true;
564 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
565 if (!subIsEmpty
) return false;
571 #if DEPLOYMENT_TARGET_WINDOWS
572 DWORD
__CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
573 CFRunLoopModeRef rlm
;
576 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
578 result
= rlm
->_msgQMask
;
579 __CFRunLoopModeUnlock(rlm
);
581 __CFRunLoopUnlock(rl
);
585 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, DWORD mask
, CFStringRef modeName
) {
586 CFRunLoopModeRef rlm
;
588 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
589 rlm
->_msgQMask
= mask
;
590 __CFRunLoopModeUnlock(rlm
);
591 __CFRunLoopUnlock(rl
);
595 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
597 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
598 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
601 CF_INLINE
void __CFSetValid(void *cf
) {
602 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
605 CF_INLINE
void __CFUnsetValid(void *cf
) {
606 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
609 struct __CFRunLoopSource
{
613 CFIndex _order
; /* immutable */
614 CFMutableBagRef _runLoops
;
616 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
617 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
621 /* Bit 1 of the base reserved bits is used for signalled state */
623 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
624 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
627 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
628 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
631 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
632 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
635 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
636 __CFSpinLock(&(rls
->_lock
));
639 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
640 __CFSpinUnlock(&(rls
->_lock
));
643 /* rlm is not locked */
644 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
645 //printf("Scheduling source %p with mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
646 __CFRunLoopSourceLock(rls
);
647 if (NULL
== rls
->_runLoops
) {
648 rls
->_runLoops
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeBagCallBacks
); // sources retain run loops!
650 CFBagAddValue(rls
->_runLoops
, rl
);
651 __CFRunLoopSourceUnlock(rls
); // have to unlock before the callout -- cannot help clients with safety
652 if (0 == rls
->_context
.version0
.version
) {
653 if (NULL
!= rls
->_context
.version0
.schedule
) {
654 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, rlm
->_name
);
656 } else if (1 == rls
->_context
.version0
.version
) {
657 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
658 if (CFPORT_NULL
!= port
) {
659 __CFPortSetInsert(port
, rlm
->_portSet
);
661 #if DEPLOYMENT_TARGET_WINDOWS
663 //#warning Bug here - if rl->_currentMode is NULL and rlm == the default mode, we should also update
664 if (rl
->_currentMode
== rlm
) {
665 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
666 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
668 __CFRunLoopUpdateMsgWait(rl
);
670 __CFRunLoopUnlock(rl
);
675 /* rlm is not locked */
676 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
677 //printf("Cancelling source %p from mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
678 __CFRunLoopSourceLock(rls
);
679 if (NULL
!= rls
->_runLoops
) {
680 CFBagRemoveValue(rls
->_runLoops
, rl
);
682 __CFRunLoopSourceUnlock(rls
);
683 if (0 == rls
->_context
.version0
.version
) {
684 if (NULL
!= rls
->_context
.version0
.cancel
) {
685 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
687 } else if (1 == rls
->_context
.version0
.version
) {
688 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
689 if (CFPORT_NULL
!= port
) {
690 __CFPortSetRemove(port
, rlm
->_portSet
);
692 #if DEPLOYMENT_TARGET_WINDOWS
694 //#warning Bug here - must also update if rl->_currentMode == NULL and rlm == default mode
695 if (rl
->_currentMode
== rlm
&& rl
->_msgUpdatePort
!= CFPORT_NULL
) {
696 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
697 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
699 __CFRunLoopUpdateMsgWait(rl
);
701 __CFRunLoopUnlock(rl
);
706 struct __CFRunLoopObserver
{
709 CFRunLoopRef _runLoop
;
711 CFOptionFlags _activities
; /* immutable */
712 CFIndex _order
; /* immutable */
713 CFRunLoopObserverCallBack _callout
; /* immutable */
714 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
717 /* Bit 0 of the base reserved bits is used for firing state */
718 /* Bit 1 of the base reserved bits is used for repeats state */
720 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
721 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
724 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
725 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
728 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
729 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
732 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
733 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
736 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
737 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
740 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
741 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
744 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
745 __CFSpinLock(&(rlo
->_lock
));
748 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
749 __CFSpinUnlock(&(rlo
->_lock
));
752 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
753 __CFRunLoopObserverLock(rlo
);
754 if (0 == rlo
->_rlCount
) {
758 __CFRunLoopObserverUnlock(rlo
);
761 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
762 __CFRunLoopObserverLock(rlo
);
764 if (0 == rlo
->_rlCount
) {
765 rlo
->_runLoop
= NULL
;
767 __CFRunLoopObserverUnlock(rlo
);
770 struct __CFRunLoopTimer
{
773 CFRunLoopRef _runLoop
;
774 CFMutableSetRef _rlModes
;
775 CFAbsoluteTime _nextFireDate
;
776 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
777 mach_port_name_t _port
;
778 int64_t _fireTSR
; /* TSR units */
779 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
780 #elif DEPLOYMENT_TARGET_WINDOWS
782 int64_t _fireTSR
; /* TSR units */
783 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
785 CFTimeInterval _interval
; /* immutable */
786 CFIndex _order
; /* immutable */
787 CFRunLoopTimerCallBack _callout
; /* immutable */
788 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
791 /* Bit 0 of the base reserved bits is used for firing state */
792 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
794 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
795 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
798 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
799 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
802 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
803 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
806 CF_INLINE Boolean
__CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt
) {
807 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
810 CF_INLINE
void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt
) {
811 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
814 CF_INLINE
void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt
) {
815 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
818 CF_INLINE Boolean
__CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt
) {
819 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
822 CF_INLINE
void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt
) {
823 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
826 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
827 __CFSpinLock(&(rlt
->_lock
));
830 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
831 __CFSpinUnlock(&(rlt
->_lock
));
834 static CFSpinLock_t __CFRLTFireTSRLock
= CFSpinLockInit
;
836 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
837 __CFSpinLock(&__CFRLTFireTSRLock
);
840 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
841 __CFSpinUnlock(&__CFRLTFireTSRLock
);
844 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
845 static CFMutableDictionaryRef __CFRLTPortMap
= NULL
;
846 static CFSpinLock_t __CFRLTPortMapLock
= CFSpinLockInit
;
848 CF_INLINE
void __CFRunLoopTimerPortMapLock(void) {
849 __CFSpinLock(&__CFRLTPortMapLock
);
852 CF_INLINE
void __CFRunLoopTimerPortMapUnlock(void) {
853 __CFSpinUnlock(&__CFRLTPortMapLock
);
857 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
);
859 // called with timer locked in libdispatch mode
860 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt
) {
861 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
862 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
866 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
867 //CFLog(4, CFSTR("__CFRunLoopTimerSchedule(%p, loop %p, mode %@) [%p, %p]"), rlt, rl, rlm->_name, rlt->_runLoop, rlt->_port);
868 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
869 __CFRunLoopTimerLock(rlt
);
870 if (NULL
== rlt
->_runLoop
) {
872 if (MACH_PORT_NULL
== rlt
->_port
) {
873 rlt
->_port
= mk_timer_create();
875 __CFRunLoopTimerPortMapLock();
876 if (NULL
== __CFRLTPortMap
) {
877 __CFRLTPortMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
879 CFDictionarySetValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
, rlt
);
880 __CFRunLoopTimerPortMapUnlock();
881 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
883 mach_port_insert_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
884 CFSetAddValue(rlt
->_rlModes
, rlm
->_name
);
885 __CFRunLoopTimerUnlock(rlt
);
886 #elif DEPLOYMENT_TARGET_WINDOWS
887 if (0 == rlt
->_rlCount
) {
894 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
895 //CFLog(6, CFSTR("__CFRunLoopTimerCancel(rlt %p, rl %p, rlm %@)"), rlt, rl, rlm->_name);
896 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
897 __CFRunLoopTimerLock(rlt
);
898 CFSetRemoveValue(rlt
->_rlModes
, rlm
->_name
);
899 __CFPortSetRemove(rlt
->_port
, rlm
->_portSet
);
900 if (0 == CFSetGetCount(rlt
->_rlModes
)) {
901 __CFRunLoopTimerPortMapLock();
902 if (NULL
!= __CFRLTPortMap
) {
903 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
905 __CFRunLoopTimerPortMapUnlock();
906 mk_timer_cancel(rlt
->_port
, NULL
);
907 rlt
->_runLoop
= NULL
;
909 __CFRunLoopTimerUnlock(rlt
);
910 #elif DEPLOYMENT_TARGET_WINDOWS
915 #if DEPLOYMENT_TARGET_WINDOWS
917 struct _collectTimersContext
{
918 CFMutableArrayRef results
;
922 static void __CFRunLoopCollectTimers(const void *value
, void *ctx
) {
923 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
924 struct _collectTimersContext
*context
= (struct _collectTimersContext
*)ctx
;
925 if (rlt
->_fireTSR
<= context
->cutoffTSR
) {
926 if (NULL
== context
->results
)
927 context
->results
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
928 CFArrayAppendValue(context
->results
, rlt
);
932 // RunLoop and RunLoopMode must be locked
933 static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, struct _collectTimersContext
*ctxt
) {
934 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
935 __CFRunLoopTimerFireTSRLock();
936 CFSetApplyFunction(rlm
->_timers
, __CFRunLoopCollectTimers
, ctxt
);
937 __CFRunLoopTimerFireTSRUnlock();
939 if (NULL
!= rlm
->_submodes
) {
941 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
942 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
943 CFRunLoopModeRef subrlm
;
944 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
945 if (NULL
!= subrlm
) {
946 __CFRunLoopTimersToFireRecursive(rl
, subrlm
, ctxt
);
947 __CFRunLoopModeUnlock(subrlm
);
953 // RunLoop and RunLoopMode must be locked
954 static CFArrayRef
__CFRunLoopTimersToFire(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
955 struct _collectTimersContext ctxt
= {NULL
, __CFReadTSR()};
956 __CFRunLoopTimersToFireRecursive(rl
, rlm
, &ctxt
);
963 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
964 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
966 // call with rl and rlm locked
967 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
969 CFRunLoopSourceRef found
= rlm
->_portToV1SourceMap
? (CFRunLoopSourceRef
)CFDictionaryGetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)port
) : NULL
;
970 if (NULL
== found
&& NULL
!= rlm
->_submodes
) {
972 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
973 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
974 CFRunLoopModeRef subrlm
;
975 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
976 if (NULL
!= subrlm
) {
977 found
= __CFRunLoopModeFindSourceForMachPort(rl
, subrlm
, port
);
978 __CFRunLoopModeUnlock(subrlm
);
988 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
989 // call with rl and rlm locked
990 static CFRunLoopTimerRef
__CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm
, __CFPort port
) {
992 CFRunLoopTimerRef result
= NULL
;
993 __CFRunLoopTimerPortMapLock();
994 if (NULL
!= __CFRLTPortMap
) {
995 result
= (CFRunLoopTimerRef
)CFDictionaryGetValue(__CFRLTPortMap
, (void *)(uintptr_t)port
);
997 __CFRunLoopTimerPortMapUnlock();
1002 // Remove backreferences the mode's sources have to the rl (context);
1003 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1004 // the source from the run loops it is in, but during deallocation of a
1005 // run loop, we already know that the sources are going to be punted
1006 // from it, so invalidation of sources does not need to remove from a
1007 // deallocating run loop.
1008 static void __CFRunLoopCleanseSources(const void *value
, void *context
) {
1009 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1010 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1012 const void **list
, *buffer
[256];
1013 if (NULL
== rlm
->_sources
) return;
1014 cnt
= CFSetGetCount(rlm
->_sources
);
1015 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1016 CFSetGetValues(rlm
->_sources
, list
);
1017 for (idx
= 0; idx
< cnt
; idx
++) {
1018 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1019 __CFRunLoopSourceLock(rls
);
1020 if (NULL
!= rls
->_runLoops
) {
1021 CFBagRemoveValue(rls
->_runLoops
, rl
);
1023 __CFRunLoopSourceUnlock(rls
);
1025 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1028 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
1029 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1030 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1032 const void **list
, *buffer
[256];
1033 if (NULL
== rlm
->_sources
) return;
1034 cnt
= CFSetGetCount(rlm
->_sources
);
1035 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1036 CFSetGetValues(rlm
->_sources
, list
);
1037 for (idx
= 0; idx
< cnt
; idx
++) {
1038 CFRetain(list
[idx
]);
1040 CFSetRemoveAllValues(rlm
->_sources
);
1041 for (idx
= 0; idx
< cnt
; idx
++) {
1042 __CFRunLoopSourceCancel((CFRunLoopSourceRef
)list
[idx
], rl
, rlm
);
1043 CFRelease(list
[idx
]);
1045 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1048 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
1049 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1050 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1052 const void **list
, *buffer
[256];
1053 if (NULL
== rlm
->_observers
) return;
1054 cnt
= CFSetGetCount(rlm
->_observers
);
1055 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1056 CFSetGetValues(rlm
->_observers
, list
);
1057 for (idx
= 0; idx
< cnt
; idx
++) {
1058 CFRetain(list
[idx
]);
1060 CFSetRemoveAllValues(rlm
->_observers
);
1061 for (idx
= 0; idx
< cnt
; idx
++) {
1062 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
1063 CFRelease(list
[idx
]);
1065 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1068 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
1069 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1070 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1072 const void **list
, *buffer
[256];
1073 if (NULL
== rlm
->_timers
) return;
1074 cnt
= CFSetGetCount(rlm
->_timers
);
1075 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1076 CFSetGetValues(rlm
->_timers
, list
);
1077 for (idx
= 0; idx
< cnt
; idx
++) {
1078 CFRetain(list
[idx
]);
1080 CFSetRemoveAllValues(rlm
->_timers
);
1081 for (idx
= 0; idx
< cnt
; idx
++) {
1082 __CFRunLoopTimerCancel((CFRunLoopTimerRef
)list
[idx
], rl
, rlm
);
1083 CFRelease(list
[idx
]);
1085 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1088 CF_EXPORT pthread_t _CFMainPThread
;
1089 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
);
1091 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
1092 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
1094 if (_CFRunLoopGet0b(_CFMainPThread
) == cf
) HALT
;
1096 /* We try to keep the run loop in a valid state as long as possible,
1097 since sources may have non-retained references to the run loop.
1098 Another reason is that we don't want to lock the run loop for
1099 callback reasons, if we can get away without that. We start by
1100 eliminating the sources, since they are the most likely to call
1101 back into the run loop during their "cancellation". Common mode
1102 items will be removed from the mode indirectly by the following
1104 __CFRunLoopSetDeallocating(rl
);
1105 if (NULL
!= rl
->_modes
) {
1106 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopCleanseSources
), rl
); // remove references to rl
1107 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
1108 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
1109 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
1111 __CFRunLoopLock(rl
);
1112 struct _block_item
*item
= rl
->_blocks_head
;
1114 struct _block_item
*curr
= item
;
1116 CFRelease(curr
->_mode
);
1117 Block_release(curr
->_block
);
1120 if (NULL
!= rl
->_commonModeItems
) {
1121 CFRelease(rl
->_commonModeItems
);
1123 if (NULL
!= rl
->_commonModes
) {
1124 CFRelease(rl
->_commonModes
);
1126 if (NULL
!= rl
->_modes
) {
1127 CFRelease(rl
->_modes
);
1129 __CFPortFree(rl
->_wakeUpPort
);
1130 rl
->_wakeUpPort
= CFPORT_NULL
;
1131 #if DEPLOYMENT_TARGET_WINDOWS
1132 __CFPortFree(rl
->_msgUpdatePort
);
1133 rl
->_msgUpdatePort
= CFPORT_NULL
;
1135 __CFRunLoopUnlock(rl
);
1136 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x8C, sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
));
1139 static const CFRuntimeClass __CFRunLoopModeClass
= {
1144 __CFRunLoopModeDeallocate
,
1145 __CFRunLoopModeEqual
,
1146 __CFRunLoopModeHash
,
1148 __CFRunLoopModeCopyDescription
1151 static const CFRuntimeClass __CFRunLoopClass
= {
1156 __CFRunLoopDeallocate
,
1160 __CFRunLoopCopyDescription
1163 static void __CFFinalizeRunLoop(uintptr_t data
);
1165 __private_extern__
void __CFRunLoopInitialize(void) {
1166 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
1167 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
1168 #if DEPLOYMENT_TARGET_WINDOWS
1169 __kCFRunLoopWakeUpMessage
= RegisterWindowMessageW((LPCWSTR
)L
"CFRunLoopWakeup");
1170 __kCFRunLoopV1SourceReadyMessage
= RegisterWindowMessageW((LPCWSTR
)L
"CFRunLoopV1Ready");
1172 #if DEPLOYMENT_TARGET_WINDOWS
1173 if (~0 == __CFTSDKeyRunLoopKey
) __CFTSDKeyRunLoopKey
= TlsAlloc();
1175 pthread_key_init_np(__CFTSDKeyRunLoop
, NULL
);
1176 pthread_key_init_np(__CFTSDKeyRunLoopCntr
, (void *)__CFFinalizeRunLoop
);
1180 CFTypeID
CFRunLoopGetTypeID(void) {
1181 return __kCFRunLoopTypeID
;
1184 static CFRunLoopRef
__CFRunLoopCreate(pthread_t t
) {
1185 CFRunLoopRef loop
= NULL
;
1186 CFRunLoopModeRef rlm
;
1187 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
1188 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
1192 loop
->_stopped
= NULL
;
1193 CF_SPINLOCK_INIT_FOR_STRUCTS(loop
->_lock
);
1194 loop
->_wakeUpPort
= __CFPortAllocate();
1195 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
1196 #if DEPLOYMENT_TARGET_WINDOWS
1197 loop
->_msgUpdatePort
= CFPORT_NULL
;
1199 loop
->_commonModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1200 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
1201 loop
->_commonModeItems
= NULL
;
1202 loop
->_currentMode
= NULL
;
1203 loop
->_modes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1204 _CFSetSetCapacity(loop
->_modes
, 10);
1205 loop
->_blocks_head
= NULL
;
1206 loop
->_blocks_tail
= NULL
;
1207 loop
->_counterpart
= NULL
;
1209 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
1210 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
1214 static CFMutableDictionaryRef __CFRunLoops
= NULL
;
1215 static CFSpinLock_t loopsLock
= CFSpinLockInit
;
1217 // should only be called by Foundation
1218 // t==0 is a synonym for "main thread" that always works
1219 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0(pthread_t t
) {
1220 if (pthread_equal(t
, kNilPthreadT
)) {
1223 __CFSpinLock(&loopsLock
);
1224 if (!__CFRunLoops
) {
1225 __CFSpinUnlock(&loopsLock
);
1226 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1227 CFRunLoopRef mainLoop
= __CFRunLoopCreate(_CFMainPThread
);
1228 CFDictionarySetValue(dict
, pthreadPointer(_CFMainPThread
), mainLoop
);
1229 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, dict
, (void * volatile *)&__CFRunLoops
)) {
1232 CFRelease(mainLoop
);
1233 __CFSpinLock(&loopsLock
);
1235 CFRunLoopRef loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1237 __CFSpinUnlock(&loopsLock
);
1238 CFRunLoopRef newLoop
= __CFRunLoopCreate(t
);
1239 __CFSpinLock(&loopsLock
);
1240 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1242 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(t
), newLoop
);
1247 if (pthread_equal(t
, pthread_self())) {
1248 #if DEPLOYMENT_TARGET_WINDOWS
1249 TlsSetValue(__CFTSDKeyRunLoopKey
, (LPVOID
)(PTHREAD_DESTRUCTOR_ITERATIONS
-1));
1251 pthread_setspecific(__CFTSDKeyRunLoop
, (void *)loop
);
1252 if (0 == pthread_getspecific(__CFTSDKeyRunLoopCntr
)) {
1253 pthread_setspecific(__CFTSDKeyRunLoopCntr
, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS
-1));
1256 #if DEPLOYMENT_TARGET_WINDOWS
1257 // Install our message hook so we can spin the runloop
1258 loop
->_threadID
= GetCurrentThreadId();
1259 //#if MARRY_MESSAGE_QUEUE
1260 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) {
1262 __CFGetThreadSpecificData_inline()->_messageHook
= SetWindowsHookExW(WH_GETMESSAGE
, (HOOKPROC
)pumpRunLoopFromMessageQueue
, GetModuleHandleW((LPCWSTR
)L
"CoreFoundation_debug.dll"), loop
->_threadID
);
1264 __CFGetThreadSpecificData_inline()->_messageHook
= SetWindowsHookExW(WH_GETMESSAGE
, (HOOKPROC
)pumpRunLoopFromMessageQueue
, GetModuleHandleW((LPCWSTR
)L
"CoreFoundation.dll"), loop
->_threadID
);
1270 __CFSpinUnlock(&loopsLock
);
1274 // should only be called by Foundation
1275 CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
) {
1276 if (pthread_equal(t
, kNilPthreadT
)) {
1279 __CFSpinLock(&loopsLock
);
1280 CFRunLoopRef loop
= NULL
;
1282 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1284 __CFSpinUnlock(&loopsLock
);
1288 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
);
1290 // Called for each thread as it exits
1291 static void __CFFinalizeRunLoop(uintptr_t data
) {
1292 CFRunLoopRef rl
= NULL
;
1294 __CFSpinLock(&loopsLock
);
1296 rl
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1297 if (rl
) CFRetain(rl
);
1298 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1300 __CFSpinUnlock(&loopsLock
);
1302 #if DEPLOYMENT_TARGET_WINDOWS
1303 TlsSetValue(__CFTSDKeyRunLoopKey
, (LPVOID
)(data
- 1));
1305 pthread_setspecific(__CFTSDKeyRunLoopCntr
, (void *)(data
- 1));
1308 if (rl
&& CFRunLoopGetMain() != rl
) { // protect against cooperative threads
1309 if (NULL
!= rl
->_counterpart
) {
1310 CFRelease(rl
->_counterpart
);
1311 rl
->_counterpart
= NULL
;
1313 // purge all sources before deallocation
1314 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
1315 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
1316 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
1317 __CFRunLoopRemoveAllSources(rl
, modeName
);
1319 __CFRunLoopRemoveAllSources(rl
, kCFRunLoopCommonModes
);
1322 if (rl
) CFRelease(rl
);
1325 pthread_t
_CFRunLoopGet1(CFRunLoopRef rl
) {
1326 return rl
->_pthread
;
1329 // should only be called by Foundation
1330 CF_EXPORT CFTypeRef
_CFRunLoopGet2(CFRunLoopRef rl
) {
1331 CFTypeRef ret
= NULL
;
1332 __CFSpinLock(&loopsLock
);
1333 if (NULL
== rl
->_counterpart
) {
1334 Class cls
= (Class
)objc_lookUpClass("NSRunLoop");
1337 CF_OBJC_CALL1(char, hasMethod
, cls
, "respondsToSelector:", sel_registerName("_new:"));
1340 CF_OBJC_CALL1(void *, ns
, cls
, "_new:", rl
);
1341 rl
->_counterpart
= ns
? CFRetain(ns
) : NULL
;
1345 ret
= rl
->_counterpart
;
1346 __CFSpinUnlock(&loopsLock
);
1350 // should only be called by Foundation
1351 CF_EXPORT CFTypeRef
_CFRunLoopGet2b(CFRunLoopRef rl
) {
1352 return rl
->_counterpart
;
1355 #if DEPLOYMENT_TARGET_MACOSX
1356 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1357 if (pthread_main_np()) return;
1358 CFRunLoopRef currentLoop
= CFRunLoopGetCurrent();
1359 if (rl
!= currentLoop
) {
1360 CFRetain(currentLoop
); // avoid a deallocation of the currentLoop inside the lock
1361 __CFSpinLock(&loopsLock
);
1363 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(pthread_self()), rl
);
1365 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1367 __CFSpinUnlock(&loopsLock
);
1368 CFRelease(currentLoop
);
1369 pthread_setspecific(__CFTSDKeyRunLoop
, NULL
);
1370 pthread_setspecific(__CFTSDKeyRunLoopCntr
, 0);
1375 CFRunLoopRef
CFRunLoopGetMain(void) {
1377 static CFRunLoopRef __main
= NULL
; // no retain needed
1378 if (!__main
) __main
= _CFRunLoopGet0(_CFMainPThread
); // no CAS needed
1382 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1384 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1385 CFRunLoopRef rl
= (CFRunLoopRef
)pthread_getspecific(__CFTSDKeyRunLoop
);
1388 return _CFRunLoopGet0(pthread_self());
1391 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1393 CFStringRef result
= NULL
;
1394 __CFRunLoopLock(rl
);
1395 if (NULL
!= rl
->_currentMode
) {
1396 result
= (CFStringRef
)CFRetain(rl
->_currentMode
->_name
);
1398 __CFRunLoopUnlock(rl
);
1402 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1403 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1404 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1405 CFArrayAppendValue(array
, rlm
->_name
);
1408 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1410 CFMutableArrayRef array
;
1411 __CFRunLoopLock(rl
);
1412 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1413 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1414 __CFRunLoopUnlock(rl
);
1418 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1419 CFTypeRef item
= (CFTypeRef
)value
;
1420 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1421 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1422 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1423 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1424 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1425 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1426 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1427 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1431 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1432 CFStringRef modeName
= (CFStringRef
)value
;
1433 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1434 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1435 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1436 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1437 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1438 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1439 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1440 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1444 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1445 CFStringRef modeName
= (CFStringRef
)value
;
1446 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1447 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1448 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1449 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1450 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1451 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1452 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1453 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1457 CF_EXPORT Boolean
_CFRunLoop01(CFRunLoopRef rl
, CFStringRef modeName
) {
1458 __CFRunLoopLock(rl
);
1459 Boolean present
= CFSetContainsValue(rl
->_commonModes
, modeName
);
1460 __CFRunLoopUnlock(rl
);
1464 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1466 if (__CFRunLoopIsDeallocating(rl
)) return;
1467 __CFRunLoopLock(rl
);
1468 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1469 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1470 CFSetAddValue(rl
->_commonModes
, modeName
);
1471 __CFRunLoopUnlock(rl
);
1473 CFTypeRef context
[2] = {rl
, modeName
};
1474 /* add all common-modes items to new mode */
1475 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1479 __CFRunLoopUnlock(rl
);
1483 static Boolean
__CFRunLoopDoBlocks(CFRunLoopRef rl
, CFStringRef curMode
) { // Call with rl locked
1484 if (!rl
->_blocks_head
) return false;
1485 if (!curMode
) return false;
1486 Boolean did
= false;
1487 CFAbsoluteTime deadline
= CFAbsoluteTimeGetCurrent() + 0.0009765625;
1488 struct _block_item
*head
= rl
->_blocks_head
;
1489 struct _block_item
*tail
= rl
->_blocks_tail
;
1490 rl
->_blocks_head
= NULL
;
1491 rl
->_blocks_tail
= NULL
;
1492 CFSetRef commonModes
= rl
->_commonModes
;
1493 __CFRunLoopUnlock(rl
);
1494 struct _block_item
*prev
= NULL
;
1495 struct _block_item
*item
= head
;
1496 while (item
&& CFAbsoluteTimeGetCurrent() < deadline
) {
1497 struct _block_item
*curr
= item
;
1499 Boolean doit
= false;
1500 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
1501 doit
= CFEqual(curr
->_mode
, curMode
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1503 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, curMode
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1505 if (!doit
) prev
= curr
;
1507 if (prev
) prev
->_next
= item
;
1508 if (curr
== head
) head
= item
;
1509 if (curr
== tail
) tail
= prev
;
1510 void (^block
)(void) = curr
->_block
;
1511 CFRelease(curr
->_mode
);
1514 block(); // rl is not locked, mode is not locked
1517 Block_release(block
); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1520 __CFRunLoopLock(rl
);
1522 tail
->_next
= rl
->_blocks_head
;
1523 rl
->_blocks_head
= head
;
1524 if (!rl
->_blocks_tail
) rl
->_blocks_tail
= tail
;
1529 static CFComparisonResult
__CFRunLoopObserverQSortComparator(const void *val1
, const void *val2
, void *context
) {
1530 CFRunLoopObserverRef o1
= *((CFRunLoopObserverRef
*)val1
);
1531 CFRunLoopObserverRef o2
= *((CFRunLoopObserverRef
*)val2
);
1533 return (!o2
) ? kCFCompareEqualTo
: kCFCompareLessThan
;
1536 return kCFCompareGreaterThan
;
1538 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1539 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1540 return kCFCompareEqualTo
;
1544 /* rl is unlocked, rlm is locked on entrance and exit */
1545 /* ALERT: this should collect all the candidate observers from the top level
1546 * and all submodes, recursively, THEN start calling them, in order to obey
1547 * the ordering parameter. */
1548 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1551 CFArrayRef submodes
;
1553 /* Fire the observers */
1554 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1555 if (NULL
!= rlm
->_observers
) {
1556 cnt
= CFSetGetCount(rlm
->_observers
);
1558 STACK_BUFFER_DECL(CFRunLoopObserverRef
, buffer
, (cnt
<= 1024) ? cnt
: 1);
1559 CFRunLoopObserverRef
*collectedObservers
= (CFRunLoopObserverRef
*)((cnt
<= 1024) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(CFRunLoopObserverRef
), 0));
1560 CFSetGetValues(rlm
->_observers
, (const void **)collectedObservers
);
1561 for (idx
= 0; idx
< cnt
; idx
++) {
1562 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1563 if (0 != (rlo
->_activities
& activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1566 /* We're not interested in this one - set it to NULL so we don't process it later */
1567 collectedObservers
[idx
] = NULL
;
1570 __CFRunLoopModeUnlock(rlm
);
1571 CFQSortArray(collectedObservers
, cnt
, sizeof(CFRunLoopObserverRef
), __CFRunLoopObserverQSortComparator
, NULL
);
1572 for (idx
= 0; idx
< cnt
; idx
++) {
1573 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1575 __CFRunLoopObserverLock(rlo
);
1576 if (__CFIsValid(rlo
)) {
1577 __CFRunLoopObserverUnlock(rlo
);
1578 __CFRunLoopObserverSetFiring(rlo
);
1579 rlo
->_callout(rlo
, activity
, rlo
->_context
.info
); /* CALLOUT */
1580 __CFRunLoopObserverUnsetFiring(rlo
);
1581 if (!__CFRunLoopObserverRepeats(rlo
)) {
1582 CFRunLoopObserverInvalidate(rlo
);
1585 __CFRunLoopObserverUnlock(rlo
);
1590 __CFRunLoopModeLock(rlm
);
1591 if (collectedObservers
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, collectedObservers
);
1594 if (NULL
!= submodes
) {
1595 __CFRunLoopModeUnlock(rlm
);
1596 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1597 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1598 CFRunLoopModeRef subrlm
;
1599 __CFRunLoopLock(rl
);
1600 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1601 __CFRunLoopUnlock(rl
);
1602 if (NULL
!= subrlm
) {
1603 __CFRunLoopDoObservers(rl
, subrlm
, activity
);
1604 __CFRunLoopModeUnlock(subrlm
);
1607 CFRelease(submodes
);
1608 __CFRunLoopModeLock(rlm
);
1612 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1613 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1614 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1615 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1616 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1617 return kCFCompareEqualTo
;
1620 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1621 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1622 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1623 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1624 if (NULL
== *sources
) {
1625 *sources
= CFRetain(rls
);
1626 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1627 CFTypeRef oldrls
= *sources
;
1628 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1629 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1630 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1633 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1638 /* rl is unlocked, rlm is locked on entrance and exit */
1639 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1641 CFTypeRef sources
= NULL
;
1642 Boolean sourceHandled
= false;
1645 __CFRunLoopModeUnlock(rlm
); // locks have to be taken in order
1646 __CFRunLoopLock(rl
);
1647 __CFRunLoopModeLock(rlm
);
1648 /* Fire the version 0 sources */
1649 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) {
1650 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1652 for (idx
= 0, cnt
= (NULL
!= rlm
->_submodes
) ? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1653 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1654 CFRunLoopModeRef subrlm
;
1655 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1656 if (NULL
!= subrlm
) {
1657 if (NULL
!= subrlm
->_sources
&& 0 < CFSetGetCount(subrlm
->_sources
)) {
1658 CFSetApplyFunction(subrlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1660 __CFRunLoopModeUnlock(subrlm
);
1663 __CFRunLoopUnlock(rl
);
1664 if (NULL
!= sources
) {
1665 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1666 __CFRunLoopModeUnlock(rlm
);
1667 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1668 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1669 __CFRunLoopSourceLock(rls
);
1670 #if DEPLOYMENT_TARGET_WINDOWS
1671 if (__CFRunLoopSourceIsSignaled(rls
)) {
1673 __CFRunLoopSourceUnsetSignaled(rls
);
1674 if (__CFIsValid(rls
)) {
1675 __CFRunLoopSourceUnlock(rls
);
1676 if (NULL
!= rls
->_context
.version0
.perform
) {
1677 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1680 sourceHandled
= true;
1682 __CFRunLoopSourceUnlock(rls
);
1684 #if DEPLOYMENT_TARGET_WINDOWS
1686 __CFRunLoopSourceUnlock(rls
);
1690 cnt
= CFArrayGetCount((CFArrayRef
)sources
);
1691 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1692 for (idx
= 0; idx
< cnt
; idx
++) {
1693 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex((CFArrayRef
)sources
, idx
);
1694 __CFRunLoopSourceLock(rls
);
1695 #if DEPLOYMENT_TARGET_WINDOWS
1696 if (__CFRunLoopSourceIsSignaled(rls
)) {
1698 __CFRunLoopSourceUnsetSignaled(rls
);
1699 if (__CFIsValid(rls
)) {
1700 __CFRunLoopSourceUnlock(rls
);
1701 if (NULL
!= rls
->_context
.version0
.perform
) {
1702 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1705 sourceHandled
= true;
1707 __CFRunLoopSourceUnlock(rls
);
1709 #if DEPLOYMENT_TARGET_WINDOWS
1711 __CFRunLoopSourceUnlock(rls
);
1714 if (stopAfterHandle
&& sourceHandled
) {
1720 __CFRunLoopModeLock(rlm
);
1722 return sourceHandled
;
1725 // msg, size and reply are unused on Windows
1726 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1727 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1728 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1730 ) { /* DOES CALLOUT */
1732 Boolean sourceHandled
= false;
1734 /* Fire a version 1 source */
1736 __CFRunLoopModeUnlock(rlm
);
1737 __CFRunLoopSourceLock(rls
);
1738 if (__CFIsValid(rls
)) {
1739 __CFRunLoopSourceUnsetSignaled(rls
);
1740 __CFRunLoopSourceUnlock(rls
);
1741 if (NULL
!= rls
->_context
.version1
.perform
) {
1742 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1743 *reply
= rls
->_context
.version1
.perform(msg
, size
, kCFAllocatorSystemDefault
, rls
->_context
.version1
.info
); /* CALLOUT */
1746 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1747 rls
->_context
.version1
.perform(rls
->_context
.version1
.info
); /* CALLOUT */
1751 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); }
1753 sourceHandled
= true;
1755 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1756 __CFRunLoopSourceUnlock(rls
);
1759 __CFRunLoopModeLock(rlm
);
1760 return sourceHandled
;
1763 // mode is locked on entry and exit
1764 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1765 Boolean timerHandled
= false, timerEarly
= false;
1766 int64_t oldFireTSR
= 0;
1770 __CFRunLoopModeUnlock(rlm
);
1771 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
1772 void *context_info
= NULL
;
1773 void (*context_release
)(const void *) = NULL
;
1774 if (rlt
->_context
.retain
) {
1775 context_info
= (void *)rlt
->_context
.retain(rlt
->_context
.info
);
1776 context_release
= rlt
->_context
.release
;
1778 context_info
= rlt
->_context
.info
;
1780 __CFRunLoopTimerUnsetDidFire(rlt
);
1781 __CFRunLoopTimerSetFiring(rlt
);
1782 //CFLog(4, CFSTR("Firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1783 __CFRunLoopTimerFireTSRLock();
1784 oldFireTSR
= rlt
->_fireTSR
;
1785 __CFRunLoopTimerFireTSRUnlock();
1786 if (0 && CFAbsoluteTimeGetCurrent() < rlt
->_nextFireDate
) { // not enabled at this time -- causes trouble when clock goes backwards
1789 rlt
->_callout(rlt
, context_info
); /* CALLOUT */
1791 timerHandled
= true;
1793 //CFLog(4, CFSTR("Done firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1794 __CFRunLoopTimerUnsetFiring(rlt
);
1795 if (context_release
) {
1796 context_release(context_info
);
1799 // If the timer fires while it is firing in a higher activiation,
1800 // it is not allowed to fire, but we have to remember that fact.
1801 // Later, if the timer's fire date is being handled manually, we
1802 // need to re-arm the kernel timer, since it has possibly already
1803 // fired (this firing which is being skipped, say) and the timer
1804 // will permanently stop if we completely drop this firing.
1805 if (__CFRunLoopTimerIsFiring(rlt
)) __CFRunLoopTimerSetDidFire(rlt
);
1807 if (__CFIsValid(rlt
) && timerHandled
) {
1808 if (0.0 == rlt
->_interval
) {
1809 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1811 /* This is just a little bit tricky: we want to support calling
1812 * CFRunLoopTimerSetNextFireDate() from within the callout and
1813 * honor that new time here if it is a later date, otherwise
1814 * it is completely ignored. */
1815 __CFRunLoopTimerFireTSRLock();
1816 int64_t currentFireTSR
= rlt
->_fireTSR
;
1817 if (oldFireTSR
< currentFireTSR
) {
1818 /* Next fire TSR was set, and set to a date after the previous
1819 * fire date, so we honor it. */
1820 if (__CFRunLoopTimerDidFire(rlt
)) {
1821 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1822 __CFRunLoopTimerUnsetDidFire(rlt
);
1825 if ((uint64_t)LLONG_MAX
<= (uint64_t)oldFireTSR
+ (uint64_t)rlt
->_intervalTSR
) {
1826 currentFireTSR
= LLONG_MAX
;
1828 int64_t currentTSR
= (int64_t)__CFReadTSR();
1829 currentFireTSR
= oldFireTSR
;
1830 while (currentFireTSR
<= currentTSR
) {
1831 currentFireTSR
+= rlt
->_intervalTSR
;
1834 rlt
->_fireTSR
= currentFireTSR
;
1835 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1837 __CFRunLoopTimerFireTSRUnlock();
1840 if (__CFIsValid(rlt
) && timerEarly
) {
1841 int64_t now2
= (int64_t)mach_absolute_time();
1842 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
1843 __CFRunLoopTimerFireTSRLock();
1844 if (rlt
->_nextFireDate
< now1
) {
1845 rlt
->_fireTSR
= now2
;
1846 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < rlt
->_nextFireDate
) {
1847 rlt
->_fireTSR
= LLONG_MAX
;
1849 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(rlt
->_nextFireDate
- now1
);
1851 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
1852 __CFRunLoopTimerFireTSRUnlock();
1855 __CFRunLoopModeLock(rlm
);
1856 return timerHandled
;
1859 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1861 CFRunLoopModeRef rlm
;
1862 Boolean result
= false;
1863 __CFRunLoopLock(rl
);
1864 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1865 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
, NULL
)) {
1868 __CFRunLoopUnlock(rl
);
1869 if (rlm
) __CFRunLoopModeUnlock(rlm
);
1873 // rl is locked, rlm is locked on entry and exit
1874 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPortSet portSet
) {
1876 const void **list
, *buffer
[256];
1878 // Timers and version 1 sources go into the portSet currently
1879 if (NULL
!= rlm
->_sources
) {
1880 cnt
= CFSetGetCount(rlm
->_sources
);
1881 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1882 CFSetGetValues(rlm
->_sources
, list
);
1883 for (idx
= 0; idx
< cnt
; idx
++) {
1884 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1885 if (1 == rls
->_context
.version0
.version
) {
1886 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1887 if (CFPORT_NULL
!= port
) {
1888 __CFPortSetInsert(port
, portSet
);
1892 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1894 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1895 if (NULL
!= rlm
->_timers
) {
1896 cnt
= CFSetGetCount(rlm
->_timers
);
1897 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1898 CFSetGetValues(rlm
->_timers
, list
);
1899 for (idx
= 0; idx
< cnt
; idx
++) {
1900 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1901 if (MACH_PORT_NULL
!= rlt
->_port
) {
1902 mach_port_insert_member(mach_task_self(), rlt
->_port
, portSet
);
1905 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1908 // iterate over submodes
1909 for (idx
= 0, cnt
= NULL
!= rlm
->_submodes
? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1910 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1911 CFRunLoopModeRef subrlm
;
1912 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1913 if (NULL
!= subrlm
) {
1914 __CFRunLoopModeAddPortsToPortSet(rl
, subrlm
, portSet
);
1915 __CFRunLoopModeUnlock(subrlm
);
1920 static __CFPortSet _LastMainWaitSet
= 0;
1922 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1923 // return NO if we're the main runloop and there are no messages waiting on the port set
1924 int _CFRunLoopInputsReady(void) {
1926 if (!pthread_main_np()) return true;
1928 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1929 if (_LastMainWaitSet
== MACH_PORT_NULL
) return false;
1931 // prepare a message header with no space for any data, nor a trailer
1932 mach_msg_header_t msg
;
1933 msg
.msgh_size
= sizeof(msg
); // just the header, ma'am
1934 // need the waitset, actually XXX
1935 msg
.msgh_local_port
= _LastMainWaitSet
;
1936 msg
.msgh_remote_port
= MACH_PORT_NULL
;
1939 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
);
1941 return (MACH_RCV_TOO_LARGE
== ret
);
1947 static void print_msg_scan_header(void) {
1948 printf("======== ======== ======== ========\n");
1949 printf("description\tport\tport type\t\treferences\n");
1952 static void print_one_port_info(const char *desc
, mach_port_t port
, mach_msg_type_name_t type
) {
1953 mach_port_urefs_t refs
;
1954 kern_return_t ret
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs
);
1955 if (ret
!= KERN_SUCCESS
) refs
= 0;
1956 const char *type_name
= "???";
1958 case MACH_MSG_TYPE_MOVE_SEND
: type_name
= "MACH_MSG_TYPE_MOVE_SEND"; break;
1959 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break;
1960 case MACH_MSG_TYPE_MOVE_RECEIVE
: type_name
= "MACH_MSG_TYPE_MOVE_RECEIVE"; break;
1961 case MACH_MSG_TYPE_MAKE_SEND
: type_name
= "MACH_MSG_TYPE_MAKE_SEND"; break;
1962 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break;
1964 printf("%s\t%p\t%-20s\t%u\n", desc
, port
, type_name
, refs
);
1967 static void mach_msg_scan(mach_msg_header_t
*msg
, int clean
) {
1968 Boolean printed_header
= false;
1970 * The msgh_local_port field doesn't hold a port right.
1971 * The receive operation consumes the destination port right.
1973 if (MACH_PORT_NULL
!= msg
->msgh_remote_port
) {
1974 if (! printed_header
) print_msg_scan_header();
1975 printed_header
= true;
1976 print_one_port_info("msg->msgh_remote_port", msg
->msgh_remote_port
, MACH_MSGH_BITS_REMOTE(msg
->msgh_bits
));
1978 if (msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
1979 mach_msg_body_t
*body
= (mach_msg_body_t
*) (msg
+ 1);
1980 mach_msg_descriptor_t
*saddr
= (mach_msg_descriptor_t
*) ((mach_msg_base_t
*) msg
+ 1);
1981 mach_msg_descriptor_t
*eaddr
= saddr
+ body
->msgh_descriptor_count
;
1982 for ( ; saddr
< eaddr
; saddr
++) {
1983 switch (saddr
->type
.type
) {
1984 case MACH_MSG_PORT_DESCRIPTOR
:;
1985 mach_msg_port_descriptor_t
*dsc
= &saddr
->port
;
1986 if (! printed_header
) print_msg_scan_header();
1987 printed_header
= true;
1988 print_one_port_info("port in body", dsc
->name
, dsc
->disposition
);
1989 // if (clean) mach_port_deallocate(mach_task_self(), dsc->name);
1991 case MACH_MSG_OOL_PORTS_DESCRIPTOR
:;
1992 mach_msg_ool_ports_descriptor_t
*dsc2
= &saddr
->ool_ports
;
1993 mach_port_t
*ports
= (mach_port_t
*) dsc2
->address
;
1994 for (mach_msg_type_number_t j
= 0; j
< dsc2
->count
; j
++, ports
++) {
1995 if (! printed_header
) print_msg_scan_header();
1996 printed_header
= true;
1997 print_one_port_info("port in OOL ports", *ports
, dsc2
->disposition
);
2006 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
, Boolean waitIfEmpty
) __attribute__((noinline
));
2007 #if DEPLOYMENT_TARGET_WINDOWS
2008 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
);
2011 /* rl is unlocked, rlm locked on entrance and exit */
2012 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
, Boolean waitIfEmpty
) { /* DOES CALLOUT */
2014 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2015 mach_port_name_t timeoutPort
= MACH_PORT_NULL
;
2016 mach_port_name_t dispatchPort
= MACH_PORT_NULL
;
2017 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ
)));
2018 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) dispatchPort
= _dispatch_get_main_queue_port_4CF();
2020 Boolean poll
= false;
2021 Boolean firstPass
= true;
2023 if (__CFRunLoopIsStopped(rl
)) {
2024 __CFRunLoopUnsetStopped(rl
);
2025 return kCFRunLoopRunStopped
;
2026 } else if (rlm
->_stopped
) {
2027 rlm
->_stopped
= false;
2028 return kCFRunLoopRunStopped
;
2030 if (seconds
<= 0.0) {
2032 } else if (TIMER_INTERVAL_LIMIT
< seconds
) {
2033 termTSR
= LLONG_MAX
;
2035 termTSR
= (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds
);
2036 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2037 timeoutPort
= mk_timer_create();
2038 mk_timer_arm(timeoutPort
, __CFUInt64ToAbsoluteTime(termTSR
));
2041 if (seconds
<= 0.0) {
2044 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= CFPORT_NULL
;
2046 __CFPortSet waitSet
= CFPORT_NULL
;
2047 Boolean destroyWaitSet
= false;
2048 CFRunLoopSourceRef rls
;
2049 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2050 mach_msg_header_t
*msg
;
2052 uint8_t buffer
[2048];
2054 CFArrayRef timersToCall
= NULL
;
2056 int32_t returnValue
= 0;
2057 Boolean sourceHandledThisLoop
= false;
2059 // Do not handle blocks here, as there is already a handling at
2060 // the end of this loop, and that just makes for two handlings
2061 // in a row when the loop cycles.
2062 if (rlm
->_observerMask
& kCFRunLoopBeforeTimers
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
2063 if (rlm
->_observerMask
& kCFRunLoopBeforeSources
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
2064 if (rl
->_blocks_head
) {
2065 __CFRunLoopModeUnlock(rlm
);
2066 __CFRunLoopLock(rl
);
2067 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2068 __CFRunLoopModeLock(rlm
);
2069 __CFRunLoopUnlock(rl
);
2072 sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
) || sourceHandledThisLoop
;
2074 if (sourceHandledThisLoop
) {
2076 if (rl
->_blocks_head
) {
2077 __CFRunLoopModeUnlock(rlm
);
2078 __CFRunLoopLock(rl
);
2079 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2080 __CFRunLoopModeLock(rlm
);
2081 __CFRunLoopUnlock(rl
);
2086 if (rlm
->_observerMask
& kCFRunLoopBeforeWaiting
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
2087 // do not do any user callouts after this point (after notifying of sleeping)
2088 __CFRunLoopSetSleeping(rl
);
2090 if (NULL
!= rlm
->_submodes
) {
2091 // !!! what do we do if this doesn't succeed?
2092 waitSet
= __CFPortSetAllocate();
2093 if (CFPORT_NULL
== waitSet
) HALT
;
2094 __CFRunLoopModeUnlock(rlm
);
2095 __CFRunLoopLock(rl
);
2096 __CFRunLoopModeLock(rlm
);
2097 __CFRunLoopModeAddPortsToPortSet(rl
, rlm
, waitSet
);
2098 __CFRunLoopUnlock(rl
);
2099 destroyWaitSet
= true;
2101 waitSet
= rlm
->_portSet
;
2103 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2104 if (CFPORT_NULL
!= timeoutPort
) {
2105 __CFPortSetInsert(timeoutPort
, waitSet
);
2107 if (CFPORT_NULL
!= dispatchPort
) {
2108 __CFPortSetInsert(dispatchPort
, waitSet
);
2111 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= waitSet
;
2112 __CFRunLoopModeUnlock(rlm
);
2114 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2115 if (kCFUseCollectableAllocator
&& !poll
) {
2116 memset(buffer
, 0, sizeof(buffer
));
2117 objc_clear_stack(0);
2120 msg
= (mach_msg_header_t
*)buffer
;
2121 msg
->msgh_size
= sizeof(buffer
);
2123 //static uint64_t _last_value = 0;
2124 //uint64_t new_val = mach_absolute_time();
2125 //printf(". %d before %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2126 //_last_value = new_val;
2128 /* In that sleep of death what nightmares may come ... */
2131 msg
->msgh_local_port
= waitSet
;
2132 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2134 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
);
2136 if (MACH_RCV_TOO_LARGE
== ret
) {
2137 uint32_t newSize
= round_msg(msg
->msgh_size
+ MAX_TRAILER_SIZE
);
2138 if (msg
== (mach_msg_header_t
*)buffer
) msg
= NULL
;
2139 msg
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, msg
, newSize
, 0);
2140 msg
->msgh_size
= newSize
;
2142 } else if (MACH_RCV_TIMED_OUT
== ret
) {
2143 // timeout, for poll
2144 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
2146 } else if (MACH_MSG_SUCCESS
!= ret
) {
2149 //new_val = mach_absolute_time();
2150 //printf(". %d after %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2151 //_last_value = new_val;
2152 #elif DEPLOYMENT_TARGET_WINDOWS
2153 DWORD waitResult
= WAIT_TIMEOUT
;
2154 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
2156 uint32_t handleCount
;
2157 Boolean freeHandles
;
2158 if (destroyWaitSet
) {
2159 // wait set is a local, no one else could modify it, no need to copy handles
2160 handles
= waitSet
->handles
;
2161 handleCount
= waitSet
->used
;
2162 freeHandles
= FALSE
;
2164 // copy out the handles to be safe from other threads at work
2165 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
2166 freeHandles
= (handles
!= handleBuf
);
2168 // should msgQMask be an OR'ing of this and all submodes' masks?
2169 if (0 == GetQueueStatus(rlm
->_msgQMask
)) {
2175 __CFRunLoopModeLock(rlm
);
2176 nextStop
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
2179 else if (nextStop
> termTSR
)
2181 // else the next stop is dictated by the next timer
2182 int64_t timeoutTSR
= nextStop
- __CFReadTSR();
2186 CFTimeInterval timeoutCF
= __CFTSRToTimeInterval(timeoutTSR
) * 1000;
2187 if (timeoutCF
> MAXDWORD
)
2190 timeout
= (DWORD
)timeoutCF
;
2193 waitResult
= WaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, timeout
);
2195 ResetEvent(rl
->_wakeUpPort
);
2197 __CFRunLoopLock(rl
);
2198 __CFRunLoopModeLock(rlm
);
2199 __CFRunLoopUnlock(rl
);
2200 if (destroyWaitSet
) {
2201 __CFPortSetFree(waitSet
);
2202 if (rl
== CFRunLoopGetMain()) _LastMainWaitSet
= 0;
2204 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2205 if (CFPORT_NULL
!= timeoutPort
) {
2206 __CFPortSetRemove(timeoutPort
, waitSet
);
2208 if (CFPORT_NULL
!= dispatchPort
) {
2209 __CFPortSetRemove(dispatchPort
, waitSet
);
2215 __CFRunLoopUnsetSleeping(rl
);
2216 if (rlm
->_observerMask
& kCFRunLoopAfterWaiting
|| rlm
->_submodes
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
2219 __CFRunLoopModeUnlock(rlm
);
2220 __CFRunLoopLock(rl
);
2221 __CFRunLoopModeLock(rlm
);
2223 __CFPort livePort
= CFPORT_NULL
;
2224 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2226 livePort
= msg
->msgh_local_port
;
2228 #elif DEPLOYMENT_TARGET_WINDOWS
2229 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
2230 if (waitResult
== WAIT_TIMEOUT
) {
2231 // do nothing, just return to caller
2232 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
2233 // a handle was signaled
2234 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
2235 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
2236 // windows message received - the CFWindowsMessageQueue will pick this up when
2237 // the v0 RunLoopSources get their chance
2238 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
2239 // an "abandoned mutex object"
2240 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
2242 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
2245 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
2246 timersToCall
= __CFRunLoopTimersToFire(rl
, rlm
);
2249 if (CFPORT_NULL
== livePort
) {
2250 __CFRunLoopUnlock(rl
);
2251 } else if (livePort
== rl
->_wakeUpPort
) {
2253 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("wakeupPort was signalled")); }
2254 __CFRunLoopUnlock(rl
); // leave run loop unlocked
2256 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2257 else if (livePort
== timeoutPort
) {
2258 returnValue
= kCFRunLoopRunTimedOut
;
2259 __CFRunLoopUnlock(rl
);
2260 } else if (dispatchPort
== livePort
) {
2261 __CFRunLoopModeUnlock(rlm
);
2262 __CFRunLoopUnlock(rl
);
2263 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)3);
2264 _dispatch_main_queue_callback_4CF(msg
);
2265 sourceHandledThisLoop
= true;
2266 pthread_setspecific(__CFTSDKeyIsInGCDMainQ
, (void *)0);
2267 __CFRunLoopLock(rl
);
2268 __CFRunLoopModeLock(rlm
);
2269 __CFRunLoopUnlock(rl
); // leave run loop unlocked
2270 } else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
2271 mach_msg_header_t
*reply
= NULL
;
2272 __CFRunLoopUnlock(rl
);
2273 // mach_msg_scan(msg, 0);
2274 if (__CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
)) {
2275 sourceHandledThisLoop
= true;
2277 // mach_msg_scan(msg, 1);
2278 if (NULL
!= reply
) {
2279 ret
= mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
2280 //#warning CF: what should be done with the return value?
2281 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
2284 CFRunLoopTimerRef rlt
;
2285 rlt
= __CFRunLoopModeFindTimerForMachPort(rlm
, livePort
);
2286 __CFRunLoopUnlock(rl
);
2288 __CFRunLoopDoTimer(rl
, rlm
, rlt
);
2291 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
2293 else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
2294 __CFRunLoopUnlock(rl
);
2295 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("Source %@ was signalled"), rls
); }
2296 if (__CFRunLoopDoSource1(rl
, rlm
, rls
)) {
2297 sourceHandledThisLoop
= true;
2302 #if DEPLOYMENT_TARGET_WINDOWS
2303 if (NULL
!= timersToCall
) {
2305 for (i
= CFArrayGetCount(timersToCall
)-1; i
>= 0; i
--)
2306 __CFRunLoopDoTimer(rl
, rlm
, (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timersToCall
, i
));
2307 CFRelease(timersToCall
);
2311 if (rl
->_blocks_head
) {
2312 __CFRunLoopModeUnlock(rlm
); // locks must be taken in order
2313 __CFRunLoopLock(rl
);
2314 __CFRunLoopDoBlocks(rl
, rlm
->_name
);
2315 __CFRunLoopModeLock(rlm
);
2316 __CFRunLoopUnlock(rl
);
2318 if (sourceHandledThisLoop
&& stopAfterHandle
) {
2319 returnValue
= kCFRunLoopRunHandledSource
;
2320 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
2321 // internal wakeup signal on the first look at the portset, we'll go around the loop one
2322 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
2323 } else if (0 != returnValue
|| (uint64_t)termTSR
<= __CFReadTSR()) {
2324 returnValue
= kCFRunLoopRunTimedOut
;
2325 } else if (__CFRunLoopIsStopped(rl
)) {
2326 __CFRunLoopUnsetStopped(rl
);
2327 returnValue
= kCFRunLoopRunStopped
;
2328 } else if (rlm
->_stopped
) {
2329 rlm
->_stopped
= false;
2330 returnValue
= kCFRunLoopRunStopped
;
2331 } else if (!waitIfEmpty
&& __CFRunLoopModeIsEmpty(rl
, rlm
, previousMode
)) {
2332 returnValue
= kCFRunLoopRunFinished
;
2334 if (0 != returnValue
) {
2335 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2336 if (MACH_PORT_NULL
!= timeoutPort
) {
2337 mk_timer_destroy(timeoutPort
);
2346 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2348 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
2349 __CFRunLoopLock(rl
);
2350 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
2351 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
, rl
->_currentMode
)) {
2352 Boolean did
= false;
2353 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2355 if (rl
->_blocks_head
) {
2356 __CFRunLoopDoBlocks(rl
, modeName
);
2359 __CFRunLoopUnlock(rl
);
2360 return did
? kCFRunLoopRunHandledSource
: kCFRunLoopRunFinished
;
2362 uint32_t *previousStopped
= (uint32_t *)rl
->_stopped
;
2363 rl
->_stopped
= NULL
;
2364 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
2365 rl
->_currentMode
= currentMode
;
2366 #if DEPLOYMENT_TARGET_WINDOWS
2367 if (previousMode
&& currentMode
!= previousMode
) {
2368 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2369 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
2371 __CFRunLoopUpdateMsgWait(rl
);
2374 __CFRunLoopUnlock(rl
);
2377 if (currentMode
->_observerMask
& kCFRunLoopEntry
|| currentMode
->_submodes
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
2378 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, previousMode
, false);
2379 if (currentMode
->_observerMask
& kCFRunLoopExit
|| currentMode
->_submodes
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
2381 // this kvetches if an exception was raised during a run loop callout, because the mode is not locked
2382 if (0 != currentMode
->_lock
) {
2383 __CFRunLoopModeUnlock(currentMode
);
2385 __CFRunLoopLock(rl
);
2386 if (rl
->_stopped
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (uint32_t *)rl
->_stopped
);
2387 rl
->_stopped
= previousStopped
;
2388 rl
->_currentMode
= previousMode
;
2389 #if DEPLOYMENT_TARGET_WINDOWS
2390 if (previousMode
&& currentMode
!= previousMode
) {
2391 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2392 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl
);
2394 __CFRunLoopUpdateMsgWait(rl
);
2397 __CFRunLoopUnlock(rl
);
2402 void CFRunLoopRun(void) { /* DOES CALLOUT */
2405 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
2407 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
2410 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2412 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
2415 static void __CFRunLoopFindMinTimer(const void *value
, void *ctx
) {
2416 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
2417 if (__CFIsValid(rlt
)) {
2418 CFRunLoopTimerRef
*result
= (CFRunLoopTimerRef
*)ctx
;
2419 if (NULL
== *result
|| rlt
->_fireTSR
< (*result
)->_fireTSR
) {
2425 #if DEPLOYMENT_TARGET_WINDOWS
2426 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
2427 CFRunLoopTimerRef result
= NULL
;
2428 int64_t fireTime
= 0;
2430 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
2431 __CFRunLoopTimerFireTSRLock();
2432 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
2434 fireTime
= result
->_fireTSR
;
2435 __CFRunLoopTimerFireTSRUnlock();
2437 if (NULL
!= rlm
->_submodes
) {
2439 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
2440 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
2441 CFRunLoopModeRef subrlm
;
2442 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2443 if (NULL
!= subrlm
) {
2444 int64_t newFireTime
= __CFRunLoopGetNextTimerFireTSR(rl
, subrlm
);
2445 __CFRunLoopModeUnlock(subrlm
);
2446 if (fireTime
== 0 || (newFireTime
!= 0 && newFireTime
< fireTime
))
2447 fireTime
= newFireTime
;
2451 __CFRunLoopModeUnlock(rlm
);
2457 // called with rlm locked, if not NULL
2458 static CFAbsoluteTime
__CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
2459 CFRunLoopTimerRef result
= NULL
;
2460 CFAbsoluteTime fireDate
= 0.0;
2461 int64_t now2
= (int64_t)mach_absolute_time();
2462 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2464 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
2465 __CFRunLoopTimerFireTSRLock();
2466 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
2468 fireDate
= (0 == result
->_fireTSR
) ? 0.0 : (now1
+ __CFTSRToTimeInterval(result
->_fireTSR
- now2
));
2470 __CFRunLoopTimerFireTSRUnlock();
2472 if (NULL
!= rlm
->_submodes
) {
2474 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
2475 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
2476 CFRunLoopModeRef subrlm
;
2477 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2478 if (NULL
!= subrlm
) {
2479 CFAbsoluteTime newFireDate
= __CFRunLoopGetNextTimerFireDate(rl
, subrlm
);
2480 __CFRunLoopModeUnlock(subrlm
);
2481 if (fireDate
== 0 || (newFireDate
!= 0.0 && newFireDate
< fireDate
))
2482 fireDate
= newFireDate
;
2486 __CFRunLoopModeUnlock(rlm
);
2491 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
2493 CFRunLoopModeRef rlm
;
2494 __CFRunLoopLock(rl
);
2495 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2496 __CFRunLoopUnlock(rl
);
2497 return __CFRunLoopGetNextTimerFireDate(rl
, rlm
);
2500 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
2502 return __CFRunLoopIsSleeping(rl
);
2505 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
2507 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2509 /* We unconditionally try to send the message, since we don't want
2510 * to lose a wakeup, but the send may fail if there is already a
2511 * wakeup pending, since the queue length is 1. */
2512 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
2513 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
2517 SetEvent(rl
->_wakeUpPort
);
2518 __CFRunLoopLock(rl
);
2519 if (rl
->_threadID
== GetCurrentThreadId()) {
2520 PostMessageW(NULL
, __kCFRunLoopWakeUpMessage
, NULL
, NULL
);
2522 PostThreadMessageW(rl
->_threadID
, __kCFRunLoopWakeUpMessage
, NULL
, NULL
);
2524 __CFRunLoopUnlock(rl
);
2528 void CFRunLoopStop(CFRunLoopRef rl
) {
2529 Boolean doWake
= false;
2531 __CFRunLoopLock(rl
);
2532 if (rl
->_currentMode
) {
2533 __CFRunLoopSetStopped(rl
);
2536 __CFRunLoopUnlock(rl
);
2538 CFRunLoopWakeUp(rl
);
2542 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
2544 CFRunLoopModeRef rlm
;
2545 __CFRunLoopLock(rl
);
2546 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2547 __CFRunLoopUnlock(rl
);
2549 rlm
->_stopped
= true;
2550 __CFRunLoopModeUnlock(rlm
);
2552 CFRunLoopWakeUp(rl
);
2555 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2557 CFRunLoopModeRef rlm
;
2558 if (modeName
== kCFRunLoopCommonModes
|| candidateContainedName
== kCFRunLoopCommonModes
) {
2560 } else if (CFEqual(modeName
, candidateContainedName
)) {
2563 __CFRunLoopLock(rl
);
2564 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2565 __CFRunLoopUnlock(rl
);
2567 CFArrayRef submodes
;
2568 if (NULL
== rlm
->_submodes
) {
2569 __CFRunLoopModeUnlock(rlm
);
2572 if (CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), candidateContainedName
)) {
2573 __CFRunLoopModeUnlock(rlm
);
2576 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
2577 __CFRunLoopModeUnlock(rlm
);
2578 if (NULL
!= submodes
) {
2580 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
2581 CFStringRef subname
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
2582 if (_CFRunLoopModeContainsMode(rl
, subname
, candidateContainedName
)) {
2583 CFRelease(submodes
);
2587 CFRelease(submodes
);
2593 CF_EXPORT
void _CFRunLoopAddModeToMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef toModeName
) {
2595 CFRunLoopModeRef rlm
;
2596 if (__CFRunLoopIsDeallocating(rl
)) return;
2597 // should really do a recursive check here, to make sure that a cycle isn't
2598 // introduced; of course, if that happens, you aren't going to get very far.
2599 if (modeName
== kCFRunLoopCommonModes
|| toModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, toModeName
)) {
2602 __CFRunLoopLock(rl
);
2603 rlm
= __CFRunLoopFindMode(rl
, toModeName
, true);
2604 __CFRunLoopUnlock(rl
);
2606 if (NULL
== rlm
->_submodes
) {
2607 rlm
->_submodes
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2609 if (!CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), modeName
)) {
2610 CFArrayAppendValue(rlm
->_submodes
, modeName
);
2612 __CFRunLoopModeUnlock(rlm
);
2617 CF_EXPORT
void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef fromModeName
) {
2619 CFRunLoopModeRef rlm
;
2620 // should really do a recursive check here, to make sure that a cycle isn't
2621 // introduced; of course, if that happens, you aren't going to get very far.
2622 if (modeName
== kCFRunLoopCommonModes
|| fromModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, fromModeName
)) {
2625 __CFRunLoopLock(rl
);
2626 rlm
= __CFRunLoopFindMode(rl
, fromModeName
, true);
2627 __CFRunLoopUnlock(rl
);
2629 if (NULL
!= rlm
->_submodes
) {
2630 CFIndex idx
, cnt
= CFArrayGetCount(rlm
->_submodes
);
2631 idx
= CFArrayGetFirstIndexOfValue(rlm
->_submodes
, CFRangeMake(0, cnt
), modeName
);
2632 if (0 <= idx
) CFArrayRemoveValueAtIndex(rlm
->_submodes
, idx
);
2634 __CFRunLoopModeUnlock(rlm
);
2639 void CFRunLoopPerformBlock(CFRunLoopRef rl
, CFTypeRef mode
, void (^block
)(void)) {
2641 if (CFStringGetTypeID() == CFGetTypeID(mode
)) {
2642 mode
= CFStringCreateCopy(kCFAllocatorSystemDefault
, (CFStringRef
)mode
);
2643 __CFRunLoopLock(rl
);
2644 // ensure mode exists
2645 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)mode
, true);
2646 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2647 __CFRunLoopUnlock(rl
);
2648 } else if (CFArrayGetTypeID() == CFGetTypeID(mode
)) {
2649 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)mode
);
2650 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2651 CFArrayGetValues((CFArrayRef
)mode
, CFRangeMake(0, cnt
), values
);
2652 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2653 __CFRunLoopLock(rl
);
2654 // ensure modes exist
2655 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2656 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2657 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2659 __CFRunLoopUnlock(rl
);
2661 } else if (CFSetGetTypeID() == CFGetTypeID(mode
)) {
2662 CFIndex cnt
= CFSetGetCount((CFSetRef
)mode
);
2663 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2664 CFSetGetValues((CFSetRef
)mode
, values
);
2665 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2666 __CFRunLoopLock(rl
);
2667 // ensure modes exist
2668 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2669 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2670 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2672 __CFRunLoopUnlock(rl
);
2677 #if DEPLOYMENT_TARGET_WINDOWS
2678 // <rdar://problem/6496715> Block.h uses "typeof", which is not available when using Visual Studio on Windows
2679 block
= (void (^)(void))_Block_copy(block
);
2681 block
= Block_copy(block
);
2683 if (!mode
|| !block
) {
2684 if (mode
) CFRelease(mode
);
2685 if (block
) Block_release(block
);
2688 __CFRunLoopLock(rl
);
2689 struct _block_item
*new_item
= (struct _block_item
*)malloc(sizeof(struct _block_item
));
2690 new_item
->_next
= NULL
;
2691 new_item
->_mode
= mode
;
2692 new_item
->_block
= block
;
2693 if (!rl
->_blocks_tail
) {
2694 rl
->_blocks_head
= new_item
;
2696 rl
->_blocks_tail
->_next
= new_item
;
2698 rl
->_blocks_tail
= new_item
;
2699 __CFRunLoopUnlock(rl
);
2702 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2704 CFRunLoopModeRef rlm
;
2705 Boolean hasValue
= false;
2706 __CFRunLoopLock(rl
);
2707 if (modeName
== kCFRunLoopCommonModes
) {
2708 if (NULL
!= rl
->_commonModeItems
) {
2709 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2711 __CFRunLoopUnlock(rl
);
2713 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2714 __CFRunLoopUnlock(rl
);
2715 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2716 hasValue
= CFSetContainsValue(rlm
->_sources
, rls
);
2717 __CFRunLoopModeUnlock(rlm
);
2718 } else if (NULL
!= rlm
) {
2719 __CFRunLoopModeUnlock(rlm
);
2725 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2727 CFRunLoopModeRef rlm
;
2728 if (__CFRunLoopIsDeallocating(rl
)) return;
2729 if (!__CFIsValid(rls
)) return;
2730 __CFRunLoopLock(rl
);
2731 if (modeName
== kCFRunLoopCommonModes
) {
2732 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2733 if (NULL
== rl
->_commonModeItems
) {
2734 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2735 _CFSetSetCapacity(rl
->_commonModeItems
, 20);
2737 CFSetAddValue(rl
->_commonModeItems
, rls
);
2738 __CFRunLoopUnlock(rl
);
2740 CFTypeRef context
[2] = {rl
, rls
};
2741 /* add new item to all common-modes */
2742 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2746 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2747 __CFRunLoopUnlock(rl
);
2748 if (NULL
!= rlm
&& NULL
== rlm
->_sources
) {
2749 rlm
->_sources
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2750 rlm
->_portToV1SourceMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
2751 _CFSetSetCapacity(rlm
->_sources
, 10);
2753 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources
, rls
)) {
2754 CFSetAddValue(rlm
->_sources
, rls
);
2755 if (1 == rls
->_context
.version0
.version
) {
2756 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2757 CFDictionarySetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
, rls
);
2759 __CFRunLoopModeUnlock(rlm
);
2760 __CFRunLoopSourceSchedule(rls
, rl
, rlm
); /* DOES CALLOUT */
2761 } else if (NULL
!= rlm
) {
2762 __CFRunLoopModeUnlock(rlm
);
2767 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2769 CFRunLoopModeRef rlm
;
2770 __CFRunLoopLock(rl
);
2771 if (modeName
== kCFRunLoopCommonModes
) {
2772 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2773 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2774 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2775 __CFRunLoopUnlock(rl
);
2777 CFTypeRef context
[2] = {rl
, rls
};
2778 /* remove new item from all common-modes */
2779 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2783 __CFRunLoopUnlock(rl
);
2786 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2787 __CFRunLoopUnlock(rl
);
2788 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
&& CFSetContainsValue(rlm
->_sources
, rls
)) {
2790 if (1 == rls
->_context
.version0
.version
) {
2791 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2792 CFDictionaryRemoveValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
);
2794 CFSetRemoveValue(rlm
->_sources
, rls
);
2795 __CFRunLoopModeUnlock(rlm
);
2796 __CFRunLoopSourceCancel(rls
, rl
, rlm
); /* DOES CALLOUT */
2798 } else if (NULL
!= rlm
) {
2799 __CFRunLoopModeUnlock(rlm
);
2804 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value
, void *ctx
) {
2805 CFStringRef modeName
= (CFStringRef
)value
;
2806 CFRunLoopRef rl
= (CFRunLoopRef
)ctx
;
2807 __CFRunLoopRemoveAllSources(rl
, modeName
);
2810 static void __CFRunLoopRemoveSourceFromMode(const void *value
, void *ctx
) {
2811 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
2812 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
2813 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
2814 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2817 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
) {
2819 CFRunLoopModeRef rlm
;
2820 __CFRunLoopLock(rl
);
2821 if (modeName
== kCFRunLoopCommonModes
) {
2822 if (NULL
!= rl
->_commonModeItems
) {
2823 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2824 __CFRunLoopUnlock(rl
);
2826 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourcesFromCommonMode
), (void *)rl
);
2830 __CFRunLoopUnlock(rl
);
2833 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2834 __CFRunLoopUnlock(rl
);
2835 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2836 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources
);
2837 __CFRunLoopModeUnlock(rlm
);
2838 CFTypeRef context
[2] = {rl
, modeName
};
2839 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2841 } else if (NULL
!= rlm
) {
2842 __CFRunLoopModeUnlock(rlm
);
2847 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2849 CFRunLoopModeRef rlm
;
2850 Boolean hasValue
= false;
2851 __CFRunLoopLock(rl
);
2852 if (modeName
== kCFRunLoopCommonModes
) {
2853 if (NULL
!= rl
->_commonModeItems
) {
2854 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2856 __CFRunLoopUnlock(rl
);
2858 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2859 __CFRunLoopUnlock(rl
);
2860 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2861 hasValue
= CFSetContainsValue(rlm
->_observers
, rlo
);
2862 __CFRunLoopModeUnlock(rlm
);
2863 } else if (NULL
!= rlm
) {
2864 __CFRunLoopModeUnlock(rlm
);
2870 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2872 CFRunLoopModeRef rlm
;
2873 if (__CFRunLoopIsDeallocating(rl
)) return;
2874 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2875 __CFRunLoopLock(rl
);
2876 if (modeName
== kCFRunLoopCommonModes
) {
2877 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2878 if (NULL
== rl
->_commonModeItems
) {
2879 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2881 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2882 __CFRunLoopUnlock(rl
);
2884 CFTypeRef context
[2] = {rl
, rlo
};
2885 /* add new item to all common-modes */
2886 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2890 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2891 __CFRunLoopUnlock(rl
);
2892 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2893 rlm
->_observers
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2895 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_observers
, rlo
)) {
2896 CFSetAddValue(rlm
->_observers
, rlo
);
2897 rlm
->_observerMask
|= rlo
->_activities
;
2898 __CFRunLoopModeUnlock(rlm
);
2899 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
2900 } else if (NULL
!= rlm
) {
2901 __CFRunLoopModeUnlock(rlm
);
2906 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2908 CFRunLoopModeRef rlm
;
2909 __CFRunLoopLock(rl
);
2910 if (modeName
== kCFRunLoopCommonModes
) {
2911 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
2912 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2913 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
2914 __CFRunLoopUnlock(rl
);
2916 CFTypeRef context
[2] = {rl
, rlo
};
2917 /* remove new item from all common-modes */
2918 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2922 __CFRunLoopUnlock(rl
);
2925 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2926 __CFRunLoopUnlock(rl
);
2927 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
&& CFSetContainsValue(rlm
->_observers
, rlo
)) {
2929 CFSetRemoveValue(rlm
->_observers
, rlo
);
2930 __CFRunLoopModeUnlock(rlm
);
2931 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
2933 } else if (NULL
!= rlm
) {
2934 __CFRunLoopModeUnlock(rlm
);
2939 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2941 CFRunLoopModeRef rlm
;
2942 Boolean hasValue
= false;
2943 __CFRunLoopLock(rl
);
2944 if (modeName
== kCFRunLoopCommonModes
) {
2945 if (NULL
!= rl
->_commonModeItems
) {
2946 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
2948 __CFRunLoopUnlock(rl
);
2950 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2951 __CFRunLoopUnlock(rl
);
2952 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2953 hasValue
= CFSetContainsValue(rlm
->_timers
, rlt
);
2954 __CFRunLoopModeUnlock(rlm
);
2955 } else if (NULL
!= rlm
) {
2956 __CFRunLoopModeUnlock(rlm
);
2962 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2964 //CFLog(4, CFSTR("CFRunLoopAddTimer(%p, timer %p, %@)"), rl, rlt, modeName);
2965 CFRunLoopModeRef rlm
;
2966 if (__CFRunLoopIsDeallocating(rl
)) return;
2967 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
2968 __CFRunLoopLock(rl
);
2969 if (modeName
== kCFRunLoopCommonModes
) {
2970 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2971 if (NULL
== rl
->_commonModeItems
) {
2972 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2974 CFSetAddValue(rl
->_commonModeItems
, rlt
);
2975 __CFRunLoopUnlock(rl
);
2977 CFTypeRef context
[2] = {rl
, rlt
};
2978 /* add new item to all common-modes */
2979 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2983 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2984 __CFRunLoopUnlock(rl
);
2985 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
2986 rlm
->_timers
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2988 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_timers
, rlt
)) {
2989 CFSetAddValue(rlm
->_timers
, rlt
);
2990 __CFRunLoopModeUnlock(rlm
);
2991 __CFRunLoopTimerSchedule(rlt
, rl
, rlm
);
2992 } else if (NULL
!= rlm
) {
2993 __CFRunLoopModeUnlock(rlm
);
2998 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3000 //CFLog(4, CFSTR("CFRunLoopRemoveTimer(%p, timer %p, %@)"), rl, rlt, modeName);
3001 CFRunLoopModeRef rlm
;
3002 __CFRunLoopLock(rl
);
3003 if (modeName
== kCFRunLoopCommonModes
) {
3004 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
3005 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3006 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
3007 __CFRunLoopUnlock(rl
);
3009 CFTypeRef context
[2] = {rl
, rlt
};
3010 /* remove new item from all common-modes */
3011 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3015 __CFRunLoopUnlock(rl
);
3018 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3019 __CFRunLoopUnlock(rl
);
3020 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
&& CFSetContainsValue(rlm
->_timers
, rlt
)) {
3022 CFSetRemoveValue(rlm
->_timers
, rlt
);
3023 __CFRunLoopModeUnlock(rlm
);
3024 __CFRunLoopTimerCancel(rlt
, rl
, rlm
);
3026 } else if (NULL
!= rlm
) {
3027 __CFRunLoopModeUnlock(rlm
);
3033 /* CFRunLoopSource */
3035 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
3036 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
3037 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
3038 if (rls1
== rls2
) return true;
3039 if (__CFIsValid(rls1
) != __CFIsValid(rls2
)) return false;
3040 if (rls1
->_order
!= rls2
->_order
) return false;
3041 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
3042 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
3043 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
3044 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
3045 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
3046 if (rls1
->_context
.version0
.equal
)
3047 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
3048 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
3051 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
3052 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3053 if (rls
->_context
.version0
.hash
)
3054 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
3055 return (CFHashCode
)rls
->_context
.version0
.info
;
3058 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3059 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3061 CFStringRef contextDesc
= NULL
;
3062 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
3063 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
3065 if (NULL
== contextDesc
) {
3066 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
3067 #if DEPLOYMENT_TARGET_WINDOWS
3068 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, addr
);
3069 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3071 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3072 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
3074 #error Unknown or unspecified DEPLOYMENT_TARGET
3077 #if DEPLOYMENT_TARGET_WINDOWS
3078 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
);
3080 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
);
3082 CFRelease(contextDesc
);
3086 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3087 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3088 CFRunLoopSourceInvalidate(rls
);
3089 if (rls
->_context
.version0
.release
) {
3090 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
3092 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0, sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
));
3095 static const CFRuntimeClass __CFRunLoopSourceClass
= {
3096 _kCFRuntimeScannedObject
,
3100 __CFRunLoopSourceDeallocate
,
3101 __CFRunLoopSourceEqual
,
3102 __CFRunLoopSourceHash
,
3104 __CFRunLoopSourceCopyDescription
3107 __private_extern__
void __CFRunLoopSourceInitialize(void) {
3108 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
3111 CFTypeID
CFRunLoopSourceGetTypeID(void) {
3112 return __kCFRunLoopSourceTypeID
;
3115 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
3117 CFRunLoopSourceRef memory
;
3119 if (NULL
== context
) HALT
;
3120 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
3121 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
3122 if (NULL
== memory
) {
3125 __CFSetValid(memory
);
3126 __CFRunLoopSourceUnsetSignaled(memory
);
3127 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3129 memory
->_order
= order
;
3130 memory
->_runLoops
= NULL
;
3132 switch (context
->version
) {
3134 size
= sizeof(CFRunLoopSourceContext
);
3137 size
= sizeof(CFRunLoopSourceContext1
);
3139 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3141 size
= sizeof(CFRunLoopSourceContext2
);
3145 objc_memmove_collectable(&memory
->_context
, context
, size
);
3146 if (context
->retain
) {
3147 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
3152 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
3154 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3158 static void __CFRunLoopSourceWakeUpLoop(const void *value
, void *context
) {
3159 CFRunLoopWakeUp((CFRunLoopRef
)value
);
3162 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
3163 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
3164 CFTypeRef
*params
= (CFTypeRef
*)context
;
3165 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
3168 if (rl
== params
[1]) return;
3169 array
= CFRunLoopCopyAllModes(rl
);
3170 for (idx
= CFArrayGetCount(array
); idx
--;) {
3171 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3172 CFRunLoopRemoveSource(rl
, rls
, modeName
);
3174 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
3179 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
3181 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3183 __CFRunLoopSourceLock(rls
);
3184 if (__CFIsValid(rls
)) {
3185 __CFUnsetValid(rls
);
3186 __CFRunLoopSourceUnsetSignaled(rls
);
3187 if (NULL
!= rls
->_runLoops
) {
3188 CFTypeRef params
[2] = {rls
, NULL
};
3189 CFBagRef bag
= rls
->_runLoops
;
3190 rls
->_runLoops
= NULL
;
3191 __CFRunLoopSourceUnlock(rls
);
3192 CFBagApplyFunction(bag
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
3195 __CFRunLoopSourceUnlock(rls
);
3197 /* for hashing- and equality-use purposes, can't actually release the context here */
3199 __CFRunLoopSourceUnlock(rls
);
3204 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
3206 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3207 return __CFIsValid(rls
);
3210 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
3212 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3213 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
3215 switch (context
->version
) {
3217 size
= sizeof(CFRunLoopSourceContext
);
3220 size
= sizeof(CFRunLoopSourceContext1
);
3222 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3224 size
= sizeof(CFRunLoopSourceContext2
);
3228 memmove(context
, &rls
->_context
, size
);
3231 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
3233 __CFRunLoopSourceLock(rls
);
3234 if (__CFIsValid(rls
)) {
3235 __CFRunLoopSourceSetSignaled(rls
);
3237 __CFRunLoopSourceUnlock(rls
);
3240 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
3242 __CFRunLoopSourceLock(rls
);
3243 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
3244 __CFRunLoopSourceUnlock(rls
);
3248 __private_extern__
void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
) {
3249 __CFRunLoopSourceLock(rls
);
3250 if (__CFIsValid(rls
) && NULL
!= rls
->_runLoops
) {
3251 CFBagApplyFunction(rls
->_runLoops
, __CFRunLoopSourceWakeUpLoop
, NULL
);
3253 __CFRunLoopSourceUnlock(rls
);
3256 /* CFRunLoopObserver */
3258 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3259 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3261 CFStringRef contextDesc
= NULL
;
3262 if (NULL
!= rlo
->_context
.copyDescription
) {
3263 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
3266 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
3268 #if DEPLOYMENT_TARGET_WINDOWS
3269 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
);
3270 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3271 void *addr
= rlo
->_callout
;
3273 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3274 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
);
3276 #error Unknown or unspecified DEPLOYMENT_TARGET
3278 CFRelease(contextDesc
);
3282 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3283 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3284 CFRunLoopObserverInvalidate(rlo
);
3287 static const CFRuntimeClass __CFRunLoopObserverClass
= {
3289 "CFRunLoopObserver",
3292 __CFRunLoopObserverDeallocate
,
3296 __CFRunLoopObserverCopyDescription
3299 __private_extern__
void __CFRunLoopObserverInitialize(void) {
3300 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
3303 CFTypeID
CFRunLoopObserverGetTypeID(void) {
3304 return __kCFRunLoopObserverTypeID
;
3307 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
3309 CFRunLoopObserverRef memory
;
3311 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
3312 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
3313 if (NULL
== memory
) {
3316 __CFSetValid(memory
);
3317 __CFRunLoopObserverUnsetFiring(memory
);
3319 __CFRunLoopObserverSetRepeats(memory
);
3321 __CFRunLoopObserverUnsetRepeats(memory
);
3323 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3324 memory
->_runLoop
= NULL
;
3325 memory
->_rlCount
= 0;
3326 memory
->_activities
= activities
;
3327 memory
->_order
= order
;
3328 memory
->_callout
= callout
;
3330 if (context
->retain
) {
3331 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3333 memory
->_context
.info
= context
->info
;
3335 memory
->_context
.retain
= context
->retain
;
3336 memory
->_context
.release
= context
->release
;
3337 memory
->_context
.copyDescription
= context
->copyDescription
;
3339 memory
->_context
.info
= 0;
3340 memory
->_context
.retain
= 0;
3341 memory
->_context
.release
= 0;
3342 memory
->_context
.copyDescription
= 0;
3347 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
3349 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3350 return rlo
->_activities
;
3353 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
3355 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3359 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
3361 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3362 return __CFRunLoopObserverRepeats(rlo
);
3365 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
3367 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3369 __CFRunLoopObserverLock(rlo
);
3370 if (__CFIsValid(rlo
)) {
3371 CFRunLoopRef rl
= rlo
->_runLoop
;
3372 __CFUnsetValid(rlo
);
3373 __CFRunLoopObserverUnlock(rlo
);
3377 array
= CFRunLoopCopyAllModes(rl
);
3378 for (idx
= CFArrayGetCount(array
); idx
--;) {
3379 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3380 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
3382 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
3385 if (rlo
->_context
.release
)
3386 rlo
->_context
.release(rlo
->_context
.info
); /* CALLOUT */
3387 rlo
->_context
.info
= NULL
;
3389 __CFRunLoopObserverUnlock(rlo
);
3394 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
3396 return __CFIsValid(rlo
);
3399 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
3401 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3402 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3403 *context
= rlo
->_context
;
3406 /* CFRunLoopTimer */
3408 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3409 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3411 int64_t now2
= (int64_t)mach_absolute_time();
3412 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3413 __CFRunLoopTimerFireTSRLock();
3414 int64_t fireTime
= rlt
->_fireTSR
;
3415 __CFRunLoopTimerFireTSRUnlock();
3416 CFAbsoluteTime fireDate
= now1
+ __CFTSRToTimeInterval(fireTime
- now2
);
3417 CFStringRef contextDesc
= NULL
;
3418 if (NULL
!= rlt
->_context
.copyDescription
) {
3419 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
3421 if (NULL
== contextDesc
) {
3422 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
3424 #if DEPLOYMENT_TARGET_WINDOWS
3425 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
);
3426 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3427 void *addr
= rlt
->_callout
;
3429 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3430 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
);
3432 #error Unknown or unspecified DEPLOYMENT_TARGET
3434 CFRelease(contextDesc
);
3438 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3439 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3440 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3441 __CFRunLoopTimerSetDeallocating(rlt
);
3442 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
3443 CFRelease(rlt
->_rlModes
);
3444 rlt
->_rlModes
= NULL
;
3447 static const CFRuntimeClass __CFRunLoopTimerClass
= {
3452 __CFRunLoopTimerDeallocate
,
3456 __CFRunLoopTimerCopyDescription
3459 __private_extern__
void __CFRunLoopTimerInitialize(void) {
3460 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
3463 CFTypeID
CFRunLoopTimerGetTypeID(void) {
3464 return __kCFRunLoopTimerTypeID
;
3467 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
3469 CFRunLoopTimerRef memory
;
3471 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
3472 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
3473 if (NULL
== memory
) {
3476 __CFSetValid(memory
);
3477 __CFRunLoopTimerUnsetFiring(memory
);
3478 __CFRunLoopTimerUnsetDidFire(memory
);
3479 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
3480 memory
->_runLoop
= NULL
;
3481 memory
->_rlModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3482 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3483 memory
->_port
= MACH_PORT_NULL
;
3485 memory
->_order
= order
;
3486 if (interval
< 0.0) interval
= 0.0;
3487 memory
->_interval
= interval
;
3488 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3489 if (TIMER_INTERVAL_LIMIT
< interval
) interval
= TIMER_INTERVAL_LIMIT
;
3490 memory
->_nextFireDate
= fireDate
;
3491 int64_t now2
= (int64_t)mach_absolute_time();
3492 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3493 if (fireDate
< now1
) {
3494 memory
->_fireTSR
= now2
;
3495 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
3496 memory
->_fireTSR
= LLONG_MAX
;
3498 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3500 if (interval
<= 0.0) {
3501 memory
->_intervalTSR
= 0;
3502 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < interval
) {
3503 memory
->_intervalTSR
= LLONG_MAX
;
3505 memory
->_intervalTSR
= __CFTimeIntervalToTSR(interval
);
3507 memory
->_callout
= callout
;
3508 if (NULL
!= context
) {
3509 if (context
->retain
) {
3510 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3512 memory
->_context
.info
= context
->info
;
3514 memory
->_context
.retain
= context
->retain
;
3515 memory
->_context
.release
= context
->release
;
3516 memory
->_context
.copyDescription
= context
->copyDescription
;
3518 memory
->_context
.info
= 0;
3519 memory
->_context
.retain
= 0;
3520 memory
->_context
.release
= 0;
3521 memory
->_context
.copyDescription
= 0;
3523 //CFLog(4, CFSTR("CFRunLoopTimerCreate(%p, %f, %f, 0x%lx, %ld, %p, %p) => %p"), allocator, fireDate, interval, flags, order, callout, context, memory);
3527 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
3529 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, rlt
, "_cffireTime");
3530 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3531 int64_t fireTime
, result
= 0;
3532 __CFRunLoopTimerFireTSRLock();
3533 fireTime
= rlt
->_fireTSR
;
3534 __CFRunLoopTimerFireTSRUnlock();
3535 __CFRunLoopTimerLock(rlt
);
3536 if (__CFIsValid(rlt
)) {
3539 __CFRunLoopTimerUnlock(rlt
);
3540 int64_t now2
= (int64_t)mach_absolute_time();
3541 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3542 return (0 == result
) ? 0.0 : now1
+ __CFTSRToTimeInterval(result
- now2
);
3545 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
3546 //CFLog(6, CFSTR("CFRunLoopTimerSetNextFireDate(rlt %p, fireDate %f)"), rlt, fireDate);
3548 //CFLog(4, CFSTR("CFRunLoopTimerSetNextFireDate(%p, %f) [limit: %f]"), rlt, fireDate, TIMER_DATE_LIMIT);
3549 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3550 rlt
->_nextFireDate
= fireDate
;
3551 int64_t now2
= (int64_t)mach_absolute_time();
3552 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3553 __CFRunLoopTimerFireTSRLock();
3554 if (fireDate
< now1
) {
3555 rlt
->_fireTSR
= now2
;
3556 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
3557 rlt
->_fireTSR
= LLONG_MAX
;
3559 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3561 if (rlt
->_runLoop
!= NULL
) {
3562 __CFRunLoopTimerRescheduleWithAllModes(rlt
);
3564 __CFRunLoopTimerFireTSRUnlock();
3567 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
3569 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFTimeInterval
, rlt
, "timeInterval");
3570 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3571 return rlt
->_interval
;
3574 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
3576 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3577 return (0.0 < rlt
->_interval
);
3580 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
3582 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFIndex
, rlt
, "order");
3583 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3587 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
3589 //CFLog(4, CFSTR("CFRunLoopTimerInvalidate(%p)"), rlt);
3590 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, void, rlt
, "invalidate");
3591 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3592 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3595 __CFRunLoopTimerLock(rlt
);
3596 if (__CFIsValid(rlt
)) {
3597 CFRunLoopRef rl
= rlt
->_runLoop
;
3598 void *info
= rlt
->_context
.info
;
3599 __CFUnsetValid(rlt
);
3600 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3601 __CFRunLoopTimerPortMapLock();
3602 if (NULL
!= __CFRLTPortMap
) {
3603 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
3605 __CFRunLoopTimerPortMapUnlock();
3606 mk_timer_destroy(rlt
->_port
);
3607 rlt
->_port
= MACH_PORT_NULL
;
3609 rlt
->_context
.info
= NULL
;
3610 __CFRunLoopTimerUnlock(rlt
);
3612 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3613 STACK_BUFFER_DECL(CFStringRef
, modes
, cnt
);
3614 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3615 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3616 CFRunLoopRemoveTimer(rl
, rlt
, modes
[idx
]);
3618 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
3620 if (NULL
!= rlt
->_context
.release
) {
3621 rlt
->_context
.release(info
); /* CALLOUT */
3624 __CFRunLoopTimerUnlock(rlt
);
3626 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3631 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
3633 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, Boolean
, rlt
, "isValid");
3634 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3635 return __CFIsValid(rlt
);
3638 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
3640 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3641 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3642 *context
= rlt
->_context
;
3646 #if DEPLOYMENT_TARGET_WINDOWS
3648 //#if MARRY_MESSAGE_QUEUE
3650 // Do we need to make sure it's not CFRunLoopRun processing the message queue?
3651 CF_EXPORT LRESULT CALLBACK
pumpRunLoopFromMessageQueue(int nCode
, WPARAM wParam
, LPARAM lParam
) {
3652 //if nCode < 0, we're supposed to blindly call CallNexthookEx instead of processing the message ourselves
3654 MSG
*msgPtr
= (MSG
*)lParam
;
3655 CFRunLoopRef rl
= CFRunLoopGetCurrent();
3656 CFStringRef currMode
;
3658 if (msgPtr
->message
== __kCFRunLoopV1SourceReadyMessage
) {
3659 CFRunLoopModeRef rlm
;
3660 CFRunLoopSourceRef rls
;
3661 __CFRunLoopLock(rl
);
3662 rlm
= rl
->_currentMode
;
3664 rlm
= __CFRunLoopFindMode(rl
, kCFRunLoopDefaultMode
, true); // returns the mode locked
3666 __CFRunLoopModeLock(rlm
);
3668 rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, (__CFPort
)msgPtr
->lParam
);
3669 __CFRunLoopUnlock(rl
);
3671 // Must still hold the mode lock when calling DoSource1
3672 __CFRunLoopDoSource1(rl
, rlm
, rls
);
3674 __CFRunLoopModeUnlock(rlm
);
3676 if (msgPtr
->message
== __kCFRunLoopV1SourceReadyMessage
|| msgPtr
->message
== __kCFRunLoopWakeUpMessage
) {
3677 // 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.
3678 currMode
= CFRunLoopCopyCurrentMode(rl
);
3680 currMode
= kCFRunLoopDefaultMode
;
3683 while (CFRunLoopRunInMode(currMode
, 0.0, true) == kCFRunLoopRunHandledSource
) {
3686 CFRelease(currMode
);
3689 return CallNextHookEx(__CFGetThreadSpecificData_inline()->_messageHook
, nCode
, wParam
, lParam
);
3692 void __CFRunLoopMsgWaitThread(void *theRL
) {
3693 CFRunLoopRef rl
= (CFRunLoopRef
)theRL
;
3694 Boolean allDone
= FALSE
;
3698 CFRunLoopModeRef rlm
;
3699 __CFPortSet waitSet
;
3700 DWORD waitResult
= WAIT_TIMEOUT
;
3702 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
3703 HANDLE
*handles
, *currHandle
;
3704 uint32_t handleCount
, handleIndex
;
3705 Boolean freeHandles
;
3707 __CFRunLoopLock(rl
);
3708 rlm
= rl
->_currentMode
;
3710 rlm
= __CFRunLoopFindMode(rl
, kCFRunLoopDefaultMode
, true); // Returns a locked mode
3712 __CFRunLoopModeLock(rlm
);
3715 waitSet
= rlm
->_portSet
;
3717 // copy out the handles to be safe from other threads at work
3718 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
3719 freeHandles
= (handles
!= handleBuf
);
3720 // Replace the wakeup port with our own update port
3721 for (handleIndex
= 0, currHandle
= handles
; handleIndex
< handleCount
; handleIndex
++, currHandle
++) {
3722 if (*currHandle
== rl
->_wakeUpPort
) {
3723 *currHandle
= rl
->_msgUpdatePort
;
3728 // Not sure what to do with this....
3729 // handles[handleCount] = rl->_msgShutdownPort;
3732 qMask
= rlm
->_msgQMask
;
3735 Boolean shuttingDown
= false;
3736 __CFRunLoopModeUnlock(rlm
);
3737 __CFRunLoopUnlock(rl
);
3739 // What do we do if there are more than MAXIMUM_WAIT_OBJECTS
3740 //waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE, qMask);
3741 waitResult
= WaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, INFINITE
);
3742 // Need to poll here to see if we've been told to die; if so, we must not touch rl. I think.
3743 __CFRunLoopLock(rl
);
3744 __CFRunLoopModeLock(rlm
);
3745 ResetEvent(rl
->_msgUpdatePort
);
3747 __CFPort livePort
= CFPORT_NULL
;
3748 if (waitResult
== WAIT_FAILED
) {
3749 DWORD error
= GetLastError();
3750 if (error
== ERROR_INVALID_HANDLE
) {
3751 // A handle got freed out from underneath us. Force an update of our handle watch list.
3752 livePort
= rl
->_msgUpdatePort
;
3754 CFAssert2(true, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects\n", __PRETTY_FUNCTION__
,error
);
3757 if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
3758 // a handle was signaled
3759 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
3760 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
3761 // an "abandoned mutex object"
3762 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
3765 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
3768 if (livePort
== rl
->_msgUpdatePort
) {
3770 // } else if (livePort == rl->_msgShutdownPort) {
3774 // OutputDebugStr(L"Posting v1 source ready msg\n");
3775 ResetEvent(livePort
);
3776 PostThreadMessageW(rl
->_threadID
, __kCFRunLoopV1SourceReadyMessage
, NULL
, (LPARAM
)livePort
);
3779 __CFRunLoopModeUnlock(rlm
);
3781 __CFRunLoopUnlock(rl
);
3787 // Called while holding the run loop lock
3789 //#if MARRY_MESSAGE_QUEUE
3791 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl
) {
3792 if (rl
->_msgUpdatePort
== CFPORT_NULL
) {
3793 rl
->_msgUpdatePort
= __CFPortAllocate();
3794 if (CFPORT_NULL
== rl
->_msgUpdatePort
) HALT
;
3796 // Kick off the MsgWaitThread
3797 _beginthread(__CFRunLoopMsgWaitThread
, 0, rl
);
3799 SetEvent(rl
->_msgUpdatePort
);
3802 CF_INLINE
void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl
) {}