2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1998-2012, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
29 #include <CoreFoundation/CFRunLoop.h>
30 #include <CoreFoundation/CFSet.h>
31 #include <CoreFoundation/CFBag.h>
32 #include "CFInternal.h"
37 #include <dispatch/dispatch.h>
38 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
39 #include <dispatch/private.h>
40 #include <CoreFoundation/CFUserNotification.h>
41 #include <mach/mach.h>
42 #include <mach/clock_types.h>
43 #include <mach/clock.h>
46 extern mach_port_t
_dispatch_get_main_queue_port_4CF(void);
47 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t
*msg
);
48 #elif DEPLOYMENT_TARGET_WINDOWS
50 DISPATCH_EXPORT HANDLE
_dispatch_get_main_queue_handle_4CF(void);
51 DISPATCH_EXPORT
void _dispatch_main_queue_callback_4CF(void);
53 #define MACH_PORT_NULL 0
54 #define mach_port_name_t HANDLE
55 #define _dispatch_get_main_queue_port_4CF _dispatch_get_main_queue_handle_4CF
56 #define _dispatch_main_queue_callback_4CF(x) _dispatch_main_queue_callback_4CF()
58 #define AbsoluteTime LARGE_INTEGER
64 static int _LogCFRunLoop
= 0;
66 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
67 #define TIMER_DATE_LIMIT 4039289856.0
68 #define TIMER_INTERVAL_LIMIT 504911232.0
70 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
72 #if DEPLOYMENT_TARGET_WINDOWS
74 static pthread_t kNilPthreadT
= { nil
, nil
};
75 #define pthreadPointer(a) a.p
76 typedef int kern_return_t
;
77 #define KERN_SUCCESS 0
81 static pthread_t kNilPthreadT
= (pthread_t
)0;
82 #define pthreadPointer(a) a
83 #define lockCount(a) a
87 CF_EXPORT
bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
89 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
90 // simple abstraction layer spanning Mach ports and Windows HANDLES
91 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
93 __private_extern__
uint32_t __CFGetProcessPortCount(void) {
94 ipc_info_space_t info
;
95 ipc_info_name_array_t table
= 0;
96 mach_msg_type_number_t tableCount
= 0;
97 ipc_info_tree_name_array_t tree
= 0;
98 mach_msg_type_number_t treeCount
= 0;
100 kern_return_t ret
= mach_port_space_info(mach_task_self(), &info
, &table
, &tableCount
, &tree
, &treeCount
);
101 if (ret
!= KERN_SUCCESS
) {
105 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)table
, tableCount
* sizeof(*table
));
108 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)tree
, treeCount
* sizeof(*tree
));
110 return (uint32_t)tableCount
;
113 __private_extern__ CFArrayRef
__CFStopAllThreads(void) {
114 CFMutableArrayRef suspended_list
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
115 mach_port_t my_task
= mach_task_self();
116 mach_port_t my_thread
= mach_thread_self();
117 thread_act_array_t thr_list
= 0;
118 mach_msg_type_number_t thr_cnt
= 0;
120 // really, should loop doing the stopping until no more threads get added to the list N times in a row
121 kern_return_t ret
= task_threads(my_task
, &thr_list
, &thr_cnt
);
122 if (ret
== KERN_SUCCESS
) {
123 for (CFIndex idx
= 0; idx
< thr_cnt
; idx
++) {
124 thread_act_t thread
= thr_list
[idx
];
125 if (thread
== my_thread
) continue;
126 if (CFArrayContainsValue(suspended_list
, CFRangeMake(0, CFArrayGetCount(suspended_list
)), (const void *)(uintptr_t)thread
)) continue;
127 ret
= thread_suspend(thread
);
128 if (ret
== KERN_SUCCESS
) {
129 CFArrayAppendValue(suspended_list
, (const void *)(uintptr_t)thread
);
131 mach_port_deallocate(my_task
, thread
);
134 vm_deallocate(my_task
, (vm_address_t
)thr_list
, sizeof(thread_t
) * thr_cnt
);
136 mach_port_deallocate(my_task
, my_thread
);
137 return suspended_list
;
140 __private_extern__
void __CFRestartAllThreads(CFArrayRef threads
) {
141 for (CFIndex idx
= 0; idx
< CFArrayGetCount(threads
); idx
++) {
142 thread_act_t thread
= (thread_act_t
)(uintptr_t)CFArrayGetValueAtIndex(threads
, idx
);
143 kern_return_t ret
= thread_resume(thread
);
144 if (ret
!= KERN_SUCCESS
) {
146 snprintf(msg
, 256, "*** Failure from thread_resume (%d) ***", ret
);
147 CRSetCrashLogMessage(msg
);
150 mach_port_deallocate(mach_task_self(), thread
);
154 static uint32_t __CF_last_warned_port_count
= 0;
156 static void foo() __attribute__((unused
));
158 uint32_t pcnt
= __CFGetProcessPortCount();
159 if (__CF_last_warned_port_count
+ 1000 < pcnt
) {
160 CFArrayRef threads
= __CFStopAllThreads();
164 CFOptionFlags responseFlags
= 0;
165 SInt32 result
= CFUserNotificationDisplayAlert(0.0, kCFUserNotificationCautionAlertLevel
, NULL
, NULL
, NULL
, CFSTR("High Mach Port Usage"), CFSTR("This application is using a lot of Mach ports."), CFSTR("Default"), CFSTR("Altern"), CFSTR("Other b"), &responseFlags
);
167 CFLog(3, CFSTR("ERROR"));
169 switch (responseFlags
) {
170 case kCFUserNotificationDefaultResponse
: CFLog(3, CFSTR("DefaultR")); break;
171 case kCFUserNotificationAlternateResponse
: CFLog(3, CFSTR("AltR")); break;
172 case kCFUserNotificationOtherResponse
: CFLog(3, CFSTR("OtherR")); break;
173 case kCFUserNotificationCancelResponse
: CFLog(3, CFSTR("CancelR")); break;
178 __CFRestartAllThreads(threads
);
180 __CF_last_warned_port_count
= pcnt
;
185 typedef mach_port_t __CFPort
;
186 #define CFPORT_NULL MACH_PORT_NULL
187 typedef mach_port_t __CFPortSet
;
189 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
190 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) { HALT
; };
192 static __CFPort
__CFPortAllocate(void) {
193 __CFPort result
= CFPORT_NULL
;
194 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
195 if (KERN_SUCCESS
!= ret
) {
197 snprintf(msg
, 256, "*** The system has no mach ports available. You may be able to diagnose which application(s) are using ports by using 'top' or Activity Monitor. (%d) ***", ret
);
198 CRSetCrashLogMessage(msg
);
199 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret
);
203 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
204 if (KERN_SUCCESS
!= ret
) {
206 snprintf(msg
, 256, "*** Unable to set send right on mach port. (%d) ***", ret
);
207 CRSetCrashLogMessage(msg
);
211 mach_port_limits_t limits
;
212 limits
.mpl_qlimit
= 1;
213 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
214 if (KERN_SUCCESS
!= ret
) {
216 snprintf(msg
, 256, "*** Unable to set attributes on mach port. (%d) ***", ret
);
217 CRSetCrashLogMessage(msg
);
218 mach_port_destroy(mach_task_self(), result
);
225 CF_INLINE
void __CFPortFree(__CFPort port
) {
226 mach_port_destroy(mach_task_self(), port
);
229 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
230 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) { HALT
; };
232 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
234 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
235 if (KERN_SUCCESS
!= ret
) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret
); }
236 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
239 CF_INLINE kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
240 if (MACH_PORT_NULL
== port
) {
243 return mach_port_insert_member(mach_task_self(), port
, portSet
);
246 CF_INLINE kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
247 if (MACH_PORT_NULL
== port
) {
250 return mach_port_extract_member(mach_task_self(), port
, portSet
);
253 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
255 mach_port_name_array_t array
;
256 mach_msg_type_number_t idx
, number
;
258 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
259 if (KERN_SUCCESS
== ret
) {
260 for (idx
= 0; idx
< number
; idx
++) {
261 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
263 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
265 mach_port_destroy(mach_task_self(), portSet
);
268 #elif DEPLOYMENT_TARGET_WINDOWS
270 typedef HANDLE __CFPort
;
271 #define CFPORT_NULL NULL
273 // A simple dynamic array of HANDLEs, which grows to a high-water mark
274 typedef struct ___CFPortSet
{
278 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
281 CF_INLINE __CFPort
__CFPortAllocate(void) {
282 return CreateEventA(NULL
, true, false, NULL
);
285 CF_INLINE
void __CFPortFree(__CFPort port
) {
289 static __CFPortSet
__CFPortSetAllocate(void) {
290 __CFPortSet result
= (__CFPortSet
)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
293 result
->handles
= (HANDLE
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
294 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
298 static void __CFPortSetFree(__CFPortSet portSet
) {
299 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
300 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
303 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
304 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
305 __CFSpinLock(&(portSet
->lock
));
306 __CFPort
*result
= portBuf
;
307 if (bufSize
< portSet
->used
)
308 result
= (__CFPort
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
309 if (portSet
->used
> 1) {
310 // rotate the ports to vaguely simulate round-robin behaviour
311 uint16_t lastPort
= portSet
->used
- 1;
312 HANDLE swapHandle
= portSet
->handles
[0];
313 memmove(portSet
->handles
, &portSet
->handles
[1], lastPort
* sizeof(HANDLE
));
314 portSet
->handles
[lastPort
] = swapHandle
;
316 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
317 *portsUsed
= portSet
->used
;
318 __CFSpinUnlock(&(portSet
->lock
));
322 static kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
326 __CFSpinLock(&(portSet
->lock
));
327 if (portSet
->used
>= portSet
->size
) {
329 portSet
->handles
= (HANDLE
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
331 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
) {
332 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
334 portSet
->handles
[portSet
->used
++] = port
;
335 __CFSpinUnlock(&(portSet
->lock
));
339 static kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
344 __CFSpinLock(&(portSet
->lock
));
345 for (i
= 0; i
< portSet
->used
; i
++) {
346 if (portSet
->handles
[i
] == port
) {
347 for (j
= i
+1; j
< portSet
->used
; j
++) {
348 portSet
->handles
[j
-1] = portSet
->handles
[j
];
351 __CFSpinUnlock(&(portSet
->lock
));
355 __CFSpinUnlock(&(portSet
->lock
));
361 #if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H)
362 #if defined(__BIG_ENDIAN__)
363 typedef struct UnsignedWide
{
367 #elif defined(__LITTLE_ENDIAN__)
368 typedef struct UnsignedWide
{
373 typedef UnsignedWide AbsoluteTime
;
376 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
377 extern mach_port_name_t
mk_timer_create(void);
378 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
379 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
380 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
382 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
385 a
.lo
= x
& (int64_t)0xFFFFFFFF;
389 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
390 kern_return_t result
;
391 mach_msg_header_t header
;
392 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
393 header
.msgh_size
= sizeof(mach_msg_header_t
);
394 header
.msgh_remote_port
= port
;
395 header
.msgh_local_port
= MACH_PORT_NULL
;
396 header
.msgh_id
= msg_id
;
397 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
398 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
401 #elif DEPLOYMENT_TARGET_WINDOWS
403 static HANDLE
mk_timer_create(void) {
404 return CreateWaitableTimer(NULL
, FALSE
, NULL
);
407 static kern_return_t
mk_timer_destroy(HANDLE name
) {
408 BOOL res
= CloseHandle(name
);
410 DWORD err
= GetLastError();
411 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to destroy timer: %d"), err
);
416 static kern_return_t
mk_timer_arm(HANDLE name
, LARGE_INTEGER expire_time
) {
417 BOOL res
= SetWaitableTimer(name
, &expire_time
, 0, NULL
, NULL
, FALSE
);
419 DWORD err
= GetLastError();
420 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to set timer: %d"), err
);
425 static kern_return_t
mk_timer_cancel(HANDLE name
, LARGE_INTEGER
*result_time
) {
426 BOOL res
= CancelWaitableTimer(name
);
428 DWORD err
= GetLastError();
429 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to cancel timer: %d"), err
);
434 // The name of this function is a lie on Windows. The return value matches the argument of the fake mk_timer functions above. Note that the Windows timers expect to be given "system time". We have to do some calculations to get the right value, which is a FILETIME-like value.
435 CF_INLINE LARGE_INTEGER
__CFUInt64ToAbsoluteTime(int64_t desiredFireTime
) {
436 LARGE_INTEGER result
;
437 // There is a race we know about here, (timer fire time calculated -> thread suspended -> timer armed == late timer fire), but we don't have a way to avoid it at this time, since the only way to specify an absolute value to the timer is to calculate the relative time first. Fixing that would probably require not using the TSR for timers on Windows.
438 int64_t timeDiff
= desiredFireTime
- (int64_t)mach_absolute_time();
442 CFTimeInterval amountOfTimeToWait
= __CFTSRToTimeInterval(timeDiff
);
443 // Result is in 100 ns (10**-7 sec) units to be consistent with a FILETIME.
444 // CFTimeInterval is in seconds.
445 result
.QuadPart
= -(amountOfTimeToWait
* 10000000);
452 /* unlock a run loop and modes before doing callouts/sleeping */
453 /* never try to take the run loop lock with a mode locked */
454 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
455 /* run loop mode structures should never be deallocated, even if they become empty */
457 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
458 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
459 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
460 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
461 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
463 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
465 struct __CFRunLoopMode
{
467 pthread_mutex_t _lock
; /* must have the run loop locked before locking this */
471 CFMutableSetRef _sources0
;
472 CFMutableSetRef _sources1
;
473 CFMutableArrayRef _observers
;
474 CFMutableArrayRef _timers
;
475 CFMutableDictionaryRef _portToV1SourceMap
;
476 __CFPortSet _portSet
;
477 CFIndex _observerMask
;
478 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
479 mach_port_t _timerPort
;
481 #if DEPLOYMENT_TARGET_WINDOWS
484 void (*_msgPump
)(void);
488 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
489 pthread_mutex_lock(&(rlm
->_lock
));
490 // CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm);
493 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
494 // CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm);
495 pthread_mutex_unlock(&(rlm
->_lock
));
498 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
499 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
500 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
501 return CFEqual(rlm1
->_name
, rlm2
->_name
);
504 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
505 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
506 return CFHash(rlm
->_name
);
509 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
510 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
511 CFMutableStringRef result
;
512 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
513 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
);
514 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p, "), rlm
->_portSet
);
515 CFStringAppendFormat(result
, NULL
, CFSTR("timer port = %p, "), rlm
->_timerPort
);
516 #if DEPLOYMENT_TARGET_WINDOWS
517 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p, "), rlm
->_msgQMask
);
519 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources0 = %@,\n\tsources1 = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm
->_sources0
, rlm
->_sources1
, rlm
->_observers
, rlm
->_timers
);
523 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
524 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
525 if (NULL
!= rlm
->_sources0
) CFRelease(rlm
->_sources0
);
526 if (NULL
!= rlm
->_sources1
) CFRelease(rlm
->_sources1
);
527 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
528 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
529 if (NULL
!= rlm
->_portToV1SourceMap
) CFRelease(rlm
->_portToV1SourceMap
);
530 CFRelease(rlm
->_name
);
531 __CFPortSetFree(rlm
->_portSet
);
532 if (MACH_PORT_NULL
!= rlm
->_timerPort
) mk_timer_destroy(rlm
->_timerPort
);
533 pthread_mutex_destroy(&rlm
->_lock
);
534 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x7C, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
));
538 struct _block_item
*_next
;
539 CFTypeRef _mode
; // CFString or CFSet
540 void (^_block
)(void);
543 typedef struct _per_run_data
{
547 uint32_t ignoreWakeUps
;
552 pthread_mutex_t _lock
; /* locked for accessing mode list */
553 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
555 volatile _per_run_data
*_perRunData
; // reset for runs of the run loop
558 CFMutableSetRef _commonModes
;
559 CFMutableSetRef _commonModeItems
;
560 CFRunLoopModeRef _currentMode
;
561 CFMutableSetRef _modes
;
562 struct _block_item
*_blocks_head
;
563 struct _block_item
*_blocks_tail
;
564 CFTypeRef _counterpart
;
567 /* Bit 0 of the base reserved bits is used for stopped state */
568 /* Bit 1 of the base reserved bits is used for sleeping state */
569 /* Bit 2 of the base reserved bits is used for deallocating state */
571 CF_INLINE
volatile _per_run_data
*__CFRunLoopPushPerRunData(CFRunLoopRef rl
) {
572 volatile _per_run_data
*previous
= rl
->_perRunData
;
573 rl
->_perRunData
= (volatile _per_run_data
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(_per_run_data
), 0);
574 rl
->_perRunData
->a
= 0x4346524C;
575 rl
->_perRunData
->b
= 0x4346524C; // 'CFRL'
576 rl
->_perRunData
->stopped
= 0x00000000;
577 rl
->_perRunData
->ignoreWakeUps
= 0x00000000;
581 CF_INLINE
void __CFRunLoopPopPerRunData(CFRunLoopRef rl
, volatile _per_run_data
*previous
) {
582 if (rl
->_perRunData
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (void *)rl
->_perRunData
);
583 rl
->_perRunData
= previous
;
586 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
587 return (rl
->_perRunData
->stopped
) ? true : false;
590 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
591 rl
->_perRunData
->stopped
= 0x53544F50; // 'STOP'
594 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
595 rl
->_perRunData
->stopped
= 0x0;
598 CF_INLINE Boolean
__CFRunLoopIsIgnoringWakeUps(CFRunLoopRef rl
) {
599 return (rl
->_perRunData
->ignoreWakeUps
) ? true : false;
602 CF_INLINE
void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl
) {
603 rl
->_perRunData
->ignoreWakeUps
= 0x57414B45; // 'WAKE'
606 CF_INLINE
void __CFRunLoopUnsetIgnoreWakeUps(CFRunLoopRef rl
) {
607 rl
->_perRunData
->ignoreWakeUps
= 0x0;
610 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
611 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
614 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
615 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
618 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
619 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
622 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
623 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
626 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
627 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
630 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
631 pthread_mutex_lock(&(((CFRunLoopRef
)rl
)->_lock
));
632 // CFLog(6, CFSTR("__CFRunLoopLock locked %p"), rl);
635 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
636 // CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl);
637 pthread_mutex_unlock(&(((CFRunLoopRef
)rl
)->_lock
));
640 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
641 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
642 CFMutableStringRef result
;
643 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
644 #if DEPLOYMENT_TARGET_WINDOWS
645 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{wakeup port = 0x%x, stopped = %s, ignoreWakeUps = %s, \ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), rl
->_wakeUpPort
, __CFRunLoopIsStopped(rl
) ? "true" : "false", __CFRunLoopIsIgnoringWakeUps(rl
) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
647 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{wakeup port = 0x%x, stopped = %s, ignoreWakeUps = %s, \ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), rl
->_wakeUpPort
, __CFRunLoopIsStopped(rl
) ? "true" : "false", __CFRunLoopIsIgnoringWakeUps(rl
) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
649 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
653 __private_extern__
void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
654 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
657 CF_INLINE
void __CFRunLoopLockInit(pthread_mutex_t
*lock
) {
658 pthread_mutexattr_t mattr
;
659 pthread_mutexattr_init(&mattr
);
660 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_RECURSIVE
);
661 int32_t mret
= pthread_mutex_init(lock
, &mattr
);
662 pthread_mutexattr_destroy(&mattr
);
667 /* call with rl locked */
668 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
670 CFRunLoopModeRef rlm
;
671 struct __CFRunLoopMode srlm
;
672 memset(&srlm
, 0, sizeof(srlm
));
673 srlm
._base
._cfisa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
674 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
675 srlm
._name
= modeName
;
676 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
678 __CFRunLoopModeLock(rlm
);
684 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
688 __CFRunLoopLockInit(&rlm
->_lock
);
689 rlm
->_name
= CFStringCreateCopy(kCFAllocatorSystemDefault
, modeName
);
690 rlm
->_stopped
= false;
691 rlm
->_portToV1SourceMap
= NULL
;
692 rlm
->_sources0
= NULL
;
693 rlm
->_sources1
= NULL
;
694 rlm
->_observers
= NULL
;
696 rlm
->_observerMask
= 0;
697 rlm
->_portSet
= __CFPortSetAllocate();
698 rlm
->_timerPort
= mk_timer_create();
699 kern_return_t ret
= __CFPortSetInsert(rlm
->_timerPort
, rlm
->_portSet
);
700 if (KERN_SUCCESS
!= ret
) {
702 snprintf(msg
, 256, "*** Unable to insert timer port into port set. (%d) ***", ret
);
703 CRSetCrashLogMessage(msg
);
706 ret
= __CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
);
707 if (KERN_SUCCESS
!= ret
) {
709 snprintf(msg
, 256, "*** Unable to insert wake up port into port set. (%d) ***", ret
);
710 CRSetCrashLogMessage(msg
);
713 #if DEPLOYMENT_TARGET_WINDOWS
715 rlm
->_msgPump
= NULL
;
717 CFSetAddValue(rl
->_modes
, rlm
);
719 __CFRunLoopModeLock(rlm
); /* return mode locked */
724 // expects rl and rlm locked
725 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopModeRef previousMode
) {
727 if (NULL
== rlm
) return true;
728 #if DEPLOYMENT_TARGET_WINDOWS
729 if (0 != rlm
->_msgQMask
) return false;
731 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
732 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) return false; // represents the libdispatch main queue
733 if (NULL
!= rlm
->_sources0
&& 0 < CFSetGetCount(rlm
->_sources0
)) return false;
734 if (NULL
!= rlm
->_sources1
&& 0 < CFSetGetCount(rlm
->_sources1
)) return false;
735 if (NULL
!= rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) return false;
736 struct _block_item
*item
= rl
->_blocks_head
;
738 struct _block_item
*curr
= item
;
740 Boolean doit
= false;
741 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
742 doit
= CFEqual(curr
->_mode
, rlm
->_name
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
744 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, rlm
->_name
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
746 if (doit
) return false;
751 #if DEPLOYMENT_TARGET_WINDOWS
753 uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
754 if (modeName
== kCFRunLoopCommonModes
) {
755 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
760 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
762 result
= rlm
->_msgQMask
;
763 __CFRunLoopModeUnlock(rlm
);
765 __CFRunLoopUnlock(rl
);
766 return (uint32_t)result
;
769 void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, uint32_t mask
, CFStringRef modeName
) {
770 if (modeName
== kCFRunLoopCommonModes
) {
771 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
775 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
776 rlm
->_msgQMask
= (DWORD
)mask
;
777 __CFRunLoopModeUnlock(rlm
);
778 __CFRunLoopUnlock(rl
);
781 uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl
) {
782 return rl
->_winthread
;
785 CFWindowsMessageQueueHandler
_CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
) {
786 if (modeName
== kCFRunLoopCommonModes
) {
787 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
790 if (rl
!= CFRunLoopGetCurrent()) {
791 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
794 void (*result
)(void) = NULL
;
796 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
798 result
= rlm
->_msgPump
;
799 __CFRunLoopModeUnlock(rlm
);
801 __CFRunLoopUnlock(rl
);
805 void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
, CFWindowsMessageQueueHandler func
) {
806 if (modeName
== kCFRunLoopCommonModes
) {
807 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
810 if (rl
!= CFRunLoopGetCurrent()) {
811 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
815 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
816 rlm
->_msgPump
= func
;
817 __CFRunLoopModeUnlock(rlm
);
818 __CFRunLoopUnlock(rl
);
823 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
825 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
826 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
829 CF_INLINE
void __CFSetValid(void *cf
) {
830 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
833 CF_INLINE
void __CFUnsetValid(void *cf
) {
834 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
837 struct __CFRunLoopSource
{
840 pthread_mutex_t _lock
;
841 CFIndex _order
; /* immutable */
842 CFMutableBagRef _runLoops
;
844 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
845 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
849 /* Bit 1 of the base reserved bits is used for signalled state */
851 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
852 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
855 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
856 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
859 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
860 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
863 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
864 pthread_mutex_lock(&(rls
->_lock
));
865 // CFLog(6, CFSTR("__CFRunLoopSourceLock locked %p"), rls);
868 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
869 // CFLog(6, CFSTR("__CFRunLoopSourceLock unlocking %p"), rls);
870 pthread_mutex_unlock(&(rls
->_lock
));
874 struct __CFRunLoopObserver
{
876 pthread_mutex_t _lock
;
877 CFRunLoopRef _runLoop
;
879 CFOptionFlags _activities
; /* immutable */
880 CFIndex _order
; /* immutable */
881 CFRunLoopObserverCallBack _callout
; /* immutable */
882 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
885 /* Bit 0 of the base reserved bits is used for firing state */
886 /* Bit 1 of the base reserved bits is used for repeats state */
888 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
889 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
892 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
893 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
896 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
897 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
900 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
901 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
904 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
905 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
908 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
909 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
912 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
913 pthread_mutex_lock(&(rlo
->_lock
));
914 // CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo);
917 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
918 // CFLog(6, CFSTR("__CFRunLoopObserverLock unlocking %p"), rlo);
919 pthread_mutex_unlock(&(rlo
->_lock
));
922 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
923 __CFRunLoopObserverLock(rlo
);
924 if (0 == rlo
->_rlCount
) {
928 __CFRunLoopObserverUnlock(rlo
);
931 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
932 __CFRunLoopObserverLock(rlo
);
934 if (0 == rlo
->_rlCount
) {
935 rlo
->_runLoop
= NULL
;
937 __CFRunLoopObserverUnlock(rlo
);
940 struct __CFRunLoopTimer
{
943 pthread_mutex_t _lock
;
944 CFRunLoopRef _runLoop
;
945 CFMutableSetRef _rlModes
;
946 CFAbsoluteTime _nextFireDate
;
947 CFTimeInterval _interval
; /* immutable */
948 int64_t _fireTSR
; /* TSR units */
949 CFIndex _order
; /* immutable */
950 CFRunLoopTimerCallBack _callout
; /* immutable */
951 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
954 /* Bit 0 of the base reserved bits is used for firing state */
955 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
957 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
958 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 0, 0);
961 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
962 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 1);
965 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
966 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 0);
969 CF_INLINE Boolean
__CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt
) {
970 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 2, 2);
973 CF_INLINE
void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt
) {
974 __CFBitfieldSetValue(rlt
->_bits
, 2, 2, 1);
977 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
978 pthread_mutex_lock(&(rlt
->_lock
));
979 // CFLog(6, CFSTR("__CFRunLoopTimerLock locked %p"), rlt);
982 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
983 // CFLog(6, CFSTR("__CFRunLoopTimerLock unlocking %p"), rlt);
984 pthread_mutex_unlock(&(rlt
->_lock
));
987 static CFSpinLock_t __CFRLTFireTSRLock
= CFSpinLockInit
;
989 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
990 __CFSpinLock(&__CFRLTFireTSRLock
);
993 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
994 __CFSpinUnlock(&__CFRLTFireTSRLock
);
997 #if DEPLOYMENT_TARGET_WINDOWS
999 struct _collectTimersContext
{
1000 CFMutableArrayRef results
;
1004 static void __CFRunLoopCollectTimers(const void *value
, void *ctx
) {
1005 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
1006 struct _collectTimersContext
*context
= (struct _collectTimersContext
*)ctx
;
1007 if (rlt
->_fireTSR
<= context
->cutoffTSR
) {
1008 if (NULL
== context
->results
)
1009 context
->results
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1010 CFArrayAppendValue(context
->results
, rlt
);
1014 // RunLoop and RunLoopMode must be locked
1015 static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, struct _collectTimersContext
*ctxt
) {
1016 __CFRunLoopTimerFireTSRLock();
1017 if (NULL
!= rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) {
1018 CFArrayApplyFunction(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), __CFRunLoopCollectTimers
, ctxt
);
1020 __CFRunLoopTimerFireTSRUnlock();
1023 // RunLoop and RunLoopMode must be locked
1024 static CFArrayRef
__CFRunLoopTimersToFire(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1025 struct _collectTimersContext ctxt
= {NULL
, mach_absolute_time()};
1026 __CFRunLoopTimersToFireRecursive(rl
, rlm
, &ctxt
);
1027 return ctxt
.results
;
1034 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
1035 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
1037 // call with rl and rlm locked
1038 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
1040 CFRunLoopSourceRef found
= rlm
->_portToV1SourceMap
? (CFRunLoopSourceRef
)CFDictionaryGetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)port
) : NULL
;
1044 // Remove backreferences the mode's sources have to the rl (context);
1045 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1046 // the source from the run loops it is in, but during deallocation of a
1047 // run loop, we already know that the sources are going to be punted
1048 // from it, so invalidation of sources does not need to remove from a
1049 // deallocating run loop.
1050 static void __CFRunLoopCleanseSources(const void *value
, void *context
) {
1051 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1052 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1054 const void **list
, *buffer
[256];
1055 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1057 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1058 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1059 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1060 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1061 for (idx
= 0; idx
< cnt
; idx
++) {
1062 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1063 __CFRunLoopSourceLock(rls
);
1064 if (NULL
!= rls
->_runLoops
) {
1065 CFBagRemoveValue(rls
->_runLoops
, rl
);
1067 __CFRunLoopSourceUnlock(rls
);
1069 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1072 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
1073 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1074 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1076 const void **list
, *buffer
[256];
1077 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1079 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1080 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1081 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1082 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1083 for (idx
= 0; idx
< cnt
; idx
++) {
1084 CFRetain(list
[idx
]);
1086 if (rlm
->_sources0
) CFSetRemoveAllValues(rlm
->_sources0
);
1087 if (rlm
->_sources1
) CFSetRemoveAllValues(rlm
->_sources1
);
1088 for (idx
= 0; idx
< cnt
; idx
++) {
1089 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1090 __CFRunLoopSourceLock(rls
);
1091 if (NULL
!= rls
->_runLoops
) {
1092 CFBagRemoveValue(rls
->_runLoops
, rl
);
1094 __CFRunLoopSourceUnlock(rls
);
1095 if (0 == rls
->_context
.version0
.version
) {
1096 if (NULL
!= rls
->_context
.version0
.cancel
) {
1097 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
1099 } else if (1 == rls
->_context
.version0
.version
) {
1100 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1101 if (CFPORT_NULL
!= port
) {
1102 __CFPortSetRemove(port
, rlm
->_portSet
);
1107 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1110 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
1111 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1112 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1114 const void **list
, *buffer
[256];
1115 if (NULL
== rlm
->_observers
) return;
1116 cnt
= CFArrayGetCount(rlm
->_observers
);
1117 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1118 CFArrayGetValues(rlm
->_observers
, CFRangeMake(0, cnt
), list
);
1119 for (idx
= 0; idx
< cnt
; idx
++) {
1120 CFRetain(list
[idx
]);
1122 CFArrayRemoveAllValues(rlm
->_observers
);
1123 for (idx
= 0; idx
< cnt
; idx
++) {
1124 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
1125 CFRelease(list
[idx
]);
1127 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1130 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
1131 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1133 const void **list
, *buffer
[256];
1134 if (NULL
== rlm
->_timers
) return;
1135 cnt
= CFArrayGetCount(rlm
->_timers
);
1136 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1137 CFArrayGetValues(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), list
);
1138 for (idx
= 0; idx
< cnt
; idx
++) {
1139 CFRetain(list
[idx
]);
1141 CFArrayRemoveAllValues(rlm
->_timers
);
1142 for (idx
= 0; idx
< cnt
; idx
++) {
1143 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1144 __CFRunLoopTimerLock(rlt
);
1145 // if the run loop is deallocating, and since a timer can only be in one
1146 // run loop, we're going to be removing the timer from all modes, so be
1147 // a little heavy-handed and direct
1148 CFSetRemoveAllValues(rlt
->_rlModes
);
1149 rlt
->_runLoop
= NULL
;
1150 __CFRunLoopTimerUnlock(rlt
);
1151 CFRelease(list
[idx
]);
1153 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1156 CF_EXPORT pthread_t _CFMainPThread
;
1157 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
);
1159 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
1160 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
1162 if (_CFRunLoopGet0b(_CFMainPThread
) == cf
) HALT
;
1164 /* We try to keep the run loop in a valid state as long as possible,
1165 since sources may have non-retained references to the run loop.
1166 Another reason is that we don't want to lock the run loop for
1167 callback reasons, if we can get away without that. We start by
1168 eliminating the sources, since they are the most likely to call
1169 back into the run loop during their "cancellation". Common mode
1170 items will be removed from the mode indirectly by the following
1172 __CFRunLoopSetDeallocating(rl
);
1173 if (NULL
!= rl
->_modes
) {
1174 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopCleanseSources
), rl
); // remove references to rl
1175 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
1176 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
1177 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
1179 __CFRunLoopLock(rl
);
1180 struct _block_item
*item
= rl
->_blocks_head
;
1182 struct _block_item
*curr
= item
;
1184 CFRelease(curr
->_mode
);
1185 Block_release(curr
->_block
);
1188 if (NULL
!= rl
->_commonModeItems
) {
1189 CFRelease(rl
->_commonModeItems
);
1191 if (NULL
!= rl
->_commonModes
) {
1192 CFRelease(rl
->_commonModes
);
1194 if (NULL
!= rl
->_modes
) {
1195 CFRelease(rl
->_modes
);
1197 __CFPortFree(rl
->_wakeUpPort
);
1198 rl
->_wakeUpPort
= CFPORT_NULL
;
1199 __CFRunLoopPopPerRunData(rl
, NULL
);
1200 __CFRunLoopUnlock(rl
);
1201 pthread_mutex_destroy(&rl
->_lock
);
1202 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x8C, sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
));
1205 static const CFRuntimeClass __CFRunLoopModeClass
= {
1210 __CFRunLoopModeDeallocate
,
1211 __CFRunLoopModeEqual
,
1212 __CFRunLoopModeHash
,
1214 __CFRunLoopModeCopyDescription
1217 static const CFRuntimeClass __CFRunLoopClass
= {
1222 __CFRunLoopDeallocate
,
1226 __CFRunLoopCopyDescription
1229 __private_extern__
void __CFFinalizeRunLoop(uintptr_t data
);
1231 static int64_t tenus
= 0LL;
1233 __private_extern__
void __CFRunLoopInitialize(void) {
1234 tenus
= __CFTimeIntervalToTSR(0.000010000);
1235 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
1236 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
1239 CFTypeID
CFRunLoopGetTypeID(void) {
1240 return __kCFRunLoopTypeID
;
1243 static CFRunLoopRef
__CFRunLoopCreate(pthread_t t
) {
1244 CFRunLoopRef loop
= NULL
;
1245 CFRunLoopModeRef rlm
;
1246 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
1247 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
1251 (void)__CFRunLoopPushPerRunData(loop
);
1252 __CFRunLoopLockInit(&loop
->_lock
);
1253 loop
->_wakeUpPort
= __CFPortAllocate();
1254 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
1255 __CFRunLoopSetIgnoreWakeUps(loop
);
1256 loop
->_commonModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1257 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
1258 loop
->_commonModeItems
= NULL
;
1259 loop
->_currentMode
= NULL
;
1260 loop
->_modes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1261 loop
->_blocks_head
= NULL
;
1262 loop
->_blocks_tail
= NULL
;
1263 loop
->_counterpart
= NULL
;
1265 #if DEPLOYMENT_TARGET_WINDOWS
1266 loop
->_winthread
= GetCurrentThreadId();
1268 loop
->_winthread
= 0;
1270 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
1271 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
1275 static CFMutableDictionaryRef __CFRunLoops
= NULL
;
1276 static CFSpinLock_t loopsLock
= CFSpinLockInit
;
1278 // should only be called by Foundation
1279 // t==0 is a synonym for "main thread" that always works
1280 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0(pthread_t t
) {
1281 if (pthread_equal(t
, kNilPthreadT
)) {
1284 __CFSpinLock(&loopsLock
);
1285 if (!__CFRunLoops
) {
1286 __CFSpinUnlock(&loopsLock
);
1287 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1288 CFRunLoopRef mainLoop
= __CFRunLoopCreate(_CFMainPThread
);
1289 CFDictionarySetValue(dict
, pthreadPointer(_CFMainPThread
), mainLoop
);
1290 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, dict
, (void * volatile *)&__CFRunLoops
)) {
1293 CFRelease(mainLoop
);
1294 __CFSpinLock(&loopsLock
);
1296 CFRunLoopRef loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1297 __CFSpinUnlock(&loopsLock
);
1299 CFRunLoopRef newLoop
= __CFRunLoopCreate(t
);
1300 __CFSpinLock(&loopsLock
);
1301 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1303 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(t
), newLoop
);
1306 // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
1307 __CFSpinUnlock(&loopsLock
);
1310 if (pthread_equal(t
, pthread_self())) {
1311 _CFSetTSD(__CFTSDKeyRunLoop
, (void *)loop
, NULL
);
1312 if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr
)) {
1313 _CFSetTSD(__CFTSDKeyRunLoopCntr
, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS
-1), (void (*)(void *))__CFFinalizeRunLoop
);
1319 // should only be called by Foundation
1320 CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
) {
1321 if (pthread_equal(t
, kNilPthreadT
)) {
1324 __CFSpinLock(&loopsLock
);
1325 CFRunLoopRef loop
= NULL
;
1327 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1329 __CFSpinUnlock(&loopsLock
);
1333 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
);
1335 // Called for each thread as it exits
1336 __private_extern__
void __CFFinalizeRunLoop(uintptr_t data
) {
1337 CFRunLoopRef rl
= NULL
;
1339 __CFSpinLock(&loopsLock
);
1341 rl
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1342 if (rl
) CFRetain(rl
);
1343 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1345 __CFSpinUnlock(&loopsLock
);
1347 _CFSetTSD(__CFTSDKeyRunLoopCntr
, (void *)(data
- 1), (void (*)(void *))__CFFinalizeRunLoop
);
1349 if (rl
&& CFRunLoopGetMain() != rl
) { // protect against cooperative threads
1350 if (NULL
!= rl
->_counterpart
) {
1351 CFRelease(rl
->_counterpart
);
1352 rl
->_counterpart
= NULL
;
1354 // purge all sources before deallocation
1355 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
1356 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
1357 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
1358 __CFRunLoopRemoveAllSources(rl
, modeName
);
1360 __CFRunLoopRemoveAllSources(rl
, kCFRunLoopCommonModes
);
1363 if (rl
) CFRelease(rl
);
1366 pthread_t
_CFRunLoopGet1(CFRunLoopRef rl
) {
1367 return rl
->_pthread
;
1370 // should only be called by Foundation
1371 CF_EXPORT CFTypeRef
_CFRunLoopGet2(CFRunLoopRef rl
) {
1372 CFTypeRef ret
= NULL
;
1373 __CFSpinLock(&loopsLock
);
1374 ret
= rl
->_counterpart
;
1375 __CFSpinUnlock(&loopsLock
);
1379 // should only be called by Foundation
1380 CF_EXPORT CFTypeRef
_CFRunLoopGet2b(CFRunLoopRef rl
) {
1381 return rl
->_counterpart
;
1384 #if DEPLOYMENT_TARGET_MACOSX
1385 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1386 if (pthread_main_np()) return;
1387 CFRunLoopRef currentLoop
= CFRunLoopGetCurrent();
1388 if (rl
!= currentLoop
) {
1389 CFRetain(currentLoop
); // avoid a deallocation of the currentLoop inside the lock
1390 __CFSpinLock(&loopsLock
);
1392 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(pthread_self()), rl
);
1394 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1396 __CFSpinUnlock(&loopsLock
);
1397 CFRelease(currentLoop
);
1398 _CFSetTSD(__CFTSDKeyRunLoop
, NULL
, NULL
);
1399 _CFSetTSD(__CFTSDKeyRunLoopCntr
, 0, (void (*)(void *))__CFFinalizeRunLoop
);
1404 CFRunLoopRef
CFRunLoopGetMain(void) {
1406 static CFRunLoopRef __main
= NULL
; // no retain needed
1407 if (!__main
) __main
= _CFRunLoopGet0(_CFMainPThread
); // no CAS needed
1411 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1413 CFRunLoopRef rl
= (CFRunLoopRef
)_CFGetTSD(__CFTSDKeyRunLoop
);
1415 return _CFRunLoopGet0(pthread_self());
1418 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1420 CFStringRef result
= NULL
;
1421 __CFRunLoopLock(rl
);
1422 if (NULL
!= rl
->_currentMode
) {
1423 result
= (CFStringRef
)CFRetain(rl
->_currentMode
->_name
);
1425 __CFRunLoopUnlock(rl
);
1429 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1430 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1431 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1432 CFArrayAppendValue(array
, rlm
->_name
);
1435 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1437 CFMutableArrayRef array
;
1438 __CFRunLoopLock(rl
);
1439 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1440 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1441 __CFRunLoopUnlock(rl
);
1445 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1446 CFTypeRef item
= (CFTypeRef
)value
;
1447 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1448 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1449 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1450 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1451 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1452 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1453 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1454 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1458 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1459 CFStringRef modeName
= (CFStringRef
)value
;
1460 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1461 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1462 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1463 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1464 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1465 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1466 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1467 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1471 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1472 CFStringRef modeName
= (CFStringRef
)value
;
1473 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1474 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1475 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1476 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1477 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1478 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1479 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1480 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1484 CF_EXPORT Boolean
_CFRunLoop01(CFRunLoopRef rl
, CFStringRef modeName
) {
1485 __CFRunLoopLock(rl
);
1486 Boolean present
= CFSetContainsValue(rl
->_commonModes
, modeName
);
1487 __CFRunLoopUnlock(rl
);
1491 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1493 if (__CFRunLoopIsDeallocating(rl
)) return;
1494 __CFRunLoopLock(rl
);
1495 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1496 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1497 CFSetAddValue(rl
->_commonModes
, modeName
);
1499 CFTypeRef context
[2] = {rl
, modeName
};
1500 /* add all common-modes items to new mode */
1501 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1506 __CFRunLoopUnlock(rl
);
1510 static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline
));
1511 static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func
, CFRunLoopObserverRef observer
, CFRunLoopActivity activity
, void *info
) {
1513 func(observer
, activity
, info
);
1515 getpid(); // thwart tail-call optimization
1518 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline
));
1519 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func
, CFRunLoopTimerRef timer
, void *info
) {
1523 getpid(); // thwart tail-call optimization
1526 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline
));
1527 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block
)(void)) {
1531 getpid(); // thwart tail-call optimization
1534 static Boolean
__CFRunLoopDoBlocks(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { // Call with rl and rlm locked
1535 if (!rl
->_blocks_head
) return false;
1536 if (!rlm
|| !rlm
->_name
) return false;
1537 Boolean did
= false;
1538 struct _block_item
*head
= rl
->_blocks_head
;
1539 struct _block_item
*tail
= rl
->_blocks_tail
;
1540 rl
->_blocks_head
= NULL
;
1541 rl
->_blocks_tail
= NULL
;
1542 CFSetRef commonModes
= rl
->_commonModes
;
1543 CFStringRef curMode
= rlm
->_name
;
1544 __CFRunLoopModeUnlock(rlm
);
1545 __CFRunLoopUnlock(rl
);
1546 struct _block_item
*prev
= NULL
;
1547 struct _block_item
*item
= head
;
1549 struct _block_item
*curr
= item
;
1551 Boolean doit
= false;
1552 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
1553 doit
= CFEqual(curr
->_mode
, curMode
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1555 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, curMode
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1557 if (!doit
) prev
= curr
;
1559 if (prev
) prev
->_next
= item
;
1560 if (curr
== head
) head
= item
;
1561 if (curr
== tail
) tail
= prev
;
1562 void (^block
)(void) = curr
->_block
;
1563 CFRelease(curr
->_mode
);
1566 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block
);
1569 Block_release(block
); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1572 __CFRunLoopLock(rl
);
1573 __CFRunLoopModeLock(rlm
);
1575 tail
->_next
= rl
->_blocks_head
;
1576 rl
->_blocks_head
= head
;
1577 if (!rl
->_blocks_tail
) rl
->_blocks_tail
= tail
;
1582 /* rl is locked, rlm is locked on entrance and exit */
1583 static void __CFRunLoopDoObservers() __attribute__((noinline
));
1584 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1587 CFIndex cnt
= rlm
->_observers
? CFArrayGetCount(rlm
->_observers
) : 0;
1588 if (cnt
< 1) return;
1590 /* Fire the observers */
1591 STACK_BUFFER_DECL(CFRunLoopObserverRef
, buffer
, (cnt
<= 1024) ? cnt
: 1);
1592 CFRunLoopObserverRef
*collectedObservers
= (cnt
<= 1024) ? buffer
: (CFRunLoopObserverRef
*)malloc(cnt
* sizeof(CFRunLoopObserverRef
));
1593 CFIndex obs_cnt
= 0;
1594 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1595 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(rlm
->_observers
, idx
);
1596 if (0 != (rlo
->_activities
& activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1597 collectedObservers
[obs_cnt
++] = (CFRunLoopObserverRef
)CFRetain(rlo
);
1600 __CFRunLoopModeUnlock(rlm
);
1601 __CFRunLoopUnlock(rl
);
1602 for (CFIndex idx
= 0; idx
< obs_cnt
; idx
++) {
1603 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1604 __CFRunLoopObserverLock(rlo
);
1605 if (__CFIsValid(rlo
)) {
1606 Boolean doInvalidate
= !__CFRunLoopObserverRepeats(rlo
);
1607 __CFRunLoopObserverSetFiring(rlo
);
1608 __CFRunLoopObserverUnlock(rlo
);
1609 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo
->_callout
, rlo
, activity
, rlo
->_context
.info
);
1611 CFRunLoopObserverInvalidate(rlo
);
1613 __CFRunLoopObserverUnsetFiring(rlo
);
1615 __CFRunLoopObserverUnlock(rlo
);
1619 __CFRunLoopLock(rl
);
1620 __CFRunLoopModeLock(rlm
);
1622 if (collectedObservers
!= buffer
) free(collectedObservers
);
1625 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1626 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1627 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1628 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1629 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1630 return kCFCompareEqualTo
;
1633 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1634 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1635 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1636 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1637 if (NULL
== *sources
) {
1638 *sources
= CFRetain(rls
);
1639 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1640 CFTypeRef oldrls
= *sources
;
1641 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1642 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1643 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1646 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1651 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline
));
1652 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform
)(void *), void *info
) {
1656 getpid(); // thwart tail-call optimization
1659 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline
));
1660 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(
1661 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1662 void *(*perform
)(void *msg
, CFIndex size
, CFAllocatorRef allocator
, void *info
),
1663 mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
,
1665 void (*perform
)(void *),
1669 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1670 *reply
= perform(msg
, size
, kCFAllocatorSystemDefault
, info
);
1675 getpid(); // thwart tail-call optimization
1678 /* rl is locked, rlm is locked on entrance and exit */
1679 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) __attribute__((noinline
));
1680 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1682 CFTypeRef sources
= NULL
;
1683 Boolean sourceHandled
= false;
1685 /* Fire the version 0 sources */
1686 if (NULL
!= rlm
->_sources0
&& 0 < CFSetGetCount(rlm
->_sources0
)) {
1687 CFSetApplyFunction(rlm
->_sources0
, (__CFRunLoopCollectSources0
), &sources
);
1689 if (NULL
!= sources
) {
1690 __CFRunLoopModeUnlock(rlm
);
1691 __CFRunLoopUnlock(rl
);
1692 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1693 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1694 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1695 __CFRunLoopSourceLock(rls
);
1696 if (__CFRunLoopSourceIsSignaled(rls
)) {
1697 __CFRunLoopSourceUnsetSignaled(rls
);
1698 if (__CFIsValid(rls
)) {
1699 __CFRunLoopSourceUnlock(rls
);
1700 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls
->_context
.version0
.perform
, rls
->_context
.version0
.info
);
1702 sourceHandled
= true;
1704 __CFRunLoopSourceUnlock(rls
);
1707 __CFRunLoopSourceUnlock(rls
);
1710 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)sources
);
1711 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1712 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1713 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex((CFArrayRef
)sources
, idx
);
1714 __CFRunLoopSourceLock(rls
);
1715 if (__CFRunLoopSourceIsSignaled(rls
)) {
1716 __CFRunLoopSourceUnsetSignaled(rls
);
1717 if (__CFIsValid(rls
)) {
1718 __CFRunLoopSourceUnlock(rls
);
1719 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls
->_context
.version0
.perform
, rls
->_context
.version0
.info
);
1721 sourceHandled
= true;
1723 __CFRunLoopSourceUnlock(rls
);
1726 __CFRunLoopSourceUnlock(rls
);
1728 if (stopAfterHandle
&& sourceHandled
) {
1734 __CFRunLoopLock(rl
);
1735 __CFRunLoopModeLock(rlm
);
1737 return sourceHandled
;
1740 // msg, size and reply are unused on Windows
1741 static Boolean
__CFRunLoopDoSource1() __attribute__((noinline
));
1742 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1743 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1744 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1746 ) { /* DOES CALLOUT */
1748 Boolean sourceHandled
= false;
1750 /* Fire a version 1 source */
1752 __CFRunLoopModeUnlock(rlm
);
1753 __CFRunLoopUnlock(rl
);
1754 __CFRunLoopSourceLock(rls
);
1755 if (__CFIsValid(rls
)) {
1756 __CFRunLoopSourceUnsetSignaled(rls
);
1757 __CFRunLoopSourceUnlock(rls
);
1758 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(rls
->_context
.version1
.perform
,
1759 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1762 rls
->_context
.version1
.info
);
1764 sourceHandled
= true;
1766 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1767 __CFRunLoopSourceUnlock(rls
);
1770 __CFRunLoopLock(rl
);
1771 __CFRunLoopModeLock(rlm
);
1772 return sourceHandled
;
1775 static CFIndex
__CFRunLoopInsertionIndexInTimerArray(CFArrayRef array
, CFRunLoopTimerRef rlt
) __attribute__((noinline
));
1776 static CFIndex
__CFRunLoopInsertionIndexInTimerArray(CFArrayRef array
, CFRunLoopTimerRef rlt
) {
1777 CFIndex cnt
= CFArrayGetCount(array
);
1782 CFRunLoopTimerRef item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, cnt
- 1);
1783 if (item
->_fireTSR
<= rlt
->_fireTSR
) {
1786 item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, 0);
1787 if (rlt
->_fireTSR
< item
->_fireTSR
) {
1792 CFIndex add
= (1 << flsl(cnt
)) * 2;
1794 Boolean lastTestLEQ
;
1797 lastTestLEQ
= false;
1798 CFIndex testIdx
= idx
+ add
;
1799 if (testIdx
< cnt
) {
1800 CFRunLoopTimerRef item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, testIdx
);
1801 if (item
->_fireTSR
<= rlt
->_fireTSR
) {
1808 return lastTestLEQ
? idx
+ 1 : idx
;
1811 static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm
) {
1812 CFRunLoopTimerRef nextTimer
= NULL
;
1813 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(rlm
->_timers
); idx
< cnt
; idx
++) {
1814 CFRunLoopTimerRef t
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, idx
);
1815 if (!__CFRunLoopTimerIsFiring(t
)) {
1821 int64_t fireTSR
= nextTimer
->_fireTSR
;
1822 fireTSR
= (fireTSR
/ tenus
+ 1) * tenus
;
1823 mk_timer_arm(rlm
->_timerPort
, __CFUInt64ToAbsoluteTime(fireTSR
));
1827 // call with rlm and its run loop locked, and the TSRLock locked; rlt not locked; returns with same state
1828 static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
, Boolean isInArray
) __attribute__((noinline
));
1829 static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
, Boolean isInArray
) {
1830 if (!rlt
|| !rlm
->_timers
) return;
1831 Boolean found
= false;
1833 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), rlt
);
1834 if (kCFNotFound
!= idx
) {
1836 CFArrayRemoveValueAtIndex(rlm
->_timers
, idx
);
1840 if (!found
&& isInArray
) return;
1841 CFIndex newIdx
= __CFRunLoopInsertionIndexInTimerArray(rlm
->_timers
, rlt
);
1842 CFArrayInsertValueAtIndex(rlm
->_timers
, newIdx
, rlt
);
1843 __CFArmNextTimerInMode(rlm
);
1844 if (isInArray
) CFRelease(rlt
);
1847 // mode and rl are locked on entry and exit
1848 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1849 Boolean timerHandled
= false;
1850 int64_t oldFireTSR
= 0;
1854 __CFRunLoopTimerLock(rlt
);
1856 if (__CFIsValid(rlt
) && rlt
->_fireTSR
<= (int64_t)mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt
) && rlt
->_runLoop
== rl
) {
1857 void *context_info
= NULL
;
1858 void (*context_release
)(const void *) = NULL
;
1859 if (rlt
->_context
.retain
) {
1860 context_info
= (void *)rlt
->_context
.retain(rlt
->_context
.info
);
1861 context_release
= rlt
->_context
.release
;
1863 context_info
= rlt
->_context
.info
;
1865 Boolean doInvalidate
= (0.0 == rlt
->_interval
);
1866 __CFRunLoopTimerSetFiring(rlt
);
1867 __CFRunLoopTimerUnlock(rlt
);
1868 __CFRunLoopTimerFireTSRLock();
1869 oldFireTSR
= rlt
->_fireTSR
;
1870 __CFRunLoopTimerFireTSRUnlock();
1872 __CFArmNextTimerInMode(rlm
);
1874 __CFRunLoopModeUnlock(rlm
);
1875 __CFRunLoopUnlock(rl
);
1876 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt
->_callout
, rlt
, context_info
);
1879 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1881 if (context_release
) {
1882 context_release(context_info
);
1884 __CFRunLoopLock(rl
);
1885 __CFRunLoopModeLock(rlm
);
1886 __CFRunLoopTimerLock(rlt
);
1887 timerHandled
= true;
1888 __CFRunLoopTimerUnsetFiring(rlt
);
1890 if (__CFIsValid(rlt
) && timerHandled
) {
1891 /* This is just a little bit tricky: we want to support calling
1892 * CFRunLoopTimerSetNextFireDate() from within the callout and
1893 * honor that new time here if it is a later date, otherwise
1894 * it is completely ignored. */
1895 if (oldFireTSR
< rlt
->_fireTSR
) {
1896 /* Next fire TSR was set, and set to a date after the previous
1897 * fire date, so we honor it. */
1898 __CFRunLoopTimerUnlock(rlt
);
1899 // The timer was adjusted and repositioned, during the
1900 // callout, but if it was still the min timer, it was
1901 // skipped because it was firing. Need to redo the
1902 // min timer calculation in case rlt should now be that
1903 // timer instead of whatever was chosen.
1904 __CFArmNextTimerInMode(rlm
);
1906 int64_t nextFireTSR
= 0LL;
1907 int64_t intervalTSR
= 0LL;
1908 if (rlt
->_interval
<= 0.0) {
1909 } else if (TIMER_INTERVAL_LIMIT
< rlt
->_interval
) {
1910 intervalTSR
= __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
1912 intervalTSR
= __CFTimeIntervalToTSR(rlt
->_interval
);
1914 if (LLONG_MAX
- intervalTSR
<= oldFireTSR
) {
1915 nextFireTSR
= LLONG_MAX
;
1917 int64_t currentTSR
= (int64_t)mach_absolute_time();
1918 nextFireTSR
= oldFireTSR
;
1919 while (nextFireTSR
<= currentTSR
) {
1920 nextFireTSR
+= intervalTSR
;
1923 CFRunLoopRef rlt_rl
= rlt
->_runLoop
;
1926 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
1927 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
1928 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
1929 // To avoid A->B, B->A lock ordering issues when coming up
1930 // towards the run loop from a source, the timer has to be
1931 // unlocked, which means we have to protect from object
1932 // invalidation, although that's somewhat expensive.
1933 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1934 CFRetain(modes
[idx
]);
1936 __CFRunLoopTimerUnlock(rlt
);
1937 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1938 CFStringRef name
= (CFStringRef
)modes
[idx
];
1939 modes
[idx
] = (CFTypeRef
)__CFRunLoopFindMode(rlt_rl
, name
, false);
1942 __CFRunLoopTimerFireTSRLock();
1943 rlt
->_fireTSR
= nextFireTSR
;
1944 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTSRToTimeInterval(nextFireTSR
- (int64_t)mach_absolute_time());
1945 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1946 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
1948 __CFRepositionTimerInMode(rlm
, rlt
, true);
1951 __CFRunLoopTimerFireTSRUnlock();
1952 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1953 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
1957 __CFRunLoopTimerUnlock(rlt
);
1958 __CFRunLoopTimerFireTSRLock();
1959 rlt
->_fireTSR
= nextFireTSR
;
1960 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTSRToTimeInterval(nextFireTSR
- (int64_t)mach_absolute_time());
1961 __CFRunLoopTimerFireTSRUnlock();
1965 __CFRunLoopTimerUnlock(rlt
);
1968 return timerHandled
;
1971 // rl and rlm are locked on entry and exit
1972 static Boolean
__CFRunLoopDoTimers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, int64_t limitTSR
) { /* DOES CALLOUT */
1973 Boolean timerHandled
= false;
1974 CFMutableArrayRef timers
= NULL
;
1975 for (CFIndex idx
= 0, cnt
= rlm
->_timers
? CFArrayGetCount(rlm
->_timers
) : 0; idx
< cnt
; idx
++) {
1976 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, idx
);
1977 if (__CFIsValid(rlt
) && rlt
->_fireTSR
<= limitTSR
&& !__CFRunLoopTimerIsFiring(rlt
)) {
1978 if (!timers
) timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1979 CFArrayAppendValue(timers
, rlt
);
1982 for (CFIndex idx
= 0, cnt
= timers
? CFArrayGetCount(timers
) : 0; idx
< cnt
; idx
++) {
1983 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timers
, idx
);
1984 Boolean did
= __CFRunLoopDoTimer(rl
, rlm
, rlt
);
1985 timerHandled
= timerHandled
|| did
;
1987 if (timers
) CFRelease(timers
);
1988 return timerHandled
;
1992 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1994 CFRunLoopModeRef rlm
;
1995 Boolean result
= false;
1996 __CFRunLoopLock(rl
);
1997 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1998 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
, NULL
)) {
2001 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2002 __CFRunLoopUnlock(rl
);
2006 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) __attribute__((noinline
));
2008 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2010 #define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0)
2012 static Boolean
__CFRunLoopServiceMachPort(mach_port_name_t port
, mach_msg_header_t
**buffer
, size_t buffer_size
, mach_msg_timeout_t timeout
) {
2013 Boolean originalBuffer
= true;
2014 for (;;) { /* In that sleep of death what nightmares may come ... */
2015 mach_msg_header_t
*msg
= (mach_msg_header_t
*)*buffer
;
2017 msg
->msgh_local_port
= port
;
2018 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2019 msg
->msgh_size
= buffer_size
;
2021 kern_return_t ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|((TIMEOUT_INFINITY
!= timeout
) ? 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
, port
, timeout
, MACH_PORT_NULL
);
2022 if (MACH_MSG_SUCCESS
== ret
) return true;
2023 if (MACH_RCV_TIMED_OUT
== ret
) {
2024 if (!originalBuffer
) free(msg
);
2028 if (MACH_RCV_TOO_LARGE
!= ret
) break;
2029 buffer_size
= round_msg(msg
->msgh_size
+ MAX_TRAILER_SIZE
);
2030 if (originalBuffer
) *buffer
= NULL
;
2031 originalBuffer
= false;
2032 *buffer
= realloc(*buffer
, buffer_size
);
2038 #elif DEPLOYMENT_TARGET_WINDOWS
2040 #define TIMEOUT_INFINITY INFINITE
2042 // pass in either a portSet or onePort
2043 static Boolean
__CFRunLoopWaitForMultipleObjects(__CFPortSet portSet
, HANDLE
*onePort
, DWORD timeout
, DWORD mask
, HANDLE
*livePort
, Boolean
*msgReceived
) {
2044 DWORD waitResult
= WAIT_TIMEOUT
;
2045 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
2046 HANDLE
*handles
= NULL
;
2047 uint32_t handleCount
= 0;
2048 Boolean freeHandles
= false;
2049 Boolean result
= false;
2052 // copy out the handles to be safe from other threads at work
2053 handles
= __CFPortSetGetPorts(portSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
2054 freeHandles
= (handles
!= handleBuf
);
2058 freeHandles
= FALSE
;
2061 // The run loop mode and loop are already in proper unlocked state from caller
2062 waitResult
= MsgWaitForMultipleObjectsEx(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, timeout
, mask
, MWMO_INPUTAVAILABLE
);
2064 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
2066 if (waitResult
== WAIT_TIMEOUT
) {
2067 // do nothing, just return to caller
2069 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
2070 // a handle was signaled
2071 if (livePort
) *livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
2073 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
2074 // windows message received
2075 if (msgReceived
) *msgReceived
= true;
2077 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
2078 // an "abandoned mutex object"
2079 if (livePort
) *livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
2082 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
2087 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
2095 struct __timeout_context
{
2096 dispatch_source_t ds
;
2101 static void __CFRunLoopTimeoutCancel(void *arg
) {
2102 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2103 CFRelease(context
->rl
);
2104 dispatch_release(context
->ds
);
2108 static void __CFRunLoopTimeout(void *arg
) {
2109 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2110 context
->termTSR
= 0LL;
2111 CFRunLoopWakeUp(context
->rl
);
2112 // The interval is DISPATCH_TIME_FOREVER, so this won't fire again
2115 /* rl, rlm are locked on entrance and exit */
2116 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) {
2117 int64_t startTSR
= (int64_t)mach_absolute_time();
2119 if (__CFRunLoopIsStopped(rl
)) {
2120 __CFRunLoopUnsetStopped(rl
);
2121 return kCFRunLoopRunStopped
;
2122 } else if (rlm
->_stopped
) {
2123 rlm
->_stopped
= false;
2124 return kCFRunLoopRunStopped
;
2127 mach_port_name_t dispatchPort
= MACH_PORT_NULL
;
2128 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
2129 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) dispatchPort
= _dispatch_get_main_queue_port_4CF();
2131 dispatch_source_t timeout_timer
= NULL
;
2132 struct __timeout_context
*timeout_context
= (struct __timeout_context
*)malloc(sizeof(*timeout_context
));
2133 if (seconds
<= 0.0) { // instant timeout
2135 timeout_context
->termTSR
= 0LL;
2136 } else if (seconds
<= TIMER_INTERVAL_LIMIT
) {
2137 dispatch_queue_t queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH
, DISPATCH_QUEUE_OVERCOMMIT
);
2138 timeout_timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, queue
);
2139 dispatch_retain(timeout_timer
);
2140 timeout_context
->ds
= timeout_timer
;
2141 timeout_context
->rl
= (CFRunLoopRef
)CFRetain(rl
);
2142 timeout_context
->termTSR
= startTSR
+ __CFTimeIntervalToTSR(seconds
);
2143 dispatch_set_context(timeout_timer
, timeout_context
); // source gets ownership of context
2144 dispatch_source_set_event_handler_f(timeout_timer
, __CFRunLoopTimeout
);
2145 dispatch_source_set_cancel_handler_f(timeout_timer
, __CFRunLoopTimeoutCancel
);
2146 uint64_t nanos
= (uint64_t)(seconds
* 1000 * 1000 + 1) * 1000;
2147 dispatch_source_set_timer(timeout_timer
, dispatch_time(DISPATCH_TIME_NOW
, nanos
), DISPATCH_TIME_FOREVER
, 0);
2148 dispatch_resume(timeout_timer
);
2149 } else { // infinite timeout
2150 seconds
= 9999999999.0;
2151 timeout_context
->termTSR
= INT64_MAX
;
2154 Boolean didDispatchPortLastTime
= true;
2157 uint8_t msg_buffer
[3 * 1024];
2158 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2159 mach_msg_header_t
*msg
= NULL
;
2160 #elif DEPLOYMENT_TARGET_WINDOWS
2161 HANDLE livePort
= NULL
;
2162 Boolean windowsMessageReceived
= false;
2164 __CFPortSet waitSet
= rlm
->_portSet
;
2166 __CFRunLoopUnsetIgnoreWakeUps(rl
);
2168 if (rlm
->_observerMask
& kCFRunLoopBeforeTimers
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
2169 if (rlm
->_observerMask
& kCFRunLoopBeforeSources
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
2171 __CFRunLoopDoBlocks(rl
, rlm
);
2173 Boolean sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
2174 if (sourceHandledThisLoop
) {
2175 __CFRunLoopDoBlocks(rl
, rlm
);
2178 Boolean poll
= sourceHandledThisLoop
|| (0LL == timeout_context
->termTSR
);
2180 if (MACH_PORT_NULL
!= dispatchPort
&& !didDispatchPortLastTime
) {
2181 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2182 msg
= (mach_msg_header_t
*)msg_buffer
;
2183 if (__CFRunLoopServiceMachPort(dispatchPort
, &msg
, sizeof(msg_buffer
), 0)) {
2186 #elif DEPLOYMENT_TARGET_WINDOWS
2187 if (__CFRunLoopWaitForMultipleObjects(NULL
, &dispatchPort
, 0, 0, &livePort
, NULL
)) {
2193 didDispatchPortLastTime
= false;
2195 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopBeforeWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
2196 __CFRunLoopSetSleeping(rl
);
2197 // do not do any user callouts after this point (after notifying of sleeping)
2199 // Must push the local-to-this-activation ports in on every loop
2200 // iteration, as this mode could be run re-entrantly and we don't
2201 // want these ports to get serviced.
2203 __CFPortSetInsert(dispatchPort
, waitSet
);
2205 __CFRunLoopModeUnlock(rlm
);
2206 __CFRunLoopUnlock(rl
);
2208 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2209 if (kCFUseCollectableAllocator
) {
2210 objc_clear_stack(0);
2211 memset(msg_buffer
, 0, sizeof(msg_buffer
));
2213 msg
= (mach_msg_header_t
*)msg_buffer
;
2214 __CFRunLoopServiceMachPort(waitSet
, &msg
, sizeof(msg_buffer
), poll
? 0 : TIMEOUT_INFINITY
);
2215 #elif DEPLOYMENT_TARGET_WINDOWS
2216 // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages.
2217 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, poll
? 0 : TIMEOUT_INFINITY
, rlm
->_msgQMask
, &livePort
, &windowsMessageReceived
);
2220 __CFRunLoopLock(rl
);
2221 __CFRunLoopModeLock(rlm
);
2223 // Must remove the local-to-this-activation ports in on every loop
2224 // iteration, as this mode could be run re-entrantly and we don't
2225 // want these ports to get serviced. Also, we don't want them left
2226 // in there if this function returns.
2228 __CFPortSetRemove(dispatchPort
, waitSet
);
2230 __CFRunLoopSetIgnoreWakeUps(rl
);
2232 // user callouts now OK again
2233 __CFRunLoopUnsetSleeping(rl
);
2234 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopAfterWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
2237 __CFRunLoopSetIgnoreWakeUps(rl
);
2239 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2240 mach_port_t livePort
= msg
? msg
->msgh_local_port
: MACH_PORT_NULL
;
2242 #if DEPLOYMENT_TARGET_WINDOWS
2243 if (windowsMessageReceived
) {
2244 // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after
2245 __CFRunLoopModeUnlock(rlm
);
2246 __CFRunLoopUnlock(rl
);
2248 if (rlm
->_msgPump
) {
2252 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
2253 TranslateMessage(&msg
);
2254 DispatchMessage(&msg
);
2258 __CFRunLoopLock(rl
);
2259 __CFRunLoopModeLock(rlm
);
2260 sourceHandledThisLoop
= true;
2262 // To prevent starvation of sources other than the message queue, we check again to see if any other sources need to be serviced
2263 // Use 0 for the mask so windows messages are ignored this time. Also use 0 for the timeout, because we're just checking to see if the things are signalled right now -- we will wait on them again later.
2264 // NOTE: Ignore the dispatch source (it's not in the wait set anymore) and also don't run the observers here since we are polling.
2265 __CFRunLoopSetSleeping(rl
);
2266 __CFRunLoopModeUnlock(rlm
);
2267 __CFRunLoopUnlock(rl
);
2269 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, 0, 0, &livePort
, NULL
);
2271 __CFRunLoopLock(rl
);
2272 __CFRunLoopModeLock(rlm
);
2273 __CFRunLoopUnsetSleeping(rl
);
2274 // If we have a new live port then it will be handled below as normal
2279 if (MACH_PORT_NULL
== livePort
) {
2281 } else if (livePort
== rl
->_wakeUpPort
) {
2282 // do nothing on Mac OS
2283 #if DEPLOYMENT_TARGET_WINDOWS
2284 // Always reset the wake up port, or risk spinning forever
2285 ResetEvent(rl
->_wakeUpPort
);
2287 } else if (livePort
== rlm
->_timerPort
) {
2288 #if DEPLOYMENT_TARGET_WINDOWS
2289 // On Windows, we have observed an issue where the timer port is set before the time which we requested it to be set. For example, we set the fire time to be TSR 167646765860, but it is actually observed firing at TSR 167646764145, which is 1715 ticks early. On the hardware where this was observed, multiplying by the TSR to seconds conversion rate shows that this was 0.000478~ seconds early, but the tenus used when setting fire dates is 0.00001 seconds. The result is that, when __CFRunLoopDoTimers checks to see if any of the run loop timers should be firing, it appears to be 'too early' for the next timer, and no timers are handled.
2290 // In this case, the timer port has been automatically reset (since it was returned from MsgWaitForMultipleObjectsEx), and if we do not re-arm it, then no timers will ever be serviced again unless something adjusts the timer list (e.g. adding or removing timers). The fix for the issue is to reset the timer here if CFRunLoopDoTimers did not handle a timer itself. 9308754
2291 if (!__CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time())) {
2292 // Re-arm the next timer
2293 __CFArmNextTimerInMode(rlm
);
2296 __CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time());
2298 } else if (livePort
== dispatchPort
) {
2299 __CFRunLoopModeUnlock(rlm
);
2300 __CFRunLoopUnlock(rl
);
2301 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)6, NULL
);
2302 _dispatch_main_queue_callback_4CF(msg
);
2303 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)0, NULL
);
2304 __CFRunLoopLock(rl
);
2305 __CFRunLoopModeLock(rlm
);
2306 sourceHandledThisLoop
= true;
2307 didDispatchPortLastTime
= true;
2309 // Despite the name, this works for windows handles as well
2310 CFRunLoopSourceRef rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
);
2312 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2313 mach_msg_header_t
*reply
= NULL
;
2314 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
) || sourceHandledThisLoop
;
2315 if (NULL
!= reply
) {
2316 (void)mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
2317 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
2319 #elif DEPLOYMENT_TARGET_WINDOWS
2320 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
) || sourceHandledThisLoop
;
2324 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2325 if (msg
&& msg
!= (mach_msg_header_t
*)msg_buffer
) free(msg
);
2328 __CFRunLoopDoBlocks(rl
, rlm
);
2330 if (sourceHandledThisLoop
&& stopAfterHandle
) {
2331 retVal
= kCFRunLoopRunHandledSource
;
2332 } else if (timeout_context
->termTSR
< (int64_t)mach_absolute_time()) {
2333 retVal
= kCFRunLoopRunTimedOut
;
2334 } else if (__CFRunLoopIsStopped(rl
)) {
2335 __CFRunLoopUnsetStopped(rl
);
2336 retVal
= kCFRunLoopRunStopped
;
2337 } else if (rlm
->_stopped
) {
2338 rlm
->_stopped
= false;
2339 retVal
= kCFRunLoopRunStopped
;
2340 } else if (__CFRunLoopModeIsEmpty(rl
, rlm
, previousMode
)) {
2341 retVal
= kCFRunLoopRunFinished
;
2343 } while (0 == retVal
);
2345 if (timeout_timer
) {
2346 dispatch_source_cancel(timeout_timer
);
2347 dispatch_release(timeout_timer
);
2349 free(timeout_context
);
2355 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2357 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
2358 __CFRunLoopLock(rl
);
2359 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
2360 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
, rl
->_currentMode
)) {
2361 Boolean did
= false;
2362 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2363 __CFRunLoopUnlock(rl
);
2364 return did
? kCFRunLoopRunHandledSource
: kCFRunLoopRunFinished
;
2366 volatile _per_run_data
*previousPerRun
= __CFRunLoopPushPerRunData(rl
);
2367 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
2368 rl
->_currentMode
= currentMode
;
2370 if (currentMode
->_observerMask
& kCFRunLoopEntry
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
2371 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, previousMode
);
2372 if (currentMode
->_observerMask
& kCFRunLoopExit
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
2373 __CFRunLoopModeUnlock(currentMode
);
2374 __CFRunLoopPopPerRunData(rl
, previousPerRun
);
2375 rl
->_currentMode
= previousMode
;
2376 __CFRunLoopUnlock(rl
);
2380 void CFRunLoopRun(void) { /* DOES CALLOUT */
2383 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
2385 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
2388 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2390 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
2393 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
2395 __CFRunLoopLock(rl
);
2396 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2397 CFAbsoluteTime at
= 0.0;
2398 CFRunLoopTimerRef timer
= (rlm
&& rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) ? (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, 0) : NULL
;
2399 if (timer
) at
= CFRunLoopTimerGetNextFireDate(timer
);
2400 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2401 __CFRunLoopUnlock(rl
);
2405 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
2407 return __CFRunLoopIsSleeping(rl
);
2410 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
2412 // This lock is crucial to ignorable wakeups, do not remove it.
2413 __CFRunLoopLock(rl
);
2414 if (__CFRunLoopIsIgnoringWakeUps(rl
)) {
2415 __CFRunLoopUnlock(rl
);
2418 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2420 /* We unconditionally try to send the message, since we don't want
2421 * to lose a wakeup, but the send may fail if there is already a
2422 * wakeup pending, since the queue length is 1. */
2423 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
2424 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
2426 snprintf(msg
, 256, "*** Unable to send message to wake up port. (%d) ***", ret
);
2427 CRSetCrashLogMessage(msg
);
2430 #elif DEPLOYMENT_TARGET_WINDOWS
2431 SetEvent(rl
->_wakeUpPort
);
2433 __CFRunLoopUnlock(rl
);
2436 void CFRunLoopStop(CFRunLoopRef rl
) {
2437 Boolean doWake
= false;
2439 __CFRunLoopLock(rl
);
2440 if (rl
->_currentMode
) {
2441 __CFRunLoopSetStopped(rl
);
2444 __CFRunLoopUnlock(rl
);
2446 CFRunLoopWakeUp(rl
);
2450 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
2452 CFRunLoopModeRef rlm
;
2453 __CFRunLoopLock(rl
);
2454 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2456 rlm
->_stopped
= true;
2457 __CFRunLoopModeUnlock(rlm
);
2459 __CFRunLoopUnlock(rl
);
2460 CFRunLoopWakeUp(rl
);
2463 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2468 void CFRunLoopPerformBlock(CFRunLoopRef rl
, CFTypeRef mode
, void (^block
)(void)) {
2470 if (CFStringGetTypeID() == CFGetTypeID(mode
)) {
2471 mode
= CFStringCreateCopy(kCFAllocatorSystemDefault
, (CFStringRef
)mode
);
2472 __CFRunLoopLock(rl
);
2473 // ensure mode exists
2474 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)mode
, true);
2475 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2476 __CFRunLoopUnlock(rl
);
2477 } else if (CFArrayGetTypeID() == CFGetTypeID(mode
)) {
2478 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)mode
);
2479 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2480 CFArrayGetValues((CFArrayRef
)mode
, CFRangeMake(0, cnt
), values
);
2481 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2482 __CFRunLoopLock(rl
);
2483 // ensure modes exist
2484 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2485 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2486 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2488 __CFRunLoopUnlock(rl
);
2490 } else if (CFSetGetTypeID() == CFGetTypeID(mode
)) {
2491 CFIndex cnt
= CFSetGetCount((CFSetRef
)mode
);
2492 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2493 CFSetGetValues((CFSetRef
)mode
, values
);
2494 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2495 __CFRunLoopLock(rl
);
2496 // ensure modes exist
2497 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2498 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2499 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2501 __CFRunLoopUnlock(rl
);
2506 block
= Block_copy(block
);
2507 if (!mode
|| !block
) {
2508 if (mode
) CFRelease(mode
);
2509 if (block
) Block_release(block
);
2512 __CFRunLoopLock(rl
);
2513 struct _block_item
*new_item
= (struct _block_item
*)malloc(sizeof(struct _block_item
));
2514 new_item
->_next
= NULL
;
2515 new_item
->_mode
= mode
;
2516 new_item
->_block
= block
;
2517 if (!rl
->_blocks_tail
) {
2518 rl
->_blocks_head
= new_item
;
2520 rl
->_blocks_tail
->_next
= new_item
;
2522 rl
->_blocks_tail
= new_item
;
2523 __CFRunLoopUnlock(rl
);
2526 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2528 CFRunLoopModeRef rlm
;
2529 Boolean hasValue
= false;
2530 __CFRunLoopLock(rl
);
2531 if (modeName
== kCFRunLoopCommonModes
) {
2532 if (NULL
!= rl
->_commonModeItems
) {
2533 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2536 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2538 hasValue
= (rlm
->_sources0
? CFSetContainsValue(rlm
->_sources0
, rls
) : false) || (rlm
->_sources1
? CFSetContainsValue(rlm
->_sources1
, rls
) : false);
2539 __CFRunLoopModeUnlock(rlm
);
2542 __CFRunLoopUnlock(rl
);
2546 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2548 if (__CFRunLoopIsDeallocating(rl
)) return;
2549 if (!__CFIsValid(rls
)) return;
2550 Boolean doVer0Callout
= false;
2551 __CFRunLoopLock(rl
);
2552 if (modeName
== kCFRunLoopCommonModes
) {
2553 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2554 if (NULL
== rl
->_commonModeItems
) {
2555 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2557 CFSetAddValue(rl
->_commonModeItems
, rls
);
2559 CFTypeRef context
[2] = {rl
, rls
};
2560 /* add new item to all common-modes */
2561 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2565 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2566 if (NULL
!= rlm
&& NULL
== rlm
->_sources0
) {
2567 rlm
->_sources0
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2568 rlm
->_sources1
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2569 rlm
->_portToV1SourceMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
2571 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources0
, rls
) && !CFSetContainsValue(rlm
->_sources1
, rls
)) {
2572 if (0 == rls
->_context
.version0
.version
) {
2573 CFSetAddValue(rlm
->_sources0
, rls
);
2574 } else if (1 == rls
->_context
.version0
.version
) {
2575 CFSetAddValue(rlm
->_sources1
, rls
);
2576 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2577 if (CFPORT_NULL
!= src_port
) {
2578 CFDictionarySetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
, rls
);
2579 __CFPortSetInsert(src_port
, rlm
->_portSet
);
2582 __CFRunLoopSourceLock(rls
);
2583 if (NULL
== rls
->_runLoops
) {
2584 rls
->_runLoops
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeBagCallBacks
); // sources retain run loops!
2586 CFBagAddValue(rls
->_runLoops
, rl
);
2587 __CFRunLoopSourceUnlock(rls
);
2588 if (0 == rls
->_context
.version0
.version
) {
2589 if (NULL
!= rls
->_context
.version0
.schedule
) {
2590 doVer0Callout
= true;
2595 __CFRunLoopModeUnlock(rlm
);
2598 __CFRunLoopUnlock(rl
);
2599 if (doVer0Callout
) {
2600 // although it looses some protection for the source, we have no choice but
2601 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2602 // where the source wants to take a lock which is already held in another
2603 // thread which is itself waiting for a run loop/mode lock
2604 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2608 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2610 Boolean doVer0Callout
= false, doRLSRelease
= false;
2611 __CFRunLoopLock(rl
);
2612 if (modeName
== kCFRunLoopCommonModes
) {
2613 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2614 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2615 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2617 CFTypeRef context
[2] = {rl
, rls
};
2618 /* remove new item from all common-modes */
2619 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2625 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2626 if (NULL
!= rlm
&& ((NULL
!= rlm
->_sources0
&& CFSetContainsValue(rlm
->_sources0
, rls
)) || (NULL
!= rlm
->_sources1
&& CFSetContainsValue(rlm
->_sources1
, rls
)))) {
2628 if (1 == rls
->_context
.version0
.version
) {
2629 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2630 if (CFPORT_NULL
!= src_port
) {
2631 CFDictionaryRemoveValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
);
2632 __CFPortSetRemove(src_port
, rlm
->_portSet
);
2635 CFSetRemoveValue(rlm
->_sources0
, rls
);
2636 CFSetRemoveValue(rlm
->_sources1
, rls
);
2637 __CFRunLoopSourceLock(rls
);
2638 if (NULL
!= rls
->_runLoops
) {
2639 CFBagRemoveValue(rls
->_runLoops
, rl
);
2641 __CFRunLoopSourceUnlock(rls
);
2642 if (0 == rls
->_context
.version0
.version
) {
2643 if (NULL
!= rls
->_context
.version0
.schedule
) {
2644 doVer0Callout
= true;
2647 doRLSRelease
= true;
2650 __CFRunLoopModeUnlock(rlm
);
2653 __CFRunLoopUnlock(rl
);
2654 if (doVer0Callout
) {
2655 // although it looses some protection for the source, we have no choice but
2656 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2657 // where the source wants to take a lock which is already held in another
2658 // thread which is itself waiting for a run loop/mode lock
2659 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2661 if (doRLSRelease
) CFRelease(rls
);
2664 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value
, void *ctx
) {
2665 CFStringRef modeName
= (CFStringRef
)value
;
2666 CFRunLoopRef rl
= (CFRunLoopRef
)ctx
;
2667 __CFRunLoopRemoveAllSources(rl
, modeName
);
2670 static void __CFRunLoopRemoveSourceFromMode(const void *value
, void *ctx
) {
2671 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
2672 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
2673 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
2674 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2677 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
) {
2679 CFRunLoopModeRef rlm
;
2680 __CFRunLoopLock(rl
);
2681 if (modeName
== kCFRunLoopCommonModes
) {
2682 if (NULL
!= rl
->_commonModeItems
) {
2683 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2685 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourcesFromCommonMode
), (void *)rl
);
2691 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2692 if (NULL
!= rlm
&& NULL
!= rlm
->_sources0
) {
2693 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources0
);
2694 CFTypeRef context
[2] = {rl
, modeName
};
2695 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2698 if (NULL
!= rlm
&& NULL
!= rlm
->_sources1
) {
2699 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources1
);
2700 CFTypeRef context
[2] = {rl
, modeName
};
2701 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2705 __CFRunLoopModeUnlock(rlm
);
2708 __CFRunLoopUnlock(rl
);
2711 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2713 CFRunLoopModeRef rlm
;
2714 Boolean hasValue
= false;
2715 __CFRunLoopLock(rl
);
2716 if (modeName
== kCFRunLoopCommonModes
) {
2717 if (NULL
!= rl
->_commonModeItems
) {
2718 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2721 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2722 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2723 hasValue
= CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
2726 __CFRunLoopModeUnlock(rlm
);
2729 __CFRunLoopUnlock(rl
);
2733 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2735 CFRunLoopModeRef rlm
;
2736 if (__CFRunLoopIsDeallocating(rl
)) return;
2737 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2738 __CFRunLoopLock(rl
);
2739 if (modeName
== kCFRunLoopCommonModes
) {
2740 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2741 if (NULL
== rl
->_commonModeItems
) {
2742 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2744 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2746 CFTypeRef context
[2] = {rl
, rlo
};
2747 /* add new item to all common-modes */
2748 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2752 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2753 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2754 rlm
->_observers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2756 if (NULL
!= rlm
&& !CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
)) {
2757 Boolean inserted
= false;
2758 for (CFIndex idx
= CFArrayGetCount(rlm
->_observers
); idx
--; ) {
2759 CFRunLoopObserverRef obs
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(rlm
->_observers
, idx
);
2760 if (obs
->_order
<= rlo
->_order
) {
2761 CFArrayInsertValueAtIndex(rlm
->_observers
, idx
+ 1, rlo
);
2767 CFArrayInsertValueAtIndex(rlm
->_observers
, 0, rlo
);
2769 rlm
->_observerMask
|= rlo
->_activities
;
2770 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
2773 __CFRunLoopModeUnlock(rlm
);
2776 __CFRunLoopUnlock(rl
);
2779 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2781 CFRunLoopModeRef rlm
;
2782 __CFRunLoopLock(rl
);
2783 if (modeName
== kCFRunLoopCommonModes
) {
2784 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
2785 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2786 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
2788 CFTypeRef context
[2] = {rl
, rlo
};
2789 /* remove new item from all common-modes */
2790 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2796 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2797 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2799 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
2800 if (kCFNotFound
!= idx
) {
2801 CFArrayRemoveValueAtIndex(rlm
->_observers
, idx
);
2802 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
2807 __CFRunLoopModeUnlock(rlm
);
2810 __CFRunLoopUnlock(rl
);
2813 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2815 if (NULL
== rlt
->_runLoop
|| rl
!= rlt
->_runLoop
) return false;
2816 Boolean hasValue
= false;
2817 __CFRunLoopLock(rl
);
2818 if (modeName
== kCFRunLoopCommonModes
) {
2819 if (NULL
!= rl
->_commonModeItems
) {
2820 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
2823 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2824 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2825 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), rlt
);
2826 hasValue
= (kCFNotFound
!= idx
);
2829 __CFRunLoopModeUnlock(rlm
);
2832 __CFRunLoopUnlock(rl
);
2836 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2838 if (__CFRunLoopIsDeallocating(rl
)) return;
2839 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
2840 __CFRunLoopLock(rl
);
2841 if (modeName
== kCFRunLoopCommonModes
) {
2842 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2843 if (NULL
== rl
->_commonModeItems
) {
2844 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2846 CFSetAddValue(rl
->_commonModeItems
, rlt
);
2848 CFTypeRef context
[2] = {rl
, rlt
};
2849 /* add new item to all common-modes */
2850 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2854 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2855 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
2856 CFArrayCallBacks cb
= kCFTypeArrayCallBacks
;
2858 rlm
->_timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &cb
);
2860 if (NULL
!= rlm
&& !CFSetContainsValue(rlt
->_rlModes
, rlm
->_name
)) {
2861 __CFRunLoopTimerLock(rlt
);
2862 if (NULL
== rlt
->_runLoop
) {
2864 } else if (rl
!= rlt
->_runLoop
) {
2865 __CFRunLoopTimerUnlock(rlt
);
2866 __CFRunLoopModeUnlock(rlm
);
2867 __CFRunLoopUnlock(rl
);
2870 CFSetAddValue(rlt
->_rlModes
, rlm
->_name
);
2871 __CFRunLoopTimerUnlock(rlt
);
2872 __CFRunLoopTimerFireTSRLock();
2873 __CFRepositionTimerInMode(rlm
, rlt
, false);
2874 __CFRunLoopTimerFireTSRUnlock();
2875 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion
)) {
2876 // Normally we don't do this on behalf of clients, but for
2877 // backwards compatibility due to the change in timer handling...
2878 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
2882 __CFRunLoopModeUnlock(rlm
);
2885 __CFRunLoopUnlock(rl
);
2888 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2890 __CFRunLoopLock(rl
);
2891 if (modeName
== kCFRunLoopCommonModes
) {
2892 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
2893 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2894 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
2896 CFTypeRef context
[2] = {rl
, rlt
};
2897 /* remove new item from all common-modes */
2898 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2904 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2905 CFIndex idx
= kCFNotFound
;
2906 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2907 idx
= CFArrayGetFirstIndexOfValue(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), rlt
);
2909 if (kCFNotFound
!= idx
) {
2910 __CFRunLoopTimerLock(rlt
);
2911 CFSetRemoveValue(rlt
->_rlModes
, rlm
->_name
);
2912 if (0 == CFSetGetCount(rlt
->_rlModes
)) {
2913 rlt
->_runLoop
= NULL
;
2915 __CFRunLoopTimerUnlock(rlt
);
2916 CFArrayRemoveValueAtIndex(rlm
->_timers
, idx
);
2917 if (0 == CFArrayGetCount(rlm
->_timers
)) {
2919 mk_timer_cancel(rlm
->_timerPort
, &dummy
);
2920 } else if (0 == idx
) {
2921 __CFArmNextTimerInMode(rlm
);
2925 __CFRunLoopModeUnlock(rlm
);
2928 __CFRunLoopUnlock(rl
);
2931 /* CFRunLoopSource */
2933 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
2934 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
2935 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
2936 if (rls1
== rls2
) return true;
2937 if (__CFIsValid(rls1
) != __CFIsValid(rls2
)) return false;
2938 if (rls1
->_order
!= rls2
->_order
) return false;
2939 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
2940 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
2941 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
2942 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
2943 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
2944 if (rls1
->_context
.version0
.equal
)
2945 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
2946 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
2949 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
2950 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2951 if (rls
->_context
.version0
.hash
)
2952 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
2953 return (CFHashCode
)rls
->_context
.version0
.info
;
2956 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2957 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2959 CFStringRef contextDesc
= NULL
;
2960 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
2961 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
2963 if (NULL
== contextDesc
) {
2964 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
2965 #if DEPLOYMENT_TARGET_WINDOWS
2966 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, addr
);
2967 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2969 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2970 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
2973 #if DEPLOYMENT_TARGET_WINDOWS
2974 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource %p [%p]>{signalled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
2976 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource %p [%p]>{signalled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
2978 CFRelease(contextDesc
);
2982 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2983 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2984 CFRunLoopSourceInvalidate(rls
);
2985 if (rls
->_context
.version0
.release
) {
2986 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
2988 pthread_mutex_destroy(&rls
->_lock
);
2989 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0, sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
));
2992 static const CFRuntimeClass __CFRunLoopSourceClass
= {
2993 _kCFRuntimeScannedObject
,
2997 __CFRunLoopSourceDeallocate
,
2998 __CFRunLoopSourceEqual
,
2999 __CFRunLoopSourceHash
,
3001 __CFRunLoopSourceCopyDescription
3004 __private_extern__
void __CFRunLoopSourceInitialize(void) {
3005 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
3008 CFTypeID
CFRunLoopSourceGetTypeID(void) {
3009 return __kCFRunLoopSourceTypeID
;
3012 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
3014 CFRunLoopSourceRef memory
;
3016 if (NULL
== context
) {
3017 CRSetCrashLogMessage("*** NULL context value passed to CFRunLoopSourceCreate(). ***");
3020 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
3021 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
3022 if (NULL
== memory
) {
3025 __CFSetValid(memory
);
3026 __CFRunLoopSourceUnsetSignaled(memory
);
3027 __CFRunLoopLockInit(&memory
->_lock
);
3029 memory
->_order
= order
;
3030 memory
->_runLoops
= NULL
;
3032 switch (context
->version
) {
3034 size
= sizeof(CFRunLoopSourceContext
);
3037 size
= sizeof(CFRunLoopSourceContext1
);
3040 objc_memmove_collectable(&memory
->_context
, context
, size
);
3041 if (context
->retain
) {
3042 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
3047 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
3049 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3053 static void __CFRunLoopSourceWakeUpLoop(const void *value
, void *context
) {
3054 CFRunLoopWakeUp((CFRunLoopRef
)value
);
3057 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
3058 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
3059 CFTypeRef
*params
= (CFTypeRef
*)context
;
3060 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
3062 if (rl
== params
[1]) return;
3064 // CFRunLoopRemoveSource will lock the run loop while it
3065 // needs that, but we also lock it out here to keep
3066 // changes from occurring for this whole sequence.
3067 __CFRunLoopLock(rl
);
3068 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3069 for (idx
= CFArrayGetCount(array
); idx
--;) {
3070 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3071 CFRunLoopRemoveSource(rl
, rls
, modeName
);
3073 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
3074 __CFRunLoopUnlock(rl
);
3079 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
3081 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3082 __CFRunLoopSourceLock(rls
);
3084 if (__CFIsValid(rls
)) {
3085 CFBagRef rloops
= rls
->_runLoops
;
3086 __CFUnsetValid(rls
);
3087 __CFRunLoopSourceUnsetSignaled(rls
);
3088 if (NULL
!= rloops
) {
3089 // To avoid A->B, B->A lock ordering issues when coming up
3090 // towards the run loop from a source, the source has to be
3091 // unlocked, which means we have to protect from object
3093 rls
->_runLoops
= NULL
; // transfer ownership to local stack
3094 __CFRunLoopSourceUnlock(rls
);
3095 CFTypeRef params
[2] = {rls
, NULL
};
3096 CFBagApplyFunction(rloops
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
3098 __CFRunLoopSourceLock(rls
);
3100 /* for hashing- and equality-use purposes, can't actually release the context here */
3102 __CFRunLoopSourceUnlock(rls
);
3106 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
3108 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3109 return __CFIsValid(rls
);
3112 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
3114 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3115 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
3117 switch (context
->version
) {
3119 size
= sizeof(CFRunLoopSourceContext
);
3122 size
= sizeof(CFRunLoopSourceContext1
);
3125 memmove(context
, &rls
->_context
, size
);
3128 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
3130 __CFRunLoopSourceLock(rls
);
3131 if (__CFIsValid(rls
)) {
3132 __CFRunLoopSourceSetSignaled(rls
);
3134 __CFRunLoopSourceUnlock(rls
);
3137 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
3139 __CFRunLoopSourceLock(rls
);
3140 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
3141 __CFRunLoopSourceUnlock(rls
);
3145 __private_extern__
void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
) {
3146 CFBagRef loops
= NULL
;
3147 __CFRunLoopSourceLock(rls
);
3148 if (__CFIsValid(rls
) && NULL
!= rls
->_runLoops
) {
3149 loops
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
3151 __CFRunLoopSourceUnlock(rls
);
3153 CFBagApplyFunction(loops
, __CFRunLoopSourceWakeUpLoop
, NULL
);
3158 /* CFRunLoopObserver */
3160 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3161 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3163 CFStringRef contextDesc
= NULL
;
3164 if (NULL
!= rlo
->_context
.copyDescription
) {
3165 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
3168 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
3170 #if DEPLOYMENT_TARGET_WINDOWS
3171 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf
, CFGetAllocator(rlo
), __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, rlo
->_callout
, contextDesc
);
3172 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3173 void *addr
= rlo
->_callout
;
3175 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3176 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlo
), __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, name
, addr
, contextDesc
);
3178 CFRelease(contextDesc
);
3182 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3183 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3184 CFRunLoopObserverInvalidate(rlo
);
3185 pthread_mutex_destroy(&rlo
->_lock
);
3188 static const CFRuntimeClass __CFRunLoopObserverClass
= {
3190 "CFRunLoopObserver",
3193 __CFRunLoopObserverDeallocate
,
3197 __CFRunLoopObserverCopyDescription
3200 __private_extern__
void __CFRunLoopObserverInitialize(void) {
3201 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
3204 CFTypeID
CFRunLoopObserverGetTypeID(void) {
3205 return __kCFRunLoopObserverTypeID
;
3208 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
3210 CFRunLoopObserverRef memory
;
3212 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
3213 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
3214 if (NULL
== memory
) {
3217 __CFSetValid(memory
);
3218 __CFRunLoopObserverUnsetFiring(memory
);
3220 __CFRunLoopObserverSetRepeats(memory
);
3222 __CFRunLoopObserverUnsetRepeats(memory
);
3224 __CFRunLoopLockInit(&memory
->_lock
);
3225 memory
->_runLoop
= NULL
;
3226 memory
->_rlCount
= 0;
3227 memory
->_activities
= activities
;
3228 memory
->_order
= order
;
3229 memory
->_callout
= callout
;
3231 if (context
->retain
) {
3232 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3234 memory
->_context
.info
= context
->info
;
3236 memory
->_context
.retain
= context
->retain
;
3237 memory
->_context
.release
= context
->release
;
3238 memory
->_context
.copyDescription
= context
->copyDescription
;
3240 memory
->_context
.info
= 0;
3241 memory
->_context
.retain
= 0;
3242 memory
->_context
.release
= 0;
3243 memory
->_context
.copyDescription
= 0;
3248 static void _runLoopObserverWithBlockContext(CFRunLoopObserverRef observer
, CFRunLoopActivity activity
, void *opaqueBlock
) {
3249 typedef void (^observer_block_t
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
);
3250 observer_block_t block
= (observer_block_t
)opaqueBlock
;
3251 block(observer
, activity
);
3254 CFRunLoopObserverRef
CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
,
3255 void (^block
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
)) {
3256 CFRunLoopObserverContext blockContext
;
3257 blockContext
.version
= 0;
3258 blockContext
.info
= (void *)block
;
3259 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3260 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3261 blockContext
.copyDescription
= NULL
;
3262 return CFRunLoopObserverCreate(allocator
, activities
, repeats
, order
, _runLoopObserverWithBlockContext
, &blockContext
);
3265 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
3267 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3268 return rlo
->_activities
;
3271 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
3273 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3277 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
3279 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3280 return __CFRunLoopObserverRepeats(rlo
);
3283 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
3285 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3286 __CFRunLoopObserverLock(rlo
);
3288 if (__CFIsValid(rlo
)) {
3289 CFRunLoopRef rl
= rlo
->_runLoop
;
3290 void *info
= rlo
->_context
.info
;
3291 rlo
->_context
.info
= NULL
;
3292 __CFUnsetValid(rlo
);
3294 // To avoid A->B, B->A lock ordering issues when coming up
3295 // towards the run loop from an observer, it has to be
3296 // unlocked, which means we have to protect from object
3299 __CFRunLoopObserverUnlock(rlo
);
3300 // CFRunLoopRemoveObserver will lock the run loop while it
3301 // needs that, but we also lock it out here to keep
3302 // changes from occurring for this whole sequence.
3303 __CFRunLoopLock(rl
);
3304 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3305 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
3306 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3307 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
3309 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
3310 __CFRunLoopUnlock(rl
);
3313 __CFRunLoopObserverLock(rlo
);
3315 if (NULL
!= rlo
->_context
.release
) {
3316 rlo
->_context
.release(info
); /* CALLOUT */
3319 __CFRunLoopObserverUnlock(rlo
);
3323 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
3325 return __CFIsValid(rlo
);
3328 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
3330 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3331 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3332 *context
= rlo
->_context
;
3335 /* CFRunLoopTimer */
3337 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3338 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3339 CFStringRef contextDesc
= NULL
;
3340 if (NULL
!= rlt
->_context
.copyDescription
) {
3341 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
3343 if (NULL
== contextDesc
) {
3344 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
3346 void *addr
= (void *)rlt
->_callout
;
3347 const char *name
= "???";
3348 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3350 name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3352 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer %p [%p]>{valid = %s, firing = %s, interval = %0.09g, next fire date = %0.09g, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlt
), __CFIsValid(rlt
) ? "Yes" : "No", __CFRunLoopTimerIsFiring(rlt
) ? "Yes" : "No", rlt
->_interval
, rlt
->_nextFireDate
, name
, addr
, contextDesc
);
3353 CFRelease(contextDesc
);
3357 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3358 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3359 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3360 __CFRunLoopTimerSetDeallocating(rlt
);
3361 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
3362 CFRelease(rlt
->_rlModes
);
3363 rlt
->_rlModes
= NULL
;
3364 pthread_mutex_destroy(&rlt
->_lock
);
3367 static const CFRuntimeClass __CFRunLoopTimerClass
= {
3372 __CFRunLoopTimerDeallocate
,
3376 __CFRunLoopTimerCopyDescription
3379 __private_extern__
void __CFRunLoopTimerInitialize(void) {
3380 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
3383 CFTypeID
CFRunLoopTimerGetTypeID(void) {
3384 return __kCFRunLoopTimerTypeID
;
3387 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
3389 CFRunLoopTimerRef memory
;
3391 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
3392 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
3393 if (NULL
== memory
) {
3396 __CFSetValid(memory
);
3397 __CFRunLoopTimerUnsetFiring(memory
);
3398 __CFRunLoopLockInit(&memory
->_lock
);
3399 memory
->_runLoop
= NULL
;
3400 memory
->_rlModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3401 memory
->_order
= order
;
3402 if (interval
< 0.0) interval
= 0.0;
3403 memory
->_interval
= interval
;
3404 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3405 memory
->_nextFireDate
= fireDate
;
3406 memory
->_fireTSR
= 0LL;
3407 int64_t now2
= (int64_t)mach_absolute_time();
3408 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3409 if (fireDate
< now1
) {
3410 memory
->_fireTSR
= now2
;
3411 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3412 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3414 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3416 memory
->_callout
= callout
;
3417 if (NULL
!= context
) {
3418 if (context
->retain
) {
3419 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3421 memory
->_context
.info
= context
->info
;
3423 memory
->_context
.retain
= context
->retain
;
3424 memory
->_context
.release
= context
->release
;
3425 memory
->_context
.copyDescription
= context
->copyDescription
;
3427 memory
->_context
.info
= 0;
3428 memory
->_context
.retain
= 0;
3429 memory
->_context
.release
= 0;
3430 memory
->_context
.copyDescription
= 0;
3435 static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer
, void *opaqueBlock
) {
3436 typedef void (^timer_block_t
) (CFRunLoopTimerRef timer
);
3437 timer_block_t block
= (timer_block_t
)opaqueBlock
;
3441 CFRunLoopTimerRef
CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
,
3442 void (^block
) (CFRunLoopTimerRef timer
)) {
3444 CFRunLoopTimerContext blockContext
;
3445 blockContext
.version
= 0;
3446 blockContext
.info
= (void *)block
;
3447 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3448 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3449 blockContext
.copyDescription
= NULL
;
3450 return CFRunLoopTimerCreate(allocator
, fireDate
, interval
, flags
, order
, _runLoopTimerWithBlockContext
, &blockContext
);
3453 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
3455 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, (NSTimer
*)rlt
, _cffireTime
);
3456 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3457 CFAbsoluteTime at
= 0.0;
3458 __CFRunLoopTimerLock(rlt
);
3459 __CFRunLoopTimerFireTSRLock();
3460 if (__CFIsValid(rlt
)) {
3461 at
= rlt
->_nextFireDate
;
3463 __CFRunLoopTimerFireTSRUnlock();
3464 __CFRunLoopTimerUnlock(rlt
);
3468 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
3470 if (!__CFIsValid(rlt
)) return;
3471 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3472 int64_t nextFireTSR
= 0LL;
3473 int64_t now2
= (int64_t)mach_absolute_time();
3474 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3475 if (fireDate
< now1
) {
3477 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3478 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3480 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3482 __CFRunLoopTimerLock(rlt
);
3483 if (NULL
!= rlt
->_runLoop
) {
3484 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3485 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
3486 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3487 // To avoid A->B, B->A lock ordering issues when coming up
3488 // towards the run loop from a source, the timer has to be
3489 // unlocked, which means we have to protect from object
3490 // invalidation, although that's somewhat expensive.
3491 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3492 CFRetain(modes
[idx
]);
3494 CFRunLoopRef rl
= (CFRunLoopRef
)CFRetain(rlt
->_runLoop
);
3495 __CFRunLoopTimerUnlock(rlt
);
3496 __CFRunLoopLock(rl
);
3497 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3498 CFStringRef name
= (CFStringRef
)modes
[idx
];
3499 modes
[idx
] = __CFRunLoopFindMode(rl
, name
, false);
3502 __CFRunLoopTimerFireTSRLock();
3503 rlt
->_fireTSR
= nextFireTSR
;
3504 rlt
->_nextFireDate
= fireDate
;
3505 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3506 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
3508 __CFRepositionTimerInMode(rlm
, rlt
, true);
3511 __CFRunLoopTimerFireTSRUnlock();
3512 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3513 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
3515 __CFRunLoopUnlock(rl
);
3516 // This is setting the date of a timer, not a direct
3517 // interaction with a run loop, so we'll do a wakeup
3518 // (which may be costly) for the caller, just in case.
3519 // (And useful for binary compatibility with older
3520 // code used to the older timer implementation.)
3521 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
3524 __CFRunLoopTimerFireTSRLock();
3525 rlt
->_fireTSR
= nextFireTSR
;
3526 rlt
->_nextFireDate
= fireDate
;
3527 __CFRunLoopTimerFireTSRUnlock();
3528 __CFRunLoopTimerUnlock(rlt
);
3532 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
3534 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, CFTimeInterval
, (NSTimer
*)rlt
, timeInterval
);
3535 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3536 return rlt
->_interval
;
3539 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
3541 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3542 return (0.0 < rlt
->_interval
);
3545 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
3547 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3551 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
3553 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, void, (NSTimer
*)rlt
, invalidate
);
3554 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3555 __CFRunLoopTimerLock(rlt
);
3556 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3559 if (__CFIsValid(rlt
)) {
3560 CFRunLoopRef rl
= rlt
->_runLoop
;
3561 void *info
= rlt
->_context
.info
;
3562 rlt
->_context
.info
= NULL
;
3563 __CFUnsetValid(rlt
);
3565 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3566 STACK_BUFFER_DECL(CFStringRef
, modes
, cnt
);
3567 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3568 // To avoid A->B, B->A lock ordering issues when coming up
3569 // towards the run loop from a source, the timer has to be
3570 // unlocked, which means we have to protect from object
3571 // invalidation, although that's somewhat expensive.
3572 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3573 CFRetain(modes
[idx
]);
3576 __CFRunLoopTimerUnlock(rlt
);
3577 // CFRunLoopRemoveTimer will lock the run loop while it
3578 // needs that, but we also lock it out here to keep
3579 // changes from occurring for this whole sequence.
3580 __CFRunLoopLock(rl
);
3581 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3582 CFRunLoopRemoveTimer(rl
, rlt
, modes
[idx
]);
3584 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
3585 __CFRunLoopUnlock(rl
);
3586 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3587 CFRelease(modes
[idx
]);
3590 __CFRunLoopTimerLock(rlt
);
3592 if (NULL
!= rlt
->_context
.release
) {
3593 rlt
->_context
.release(info
); /* CALLOUT */
3596 __CFRunLoopTimerUnlock(rlt
);
3597 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3602 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
3604 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, Boolean
, (NSTimer
*)rlt
, isValid
);
3605 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3606 return __CFIsValid(rlt
);
3609 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
3611 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3612 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3613 *context
= rlt
->_context
;