2 * Copyright (c) 2015 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-2014, 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 <CoreFoundation/CFNumber.h>
33 #include <CoreFoundation/CFPreferences.h>
34 #include "CFInternal.h"
39 #include <dispatch/dispatch.h>
42 #if DEPLOYMENT_TARGET_WINDOWS
47 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
48 #include <sys/param.h>
49 #include <dispatch/private.h>
50 #include <CoreFoundation/CFUserNotification.h>
51 #include <mach/mach.h>
52 #include <mach/clock_types.h>
53 #include <mach/clock.h>
56 #include <pthread/private.h>
57 #include <os/voucher_private.h>
58 extern mach_port_t
_dispatch_get_main_queue_port_4CF(void);
59 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t
*msg
);
60 #elif DEPLOYMENT_TARGET_WINDOWS
62 DISPATCH_EXPORT HANDLE
_dispatch_get_main_queue_handle_4CF(void);
63 DISPATCH_EXPORT
void _dispatch_main_queue_callback_4CF(void);
65 #define MACH_PORT_NULL 0
66 #define mach_port_name_t HANDLE
67 #define mach_port_t HANDLE
68 #define _dispatch_get_main_queue_port_4CF _dispatch_get_main_queue_handle_4CF
69 #define _dispatch_main_queue_callback_4CF(x) _dispatch_main_queue_callback_4CF()
71 #define AbsoluteTime LARGE_INTEGER
75 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
76 CF_EXPORT pthread_t
_CF_pthread_main_thread_np(void);
77 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
81 #include <Block_private.h>
83 #if DEPLOYMENT_TARGET_MACOSX
84 #define USE_DISPATCH_SOURCE_FOR_TIMERS 1
85 #define USE_MK_TIMER_TOO 1
87 #define USE_DISPATCH_SOURCE_FOR_TIMERS 0
88 #define USE_MK_TIMER_TOO 1
92 static int _LogCFRunLoop
= 0;
93 static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer
, void *opaqueBlock
);
95 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
96 #define TIMER_DATE_LIMIT 4039289856.0
97 #define TIMER_INTERVAL_LIMIT 504911232.0
99 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
101 #define CRASH(string, errcode) do { char msg[256]; snprintf(msg, 256, string, errcode); CRSetCrashLogMessage(msg); HALT; } while (0)
103 #if DEPLOYMENT_TARGET_WINDOWS
105 static pthread_t kNilPthreadT
= { nil
, nil
};
106 #define pthreadPointer(a) a.p
107 typedef int kern_return_t
;
108 #define KERN_SUCCESS 0
112 static pthread_t kNilPthreadT
= (pthread_t
)0;
113 #define pthreadPointer(a) a
114 #define lockCount(a) a
119 #define CF_RUN_LOOP_PROBES 0
121 #if CF_RUN_LOOP_PROBES
122 #include "CFRunLoopProbes.h"
124 #define CFRUNLOOP_NEXT_TIMER_ARMED(arg0) do { } while (0)
125 #define CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED() (0)
126 #define CFRUNLOOP_POLL() do { } while (0)
127 #define CFRUNLOOP_POLL_ENABLED() (0)
128 #define CFRUNLOOP_SLEEP() do { } while (0)
129 #define CFRUNLOOP_SLEEP_ENABLED() (0)
130 #define CFRUNLOOP_SOURCE_FIRED(arg0, arg1, arg2) do { } while (0)
131 #define CFRUNLOOP_SOURCE_FIRED_ENABLED() (0)
132 #define CFRUNLOOP_TIMER_CREATED(arg0, arg1, arg2, arg3, arg4, arg5, arg6) do { } while (0)
133 #define CFRUNLOOP_TIMER_CREATED_ENABLED() (0)
134 #define CFRUNLOOP_TIMER_FIRED(arg0, arg1, arg2, arg3, arg4) do { } while (0)
135 #define CFRUNLOOP_TIMER_FIRED_ENABLED() (0)
136 #define CFRUNLOOP_TIMER_RESCHEDULED(arg0, arg1, arg2, arg3, arg4, arg5) do { } while (0)
137 #define CFRUNLOOP_TIMER_RESCHEDULED_ENABLED() (0)
138 #define CFRUNLOOP_WAKEUP(arg0) do { } while (0)
139 #define CFRUNLOOP_WAKEUP_ENABLED() (0)
140 #define CFRUNLOOP_WAKEUP_FOR_DISPATCH() do { } while (0)
141 #define CFRUNLOOP_WAKEUP_FOR_DISPATCH_ENABLED() (0)
142 #define CFRUNLOOP_WAKEUP_FOR_NOTHING() do { } while (0)
143 #define CFRUNLOOP_WAKEUP_FOR_NOTHING_ENABLED() (0)
144 #define CFRUNLOOP_WAKEUP_FOR_SOURCE() do { } while (0)
145 #define CFRUNLOOP_WAKEUP_FOR_SOURCE_ENABLED() (0)
146 #define CFRUNLOOP_WAKEUP_FOR_TIMEOUT() do { } while (0)
147 #define CFRUNLOOP_WAKEUP_FOR_TIMEOUT_ENABLED() (0)
148 #define CFRUNLOOP_WAKEUP_FOR_TIMER() do { } while (0)
149 #define CFRUNLOOP_WAKEUP_FOR_TIMER_ENABLED() (0)
150 #define CFRUNLOOP_WAKEUP_FOR_WAKEUP() do { } while (0)
151 #define CFRUNLOOP_WAKEUP_FOR_WAKEUP_ENABLED() (0)
154 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
155 // simple abstraction layer spanning Mach ports and Windows HANDLES
156 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
158 CF_PRIVATE
uint32_t __CFGetProcessPortCount(void) {
159 ipc_info_space_t info
;
160 ipc_info_name_array_t table
= 0;
161 mach_msg_type_number_t tableCount
= 0;
162 ipc_info_tree_name_array_t tree
= 0;
163 mach_msg_type_number_t treeCount
= 0;
165 kern_return_t ret
= mach_port_space_info(mach_task_self(), &info
, &table
, &tableCount
, &tree
, &treeCount
);
166 if (ret
!= KERN_SUCCESS
) {
170 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)table
, tableCount
* sizeof(*table
));
173 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)tree
, treeCount
* sizeof(*tree
));
175 return (uint32_t)tableCount
;
178 CF_PRIVATE CFArrayRef
__CFStopAllThreads(void) {
179 CFMutableArrayRef suspended_list
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
180 mach_port_t my_task
= mach_task_self();
181 mach_port_t my_thread
= mach_thread_self();
182 thread_act_array_t thr_list
= 0;
183 mach_msg_type_number_t thr_cnt
= 0;
185 // really, should loop doing the stopping until no more threads get added to the list N times in a row
186 kern_return_t ret
= task_threads(my_task
, &thr_list
, &thr_cnt
);
187 if (ret
== KERN_SUCCESS
) {
188 for (CFIndex idx
= 0; idx
< thr_cnt
; idx
++) {
189 thread_act_t thread
= thr_list
[idx
];
190 if (thread
== my_thread
) continue;
191 if (CFArrayContainsValue(suspended_list
, CFRangeMake(0, CFArrayGetCount(suspended_list
)), (const void *)(uintptr_t)thread
)) continue;
192 ret
= thread_suspend(thread
);
193 if (ret
== KERN_SUCCESS
) {
194 CFArrayAppendValue(suspended_list
, (const void *)(uintptr_t)thread
);
196 mach_port_deallocate(my_task
, thread
);
199 vm_deallocate(my_task
, (vm_address_t
)thr_list
, sizeof(thread_t
) * thr_cnt
);
201 mach_port_deallocate(my_task
, my_thread
);
202 return suspended_list
;
205 CF_PRIVATE
void __CFRestartAllThreads(CFArrayRef threads
) {
206 for (CFIndex idx
= 0; idx
< CFArrayGetCount(threads
); idx
++) {
207 thread_act_t thread
= (thread_act_t
)(uintptr_t)CFArrayGetValueAtIndex(threads
, idx
);
208 kern_return_t ret
= thread_resume(thread
);
209 if (ret
!= KERN_SUCCESS
) CRASH("*** Failure from thread_resume (%d) ***", ret
);
210 mach_port_deallocate(mach_task_self(), thread
);
214 static uint32_t __CF_last_warned_port_count
= 0;
216 static void foo() __attribute__((unused
));
218 uint32_t pcnt
= __CFGetProcessPortCount();
219 if (__CF_last_warned_port_count
+ 1000 < pcnt
) {
220 CFArrayRef threads
= __CFStopAllThreads();
224 CFOptionFlags responseFlags
= 0;
225 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
);
227 CFLog(3, CFSTR("ERROR"));
229 switch (responseFlags
) {
230 case kCFUserNotificationDefaultResponse
: CFLog(3, CFSTR("DefaultR")); break;
231 case kCFUserNotificationAlternateResponse
: CFLog(3, CFSTR("AltR")); break;
232 case kCFUserNotificationOtherResponse
: CFLog(3, CFSTR("OtherR")); break;
233 case kCFUserNotificationCancelResponse
: CFLog(3, CFSTR("CancelR")); break;
238 __CFRestartAllThreads(threads
);
240 __CF_last_warned_port_count
= pcnt
;
245 typedef mach_port_t __CFPort
;
246 #define CFPORT_NULL MACH_PORT_NULL
247 typedef mach_port_t __CFPortSet
;
249 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
250 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) { HALT
; };
252 static __CFPort
__CFPortAllocate(void) {
253 __CFPort result
= CFPORT_NULL
;
254 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
255 if (KERN_SUCCESS
!= ret
) {
257 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
);
258 CRSetCrashLogMessage(msg
);
259 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret
);
263 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
264 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to set send right on mach port. (%d) ***", ret
);
267 mach_port_limits_t limits
;
268 limits
.mpl_qlimit
= 1;
269 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
270 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to set attributes on mach port. (%d) ***", ret
);
275 CF_INLINE
void __CFPortFree(__CFPort port
) {
276 mach_port_destroy(mach_task_self(), port
);
279 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
280 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) { HALT
; };
282 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
284 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
285 if (KERN_SUCCESS
!= ret
) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret
); }
286 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
289 CF_INLINE kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
290 if (MACH_PORT_NULL
== port
) {
293 return mach_port_insert_member(mach_task_self(), port
, portSet
);
296 CF_INLINE kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
297 if (MACH_PORT_NULL
== port
) {
300 return mach_port_extract_member(mach_task_self(), port
, portSet
);
303 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
305 mach_port_name_array_t array
;
306 mach_msg_type_number_t idx
, number
;
308 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
309 if (KERN_SUCCESS
== ret
) {
310 for (idx
= 0; idx
< number
; idx
++) {
311 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
313 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
315 mach_port_destroy(mach_task_self(), portSet
);
318 #elif DEPLOYMENT_TARGET_WINDOWS
320 typedef HANDLE __CFPort
;
321 #define CFPORT_NULL NULL
323 // A simple dynamic array of HANDLEs, which grows to a high-water mark
324 typedef struct ___CFPortSet
{
328 CFLock_t lock
; // insert and remove must be thread safe, like the Mach calls
331 CF_INLINE __CFPort
__CFPortAllocate(void) {
332 return CreateEventA(NULL
, true, false, NULL
);
335 CF_INLINE
void __CFPortFree(__CFPort port
) {
339 static __CFPortSet
__CFPortSetAllocate(void) {
340 __CFPortSet result
= (__CFPortSet
)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
343 result
->handles
= (HANDLE
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
344 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
348 static void __CFPortSetFree(__CFPortSet portSet
) {
349 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
350 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
353 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
354 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
355 __CFLock(&(portSet
->lock
));
356 __CFPort
*result
= portBuf
;
357 if (bufSize
< portSet
->used
)
358 result
= (__CFPort
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
359 if (portSet
->used
> 1) {
360 // rotate the ports to vaguely simulate round-robin behaviour
361 uint16_t lastPort
= portSet
->used
- 1;
362 HANDLE swapHandle
= portSet
->handles
[0];
363 memmove(portSet
->handles
, &portSet
->handles
[1], lastPort
* sizeof(HANDLE
));
364 portSet
->handles
[lastPort
] = swapHandle
;
366 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
367 *portsUsed
= portSet
->used
;
368 __CFUnlock(&(portSet
->lock
));
372 static kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
376 __CFLock(&(portSet
->lock
));
377 if (portSet
->used
>= portSet
->size
) {
379 portSet
->handles
= (HANDLE
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
381 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
) {
382 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
384 portSet
->handles
[portSet
->used
++] = port
;
385 __CFUnlock(&(portSet
->lock
));
389 static kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
394 __CFLock(&(portSet
->lock
));
395 for (i
= 0; i
< portSet
->used
; i
++) {
396 if (portSet
->handles
[i
] == port
) {
397 for (j
= i
+1; j
< portSet
->used
; j
++) {
398 portSet
->handles
[j
-1] = portSet
->handles
[j
];
401 __CFUnlock(&(portSet
->lock
));
405 __CFUnlock(&(portSet
->lock
));
411 #if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H)
412 #if defined(__BIG_ENDIAN__)
413 typedef struct UnsignedWide
{
417 #elif defined(__LITTLE_ENDIAN__)
418 typedef struct UnsignedWide
{
423 typedef UnsignedWide AbsoluteTime
;
426 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
428 #if USE_DISPATCH_SOURCE_FOR_TIMERS
431 extern mach_port_name_t
mk_timer_create(void);
432 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
433 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
434 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
436 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(uint64_t x
) {
439 a
.lo
= x
& (uint64_t)0xFFFFFFFF;
444 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
445 kern_return_t result
;
446 mach_msg_header_t header
;
447 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
448 header
.msgh_size
= sizeof(mach_msg_header_t
);
449 header
.msgh_remote_port
= port
;
450 header
.msgh_local_port
= MACH_PORT_NULL
;
451 header
.msgh_id
= msg_id
;
452 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
453 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
456 #elif DEPLOYMENT_TARGET_WINDOWS
458 static HANDLE
mk_timer_create(void) {
459 return CreateWaitableTimer(NULL
, FALSE
, NULL
);
462 static kern_return_t
mk_timer_destroy(HANDLE name
) {
463 BOOL res
= CloseHandle(name
);
465 DWORD err
= GetLastError();
466 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to destroy timer: %d"), err
);
471 static kern_return_t
mk_timer_arm(HANDLE name
, LARGE_INTEGER expire_time
) {
472 BOOL res
= SetWaitableTimer(name
, &expire_time
, 0, NULL
, NULL
, FALSE
);
474 DWORD err
= GetLastError();
475 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to set timer: %d"), err
);
480 static kern_return_t
mk_timer_cancel(HANDLE name
, LARGE_INTEGER
*result_time
) {
481 BOOL res
= CancelWaitableTimer(name
);
483 DWORD err
= GetLastError();
484 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to cancel timer: %d"), err
);
489 // 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.
490 CF_INLINE LARGE_INTEGER
__CFUInt64ToAbsoluteTime(uint64_t desiredFireTime
) {
491 LARGE_INTEGER result
;
492 // 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.
493 uint64_t now
= mach_absolute_time();
494 if (now
> desiredFireTime
) {
497 uint64_t timeDiff
= desiredFireTime
- now
;
498 CFTimeInterval amountOfTimeToWait
= __CFTSRToTimeInterval(timeDiff
);
499 // Result is in 100 ns (10**-7 sec) units to be consistent with a FILETIME.
500 // CFTimeInterval is in seconds.
501 result
.QuadPart
= -(amountOfTimeToWait
* 10000000);
511 /* unlock a run loop and modes before doing callouts/sleeping */
512 /* never try to take the run loop lock with a mode locked */
513 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
514 /* run loop mode structures should never be deallocated, even if they become empty */
516 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
517 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
518 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
519 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
520 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
522 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
524 struct __CFRunLoopMode
{
526 pthread_mutex_t _lock
; /* must have the run loop locked before locking this */
530 CFMutableSetRef _sources0
;
531 CFMutableSetRef _sources1
;
532 CFMutableArrayRef _observers
;
533 CFMutableArrayRef _timers
;
534 CFMutableDictionaryRef _portToV1SourceMap
;
535 __CFPortSet _portSet
;
536 CFIndex _observerMask
;
537 #if USE_DISPATCH_SOURCE_FOR_TIMERS
538 dispatch_source_t _timerSource
;
539 dispatch_queue_t _queue
;
540 Boolean _timerFired
; // set to true by the source when a timer has fired
541 Boolean _dispatchTimerArmed
;
544 mach_port_t _timerPort
;
545 Boolean _mkTimerArmed
;
547 #if DEPLOYMENT_TARGET_WINDOWS
549 void (*_msgPump
)(void);
551 uint64_t _timerSoftDeadline
; /* TSR */
552 uint64_t _timerHardDeadline
; /* TSR */
555 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
556 pthread_mutex_lock(&(rlm
->_lock
));
557 //CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm);
560 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
561 //CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm);
562 pthread_mutex_unlock(&(rlm
->_lock
));
565 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
566 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
567 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
568 return CFEqual(rlm1
->_name
, rlm2
->_name
);
571 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
572 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
573 return CFHash(rlm
->_name
);
576 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
577 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
578 CFMutableStringRef result
;
579 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
580 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
);
581 CFStringAppendFormat(result
, NULL
, CFSTR("port set = 0x%x, "), rlm
->_portSet
);
582 #if USE_DISPATCH_SOURCE_FOR_TIMERS
583 CFStringAppendFormat(result
, NULL
, CFSTR("queue = %p, "), rlm
->_queue
);
584 CFStringAppendFormat(result
, NULL
, CFSTR("source = %p (%s), "), rlm
->_timerSource
, rlm
->_timerFired
? "fired" : "not fired");
587 CFStringAppendFormat(result
, NULL
, CFSTR("timer port = 0x%x, "), rlm
->_timerPort
);
589 #if DEPLOYMENT_TARGET_WINDOWS
590 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p, "), rlm
->_msgQMask
);
592 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources0 = %@,\n\tsources1 = %@,\n\tobservers = %@,\n\ttimers = %@,\n\tcurrently %0.09g (%lld) / soft deadline in: %0.09g sec (@ %lld) / hard deadline in: %0.09g sec (@ %lld)\n},\n"), rlm
->_sources0
, rlm
->_sources1
, rlm
->_observers
, rlm
->_timers
, CFAbsoluteTimeGetCurrent(), mach_absolute_time(), __CFTSRToTimeInterval(rlm
->_timerSoftDeadline
- mach_absolute_time()), rlm
->_timerSoftDeadline
, __CFTSRToTimeInterval(rlm
->_timerHardDeadline
- mach_absolute_time()), rlm
->_timerHardDeadline
);
596 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
597 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
598 if (NULL
!= rlm
->_sources0
) CFRelease(rlm
->_sources0
);
599 if (NULL
!= rlm
->_sources1
) CFRelease(rlm
->_sources1
);
600 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
601 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
602 if (NULL
!= rlm
->_portToV1SourceMap
) CFRelease(rlm
->_portToV1SourceMap
);
603 CFRelease(rlm
->_name
);
604 __CFPortSetFree(rlm
->_portSet
);
605 #if USE_DISPATCH_SOURCE_FOR_TIMERS
606 if (rlm
->_timerSource
) {
607 dispatch_source_cancel(rlm
->_timerSource
);
608 dispatch_release(rlm
->_timerSource
);
611 dispatch_release(rlm
->_queue
);
615 if (MACH_PORT_NULL
!= rlm
->_timerPort
) mk_timer_destroy(rlm
->_timerPort
);
617 pthread_mutex_destroy(&rlm
->_lock
);
618 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x7C, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
));
622 #pragma mark Run Loops
625 struct _block_item
*_next
;
626 CFTypeRef _mode
; // CFString or CFSet
627 void (^_block
)(void);
630 typedef struct _per_run_data
{
634 uint32_t ignoreWakeUps
;
639 pthread_mutex_t _lock
; /* locked for accessing mode list */
640 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
642 volatile _per_run_data
*_perRunData
; // reset for runs of the run loop
645 CFMutableSetRef _commonModes
;
646 CFMutableSetRef _commonModeItems
;
647 CFRunLoopModeRef _currentMode
;
648 CFMutableSetRef _modes
;
649 struct _block_item
*_blocks_head
;
650 struct _block_item
*_blocks_tail
;
651 CFAbsoluteTime _runTime
;
652 CFAbsoluteTime _sleepTime
;
653 CFTypeRef _counterpart
;
656 /* Bit 0 of the base reserved bits is used for stopped state */
657 /* Bit 1 of the base reserved bits is used for sleeping state */
658 /* Bit 2 of the base reserved bits is used for deallocating state */
660 CF_INLINE
volatile _per_run_data
*__CFRunLoopPushPerRunData(CFRunLoopRef rl
) {
661 volatile _per_run_data
*previous
= rl
->_perRunData
;
662 rl
->_perRunData
= (volatile _per_run_data
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(_per_run_data
), 0);
663 rl
->_perRunData
->a
= 0x4346524C;
664 rl
->_perRunData
->b
= 0x4346524C; // 'CFRL'
665 rl
->_perRunData
->stopped
= 0x00000000;
666 rl
->_perRunData
->ignoreWakeUps
= 0x00000000;
670 CF_INLINE
void __CFRunLoopPopPerRunData(CFRunLoopRef rl
, volatile _per_run_data
*previous
) {
671 if (rl
->_perRunData
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (void *)rl
->_perRunData
);
672 rl
->_perRunData
= previous
;
675 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
676 return (rl
->_perRunData
->stopped
) ? true : false;
679 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
680 rl
->_perRunData
->stopped
= 0x53544F50; // 'STOP'
683 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
684 rl
->_perRunData
->stopped
= 0x0;
687 CF_INLINE Boolean
__CFRunLoopIsIgnoringWakeUps(CFRunLoopRef rl
) {
688 return (rl
->_perRunData
->ignoreWakeUps
) ? true : false;
691 CF_INLINE
void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl
) {
692 rl
->_perRunData
->ignoreWakeUps
= 0x57414B45; // 'WAKE'
695 CF_INLINE
void __CFRunLoopUnsetIgnoreWakeUps(CFRunLoopRef rl
) {
696 rl
->_perRunData
->ignoreWakeUps
= 0x0;
699 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
700 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
703 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
704 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
707 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
708 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
711 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
712 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
715 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
716 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
719 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
720 pthread_mutex_lock(&(((CFRunLoopRef
)rl
)->_lock
));
721 // CFLog(6, CFSTR("__CFRunLoopLock locked %p"), rl);
724 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
725 // CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl);
726 pthread_mutex_unlock(&(((CFRunLoopRef
)rl
)->_lock
));
729 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
730 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
731 CFMutableStringRef result
;
732 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
733 #if DEPLOYMENT_TARGET_WINDOWS
734 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)"));
736 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)"));
738 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
742 CF_PRIVATE
void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
743 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
746 CF_INLINE
void __CFRunLoopLockInit(pthread_mutex_t
*lock
) {
747 pthread_mutexattr_t mattr
;
748 pthread_mutexattr_init(&mattr
);
749 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_RECURSIVE
);
750 int32_t mret
= pthread_mutex_init(lock
, &mattr
);
751 pthread_mutexattr_destroy(&mattr
);
756 /* call with rl locked, returns mode locked */
757 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
759 CFRunLoopModeRef rlm
;
760 struct __CFRunLoopMode srlm
;
761 memset(&srlm
, 0, sizeof(srlm
));
762 _CFRuntimeSetInstanceTypeIDAndIsa(&srlm
, __kCFRunLoopModeTypeID
);
763 srlm
._name
= modeName
;
764 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
766 __CFRunLoopModeLock(rlm
);
772 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
776 __CFRunLoopLockInit(&rlm
->_lock
);
777 rlm
->_name
= CFStringCreateCopy(kCFAllocatorSystemDefault
, modeName
);
778 rlm
->_stopped
= false;
779 rlm
->_portToV1SourceMap
= NULL
;
780 rlm
->_sources0
= NULL
;
781 rlm
->_sources1
= NULL
;
782 rlm
->_observers
= NULL
;
784 rlm
->_observerMask
= 0;
785 rlm
->_portSet
= __CFPortSetAllocate();
786 rlm
->_timerSoftDeadline
= UINT64_MAX
;
787 rlm
->_timerHardDeadline
= UINT64_MAX
;
789 kern_return_t ret
= KERN_SUCCESS
;
790 #if USE_DISPATCH_SOURCE_FOR_TIMERS
791 rlm
->_timerFired
= false;
792 rlm
->_queue
= _dispatch_runloop_root_queue_create_4CF("Run Loop Mode Queue", 0);
793 mach_port_t queuePort
= _dispatch_runloop_root_queue_get_port_4CF(rlm
->_queue
);
794 if (queuePort
== MACH_PORT_NULL
) CRASH("*** Unable to create run loop mode queue port. (%d) ***", -1);
795 rlm
->_timerSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, rlm
->_queue
);
797 __block Boolean
*timerFiredPointer
= &(rlm
->_timerFired
);
798 dispatch_source_set_event_handler(rlm
->_timerSource
, ^{
799 *timerFiredPointer
= true;
802 // Set timer to far out there. The unique leeway makes this timer easy to spot in debug output.
803 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, DISPATCH_TIME_FOREVER
, DISPATCH_TIME_FOREVER
, 321);
804 dispatch_resume(rlm
->_timerSource
);
806 ret
= __CFPortSetInsert(queuePort
, rlm
->_portSet
);
807 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret
);
811 rlm
->_timerPort
= mk_timer_create();
812 ret
= __CFPortSetInsert(rlm
->_timerPort
, rlm
->_portSet
);
813 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret
);
816 ret
= __CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
);
817 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret
);
819 #if DEPLOYMENT_TARGET_WINDOWS
821 rlm
->_msgPump
= NULL
;
823 CFSetAddValue(rl
->_modes
, rlm
);
825 __CFRunLoopModeLock(rlm
); /* return mode locked */
830 // expects rl and rlm locked
831 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopModeRef previousMode
) {
833 if (NULL
== rlm
) return true;
834 #if DEPLOYMENT_TARGET_WINDOWS
835 if (0 != rlm
->_msgQMask
) return false;
837 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
838 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) return false; // represents the libdispatch main queue
839 if (NULL
!= rlm
->_sources0
&& 0 < CFSetGetCount(rlm
->_sources0
)) return false;
840 if (NULL
!= rlm
->_sources1
&& 0 < CFSetGetCount(rlm
->_sources1
)) return false;
841 if (NULL
!= rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) return false;
842 struct _block_item
*item
= rl
->_blocks_head
;
844 struct _block_item
*curr
= item
;
846 Boolean doit
= false;
847 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
848 doit
= CFEqual(curr
->_mode
, rlm
->_name
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
850 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, rlm
->_name
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
852 if (doit
) return false;
857 #if DEPLOYMENT_TARGET_WINDOWS
859 uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
860 if (modeName
== kCFRunLoopCommonModes
) {
861 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
866 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
868 result
= rlm
->_msgQMask
;
869 __CFRunLoopModeUnlock(rlm
);
871 __CFRunLoopUnlock(rl
);
872 return (uint32_t)result
;
875 void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, uint32_t mask
, CFStringRef modeName
) {
876 if (modeName
== kCFRunLoopCommonModes
) {
877 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
881 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
882 rlm
->_msgQMask
= (DWORD
)mask
;
883 __CFRunLoopModeUnlock(rlm
);
884 __CFRunLoopUnlock(rl
);
887 uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl
) {
888 return rl
->_winthread
;
891 CFWindowsMessageQueueHandler
_CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
) {
892 if (modeName
== kCFRunLoopCommonModes
) {
893 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
896 if (rl
!= CFRunLoopGetCurrent()) {
897 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
900 void (*result
)(void) = NULL
;
902 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
904 result
= rlm
->_msgPump
;
905 __CFRunLoopModeUnlock(rlm
);
907 __CFRunLoopUnlock(rl
);
911 void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
, CFWindowsMessageQueueHandler func
) {
912 if (modeName
== kCFRunLoopCommonModes
) {
913 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
916 if (rl
!= CFRunLoopGetCurrent()) {
917 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
921 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
922 rlm
->_msgPump
= func
;
923 __CFRunLoopModeUnlock(rlm
);
924 __CFRunLoopUnlock(rl
);
932 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
934 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
935 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
938 CF_INLINE
void __CFSetValid(void *cf
) {
939 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
942 CF_INLINE
void __CFUnsetValid(void *cf
) {
943 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
946 struct __CFRunLoopSource
{
949 pthread_mutex_t _lock
;
950 CFIndex _order
; /* immutable */
951 CFMutableBagRef _runLoops
;
953 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
954 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
958 /* Bit 1 of the base reserved bits is used for signalled state */
960 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
961 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
964 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
965 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
968 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
969 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
972 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
973 pthread_mutex_lock(&(rls
->_lock
));
974 // CFLog(6, CFSTR("__CFRunLoopSourceLock locked %p"), rls);
977 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
978 // CFLog(6, CFSTR("__CFRunLoopSourceLock unlocking %p"), rls);
979 pthread_mutex_unlock(&(rls
->_lock
));
982 #pragma mark Observers
984 struct __CFRunLoopObserver
{
986 pthread_mutex_t _lock
;
987 CFRunLoopRef _runLoop
;
989 CFOptionFlags _activities
; /* immutable */
990 CFIndex _order
; /* immutable */
991 CFRunLoopObserverCallBack _callout
; /* immutable */
992 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
995 /* Bit 0 of the base reserved bits is used for firing state */
996 /* Bit 1 of the base reserved bits is used for repeats state */
998 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
999 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
1002 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
1003 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
1006 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
1007 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
1010 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
1011 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
1014 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
1015 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
1018 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
1019 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
1022 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
1023 pthread_mutex_lock(&(rlo
->_lock
));
1024 // CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo);
1027 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
1028 // CFLog(6, CFSTR("__CFRunLoopObserverLock unlocking %p"), rlo);
1029 pthread_mutex_unlock(&(rlo
->_lock
));
1032 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1033 __CFRunLoopObserverLock(rlo
);
1034 if (0 == rlo
->_rlCount
) {
1038 __CFRunLoopObserverUnlock(rlo
);
1041 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1042 __CFRunLoopObserverLock(rlo
);
1044 if (0 == rlo
->_rlCount
) {
1045 rlo
->_runLoop
= NULL
;
1047 __CFRunLoopObserverUnlock(rlo
);
1052 struct __CFRunLoopTimer
{
1053 CFRuntimeBase _base
;
1055 pthread_mutex_t _lock
;
1056 CFRunLoopRef _runLoop
;
1057 CFMutableSetRef _rlModes
;
1058 CFAbsoluteTime _nextFireDate
;
1059 CFTimeInterval _interval
; /* immutable */
1060 CFTimeInterval _tolerance
; /* mutable */
1061 uint64_t _fireTSR
; /* TSR units */
1062 CFIndex _order
; /* immutable */
1063 CFRunLoopTimerCallBack _callout
; /* immutable */
1064 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
1067 /* Bit 0 of the base reserved bits is used for firing state */
1068 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
1069 /* Bit 2 of the base reserved bits is used for waking state */
1071 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
1072 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 0, 0);
1075 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
1076 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 1);
1079 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
1080 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 0);
1083 CF_INLINE Boolean
__CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt
) {
1084 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 2, 2);
1087 CF_INLINE
void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt
) {
1088 __CFBitfieldSetValue(rlt
->_bits
, 2, 2, 1);
1091 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
1092 pthread_mutex_lock(&(rlt
->_lock
));
1093 // CFLog(6, CFSTR("__CFRunLoopTimerLock locked %p"), rlt);
1096 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
1097 // CFLog(6, CFSTR("__CFRunLoopTimerLock unlocking %p"), rlt);
1098 pthread_mutex_unlock(&(rlt
->_lock
));
1101 static CFLock_t __CFRLTFireTSRLock
= CFLockInit
;
1103 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
1104 __CFLock(&__CFRLTFireTSRLock
);
1107 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
1108 __CFUnlock(&__CFRLTFireTSRLock
);
1115 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
1116 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
1118 // call with rl and rlm locked
1119 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
1121 CFRunLoopSourceRef found
= rlm
->_portToV1SourceMap
? (CFRunLoopSourceRef
)CFDictionaryGetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)port
) : NULL
;
1125 // Remove backreferences the mode's sources have to the rl (context);
1126 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1127 // the source from the run loops it is in, but during deallocation of a
1128 // run loop, we already know that the sources are going to be punted
1129 // from it, so invalidation of sources does not need to remove from a
1130 // deallocating run loop.
1131 static void __CFRunLoopCleanseSources(const void *value
, void *context
) {
1132 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1133 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1135 const void **list
, *buffer
[256];
1136 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1138 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1139 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1140 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1141 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1142 for (idx
= 0; idx
< cnt
; idx
++) {
1143 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1144 __CFRunLoopSourceLock(rls
);
1145 if (NULL
!= rls
->_runLoops
) {
1146 CFBagRemoveValue(rls
->_runLoops
, rl
);
1148 __CFRunLoopSourceUnlock(rls
);
1150 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1153 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
1154 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1155 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1157 const void **list
, *buffer
[256];
1158 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1160 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1161 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1162 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1163 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1164 for (idx
= 0; idx
< cnt
; idx
++) {
1165 CFRetain(list
[idx
]);
1167 if (rlm
->_sources0
) CFSetRemoveAllValues(rlm
->_sources0
);
1168 if (rlm
->_sources1
) CFSetRemoveAllValues(rlm
->_sources1
);
1169 for (idx
= 0; idx
< cnt
; idx
++) {
1170 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1171 __CFRunLoopSourceLock(rls
);
1172 if (NULL
!= rls
->_runLoops
) {
1173 CFBagRemoveValue(rls
->_runLoops
, rl
);
1175 __CFRunLoopSourceUnlock(rls
);
1176 if (0 == rls
->_context
.version0
.version
) {
1177 if (NULL
!= rls
->_context
.version0
.cancel
) {
1178 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
1180 } else if (1 == rls
->_context
.version0
.version
) {
1181 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1182 if (CFPORT_NULL
!= port
) {
1183 __CFPortSetRemove(port
, rlm
->_portSet
);
1188 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1191 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
1192 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1193 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1195 const void **list
, *buffer
[256];
1196 if (NULL
== rlm
->_observers
) return;
1197 cnt
= CFArrayGetCount(rlm
->_observers
);
1198 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1199 CFArrayGetValues(rlm
->_observers
, CFRangeMake(0, cnt
), list
);
1200 for (idx
= 0; idx
< cnt
; idx
++) {
1201 CFRetain(list
[idx
]);
1203 CFArrayRemoveAllValues(rlm
->_observers
);
1204 for (idx
= 0; idx
< cnt
; idx
++) {
1205 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
1206 CFRelease(list
[idx
]);
1208 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1211 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
1212 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1213 if (NULL
== rlm
->_timers
) return;
1214 void (^deallocateTimers
)(CFMutableArrayRef timers
) = ^(CFMutableArrayRef timers
) {
1216 const void **list
, *buffer
[256];
1217 cnt
= CFArrayGetCount(timers
);
1218 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1219 CFArrayGetValues(timers
, CFRangeMake(0, CFArrayGetCount(timers
)), list
);
1220 for (idx
= 0; idx
< cnt
; idx
++) {
1221 CFRetain(list
[idx
]);
1223 CFArrayRemoveAllValues(timers
);
1224 for (idx
= 0; idx
< cnt
; idx
++) {
1225 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1226 __CFRunLoopTimerLock(rlt
);
1227 // if the run loop is deallocating, and since a timer can only be in one
1228 // run loop, we're going to be removing the timer from all modes, so be
1229 // a little heavy-handed and direct
1230 CFSetRemoveAllValues(rlt
->_rlModes
);
1231 rlt
->_runLoop
= NULL
;
1232 __CFRunLoopTimerUnlock(rlt
);
1233 CFRelease(list
[idx
]);
1235 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1238 if (rlm
->_timers
&& CFArrayGetCount(rlm
->_timers
)) deallocateTimers(rlm
->_timers
);
1241 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
);
1243 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
1244 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
1246 if (_CFRunLoopGet0b(pthread_main_thread_np()) == cf
) HALT
;
1248 /* We try to keep the run loop in a valid state as long as possible,
1249 since sources may have non-retained references to the run loop.
1250 Another reason is that we don't want to lock the run loop for
1251 callback reasons, if we can get away without that. We start by
1252 eliminating the sources, since they are the most likely to call
1253 back into the run loop during their "cancellation". Common mode
1254 items will be removed from the mode indirectly by the following
1256 __CFRunLoopSetDeallocating(rl
);
1257 if (NULL
!= rl
->_modes
) {
1258 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopCleanseSources
), rl
); // remove references to rl
1259 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
1260 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
1261 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
1263 __CFRunLoopLock(rl
);
1264 struct _block_item
*item
= rl
->_blocks_head
;
1266 struct _block_item
*curr
= item
;
1268 CFRelease(curr
->_mode
);
1269 Block_release(curr
->_block
);
1272 if (NULL
!= rl
->_commonModeItems
) {
1273 CFRelease(rl
->_commonModeItems
);
1275 if (NULL
!= rl
->_commonModes
) {
1276 CFRelease(rl
->_commonModes
);
1278 if (NULL
!= rl
->_modes
) {
1279 CFRelease(rl
->_modes
);
1281 __CFPortFree(rl
->_wakeUpPort
);
1282 rl
->_wakeUpPort
= CFPORT_NULL
;
1283 __CFRunLoopPopPerRunData(rl
, NULL
);
1284 __CFRunLoopUnlock(rl
);
1285 pthread_mutex_destroy(&rl
->_lock
);
1286 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x8C, sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
));
1289 static const CFRuntimeClass __CFRunLoopModeClass
= {
1294 __CFRunLoopModeDeallocate
,
1295 __CFRunLoopModeEqual
,
1296 __CFRunLoopModeHash
,
1298 __CFRunLoopModeCopyDescription
1301 static const CFRuntimeClass __CFRunLoopClass
= {
1306 __CFRunLoopDeallocate
,
1310 __CFRunLoopCopyDescription
1313 CF_PRIVATE
void __CFFinalizeRunLoop(uintptr_t data
);
1315 CFTypeID
CFRunLoopGetTypeID(void) {
1316 static dispatch_once_t initOnce
;
1317 dispatch_once(&initOnce
, ^{ __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
); __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
); });
1318 return __kCFRunLoopTypeID
;
1321 static CFRunLoopRef
__CFRunLoopCreate(pthread_t t
) {
1322 CFRunLoopRef loop
= NULL
;
1323 CFRunLoopModeRef rlm
;
1324 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
1325 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, CFRunLoopGetTypeID(), size
, NULL
);
1329 (void)__CFRunLoopPushPerRunData(loop
);
1330 __CFRunLoopLockInit(&loop
->_lock
);
1331 loop
->_wakeUpPort
= __CFPortAllocate();
1332 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
1333 __CFRunLoopSetIgnoreWakeUps(loop
);
1334 loop
->_commonModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1335 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
1336 loop
->_commonModeItems
= NULL
;
1337 loop
->_currentMode
= NULL
;
1338 loop
->_modes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
1339 loop
->_blocks_head
= NULL
;
1340 loop
->_blocks_tail
= NULL
;
1341 loop
->_counterpart
= NULL
;
1343 #if DEPLOYMENT_TARGET_WINDOWS
1344 loop
->_winthread
= GetCurrentThreadId();
1346 loop
->_winthread
= 0;
1348 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
1349 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
1353 static CFMutableDictionaryRef __CFRunLoops
= NULL
;
1354 static CFLock_t loopsLock
= CFLockInit
;
1356 // should only be called by Foundation
1357 // t==0 is a synonym for "main thread" that always works
1358 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0(pthread_t t
) {
1359 if (pthread_equal(t
, kNilPthreadT
)) {
1360 t
= pthread_main_thread_np();
1362 __CFLock(&loopsLock
);
1363 if (!__CFRunLoops
) {
1364 __CFUnlock(&loopsLock
);
1365 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
1366 CFRunLoopRef mainLoop
= __CFRunLoopCreate(pthread_main_thread_np());
1367 CFDictionarySetValue(dict
, pthreadPointer(pthread_main_thread_np()), mainLoop
);
1368 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, dict
, (void * volatile *)&__CFRunLoops
)) {
1371 CFRelease(mainLoop
);
1372 __CFLock(&loopsLock
);
1374 CFRunLoopRef loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1375 __CFUnlock(&loopsLock
);
1377 CFRunLoopRef newLoop
= __CFRunLoopCreate(t
);
1378 __CFLock(&loopsLock
);
1379 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1381 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(t
), newLoop
);
1384 // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
1385 __CFUnlock(&loopsLock
);
1388 if (pthread_equal(t
, pthread_self())) {
1389 _CFSetTSD(__CFTSDKeyRunLoop
, (void *)loop
, NULL
);
1390 if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr
)) {
1391 _CFSetTSD(__CFTSDKeyRunLoopCntr
, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS
-1), (void (*)(void *))__CFFinalizeRunLoop
);
1397 // should only be called by Foundation
1398 CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
) {
1399 if (pthread_equal(t
, kNilPthreadT
)) {
1400 t
= pthread_main_thread_np();
1402 __CFLock(&loopsLock
);
1403 CFRunLoopRef loop
= NULL
;
1405 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1407 __CFUnlock(&loopsLock
);
1411 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
);
1413 // Called for each thread as it exits
1414 CF_PRIVATE
void __CFFinalizeRunLoop(uintptr_t data
) {
1415 CFRunLoopRef rl
= NULL
;
1417 __CFLock(&loopsLock
);
1419 rl
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1420 if (rl
) CFRetain(rl
);
1421 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1423 __CFUnlock(&loopsLock
);
1425 _CFSetTSD(__CFTSDKeyRunLoopCntr
, (void *)(data
- 1), (void (*)(void *))__CFFinalizeRunLoop
);
1427 if (rl
&& CFRunLoopGetMain() != rl
) { // protect against cooperative threads
1428 if (NULL
!= rl
->_counterpart
) {
1429 CFRelease(rl
->_counterpart
);
1430 rl
->_counterpart
= NULL
;
1432 // purge all sources before deallocation
1433 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
1434 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
1435 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
1436 __CFRunLoopRemoveAllSources(rl
, modeName
);
1438 __CFRunLoopRemoveAllSources(rl
, kCFRunLoopCommonModes
);
1441 if (rl
) CFRelease(rl
);
1444 pthread_t
_CFRunLoopGet1(CFRunLoopRef rl
) {
1445 return rl
->_pthread
;
1448 // should only be called by Foundation
1449 CF_EXPORT CFTypeRef
_CFRunLoopGet2(CFRunLoopRef rl
) {
1450 CFTypeRef ret
= NULL
;
1451 __CFLock(&loopsLock
);
1452 ret
= rl
->_counterpart
;
1453 __CFUnlock(&loopsLock
);
1457 // should only be called by Foundation
1458 CF_EXPORT CFTypeRef
_CFRunLoopGet2b(CFRunLoopRef rl
) {
1459 return rl
->_counterpart
;
1462 #if DEPLOYMENT_TARGET_MACOSX
1463 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1464 if (pthread_main_np()) return;
1465 CFRunLoopRef currentLoop
= CFRunLoopGetCurrent();
1466 if (rl
!= currentLoop
) {
1467 CFRetain(currentLoop
); // avoid a deallocation of the currentLoop inside the lock
1468 __CFLock(&loopsLock
);
1470 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(pthread_self()), rl
);
1472 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1474 __CFUnlock(&loopsLock
);
1475 CFRelease(currentLoop
);
1476 _CFSetTSD(__CFTSDKeyRunLoop
, NULL
, NULL
);
1477 _CFSetTSD(__CFTSDKeyRunLoopCntr
, 0, (void (*)(void *))__CFFinalizeRunLoop
);
1482 CFRunLoopRef
CFRunLoopGetMain(void) {
1484 static CFRunLoopRef __main
= NULL
; // no retain needed
1485 if (!__main
) __main
= _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
1489 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1491 CFRunLoopRef rl
= (CFRunLoopRef
)_CFGetTSD(__CFTSDKeyRunLoop
);
1493 return _CFRunLoopGet0(pthread_self());
1496 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1498 CFStringRef result
= NULL
;
1499 __CFRunLoopLock(rl
);
1500 if (NULL
!= rl
->_currentMode
) {
1501 result
= (CFStringRef
)CFRetain(rl
->_currentMode
->_name
);
1503 __CFRunLoopUnlock(rl
);
1507 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1508 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1509 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1510 CFArrayAppendValue(array
, rlm
->_name
);
1513 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1515 CFMutableArrayRef array
;
1516 __CFRunLoopLock(rl
);
1517 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1518 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1519 __CFRunLoopUnlock(rl
);
1523 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1524 CFTypeRef item
= (CFTypeRef
)value
;
1525 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1526 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1527 if (CFGetTypeID(item
) == CFRunLoopSourceGetTypeID()) {
1528 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1529 } else if (CFGetTypeID(item
) == CFRunLoopObserverGetTypeID()) {
1530 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1531 } else if (CFGetTypeID(item
) == CFRunLoopTimerGetTypeID()) {
1532 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1536 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1537 CFStringRef modeName
= (CFStringRef
)value
;
1538 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1539 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1540 if (CFGetTypeID(item
) == CFRunLoopSourceGetTypeID()) {
1541 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1542 } else if (CFGetTypeID(item
) == CFRunLoopObserverGetTypeID()) {
1543 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1544 } else if (CFGetTypeID(item
) == CFRunLoopTimerGetTypeID()) {
1545 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1549 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1550 CFStringRef modeName
= (CFStringRef
)value
;
1551 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1552 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1553 if (CFGetTypeID(item
) == CFRunLoopSourceGetTypeID()) {
1554 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1555 } else if (CFGetTypeID(item
) == CFRunLoopObserverGetTypeID()) {
1556 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1557 } else if (CFGetTypeID(item
) == CFRunLoopTimerGetTypeID()) {
1558 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1562 CF_EXPORT Boolean
_CFRunLoop01(CFRunLoopRef rl
, CFStringRef modeName
) {
1563 __CFRunLoopLock(rl
);
1564 Boolean present
= CFSetContainsValue(rl
->_commonModes
, modeName
);
1565 __CFRunLoopUnlock(rl
);
1569 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1571 if (__CFRunLoopIsDeallocating(rl
)) return;
1572 __CFRunLoopLock(rl
);
1573 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1574 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1575 CFSetAddValue(rl
->_commonModes
, modeName
);
1577 CFTypeRef context
[2] = {rl
, modeName
};
1578 /* add all common-modes items to new mode */
1579 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1584 __CFRunLoopUnlock(rl
);
1588 static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() __attribute__((noinline
));
1589 static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(void *msg
) {
1590 _dispatch_main_queue_callback_4CF(msg
);
1591 asm __volatile__(""); // thwart tail-call optimization
1594 static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline
));
1595 static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func
, CFRunLoopObserverRef observer
, CFRunLoopActivity activity
, void *info
) {
1597 func(observer
, activity
, info
);
1599 asm __volatile__(""); // thwart tail-call optimization
1602 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline
));
1603 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func
, CFRunLoopTimerRef timer
, void *info
) {
1607 asm __volatile__(""); // thwart tail-call optimization
1610 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline
));
1611 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block
)(void)) {
1615 asm __volatile__(""); // thwart tail-call optimization
1618 static Boolean
__CFRunLoopDoBlocks(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { // Call with rl and rlm locked
1619 if (!rl
->_blocks_head
) return false;
1620 if (!rlm
|| !rlm
->_name
) return false;
1621 Boolean did
= false;
1622 struct _block_item
*head
= rl
->_blocks_head
;
1623 struct _block_item
*tail
= rl
->_blocks_tail
;
1624 rl
->_blocks_head
= NULL
;
1625 rl
->_blocks_tail
= NULL
;
1626 CFSetRef commonModes
= rl
->_commonModes
;
1627 CFStringRef curMode
= rlm
->_name
;
1628 __CFRunLoopModeUnlock(rlm
);
1629 __CFRunLoopUnlock(rl
);
1630 struct _block_item
*prev
= NULL
;
1631 struct _block_item
*item
= head
;
1633 struct _block_item
*curr
= item
;
1635 Boolean doit
= false;
1636 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
1637 doit
= CFEqual(curr
->_mode
, curMode
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1639 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, curMode
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(commonModes
, curMode
));
1641 if (!doit
) prev
= curr
;
1643 if (prev
) prev
->_next
= item
;
1644 if (curr
== head
) head
= item
;
1645 if (curr
== tail
) tail
= prev
;
1646 void (^block
)(void) = curr
->_block
;
1647 CFRelease(curr
->_mode
);
1650 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block
);
1653 Block_release(block
); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1656 __CFRunLoopLock(rl
);
1657 __CFRunLoopModeLock(rlm
);
1659 tail
->_next
= rl
->_blocks_head
;
1660 rl
->_blocks_head
= head
;
1661 if (!rl
->_blocks_tail
) rl
->_blocks_tail
= tail
;
1666 /* rl is locked, rlm is locked on entrance and exit */
1667 static void __CFRunLoopDoObservers() __attribute__((noinline
));
1668 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1671 CFIndex cnt
= rlm
->_observers
? CFArrayGetCount(rlm
->_observers
) : 0;
1672 if (cnt
< 1) return;
1674 /* Fire the observers */
1675 STACK_BUFFER_DECL(CFRunLoopObserverRef
, buffer
, (cnt
<= 1024) ? cnt
: 1);
1676 CFRunLoopObserverRef
*collectedObservers
= (cnt
<= 1024) ? buffer
: (CFRunLoopObserverRef
*)malloc(cnt
* sizeof(CFRunLoopObserverRef
));
1677 CFIndex obs_cnt
= 0;
1678 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1679 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(rlm
->_observers
, idx
);
1680 if (0 != (rlo
->_activities
& activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1681 collectedObservers
[obs_cnt
++] = (CFRunLoopObserverRef
)CFRetain(rlo
);
1684 __CFRunLoopModeUnlock(rlm
);
1685 __CFRunLoopUnlock(rl
);
1686 for (CFIndex idx
= 0; idx
< obs_cnt
; idx
++) {
1687 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1688 __CFRunLoopObserverLock(rlo
);
1689 if (__CFIsValid(rlo
)) {
1690 Boolean doInvalidate
= !__CFRunLoopObserverRepeats(rlo
);
1691 __CFRunLoopObserverSetFiring(rlo
);
1692 __CFRunLoopObserverUnlock(rlo
);
1693 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo
->_callout
, rlo
, activity
, rlo
->_context
.info
);
1695 CFRunLoopObserverInvalidate(rlo
);
1697 __CFRunLoopObserverUnsetFiring(rlo
);
1699 __CFRunLoopObserverUnlock(rlo
);
1703 __CFRunLoopLock(rl
);
1704 __CFRunLoopModeLock(rlm
);
1706 if (collectedObservers
!= buffer
) free(collectedObservers
);
1709 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1710 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1711 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1712 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1713 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1714 return kCFCompareEqualTo
;
1717 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1718 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1719 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1720 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1721 if (NULL
== *sources
) {
1722 *sources
= CFRetain(rls
);
1723 } else if (CFGetTypeID(*sources
) == CFRunLoopSourceGetTypeID()) {
1724 CFTypeRef oldrls
= *sources
;
1725 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1726 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1727 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1730 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1735 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline
));
1736 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform
)(void *), void *info
) {
1740 asm __volatile__(""); // thwart tail-call optimization
1743 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline
));
1744 static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(
1745 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1746 void *(*perform
)(void *msg
, CFIndex size
, CFAllocatorRef allocator
, void *info
),
1747 mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
,
1749 void (*perform
)(void *),
1753 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1754 *reply
= perform(msg
, size
, kCFAllocatorSystemDefault
, info
);
1759 asm __volatile__(""); // thwart tail-call optimization
1762 /* rl is locked, rlm is locked on entrance and exit */
1763 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) __attribute__((noinline
));
1764 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1766 CFTypeRef sources
= NULL
;
1767 Boolean sourceHandled
= false;
1769 /* Fire the version 0 sources */
1770 if (NULL
!= rlm
->_sources0
&& 0 < CFSetGetCount(rlm
->_sources0
)) {
1771 CFSetApplyFunction(rlm
->_sources0
, (__CFRunLoopCollectSources0
), &sources
);
1773 if (NULL
!= sources
) {
1774 __CFRunLoopModeUnlock(rlm
);
1775 __CFRunLoopUnlock(rl
);
1776 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1777 if (CFGetTypeID(sources
) == CFRunLoopSourceGetTypeID()) {
1778 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1779 __CFRunLoopSourceLock(rls
);
1780 if (__CFRunLoopSourceIsSignaled(rls
)) {
1781 __CFRunLoopSourceUnsetSignaled(rls
);
1782 if (__CFIsValid(rls
)) {
1783 __CFRunLoopSourceUnlock(rls
);
1784 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls
->_context
.version0
.perform
, rls
->_context
.version0
.info
);
1786 sourceHandled
= true;
1788 __CFRunLoopSourceUnlock(rls
);
1791 __CFRunLoopSourceUnlock(rls
);
1794 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)sources
);
1795 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1796 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
1797 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex((CFArrayRef
)sources
, idx
);
1798 __CFRunLoopSourceLock(rls
);
1799 if (__CFRunLoopSourceIsSignaled(rls
)) {
1800 __CFRunLoopSourceUnsetSignaled(rls
);
1801 if (__CFIsValid(rls
)) {
1802 __CFRunLoopSourceUnlock(rls
);
1803 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls
->_context
.version0
.perform
, rls
->_context
.version0
.info
);
1805 sourceHandled
= true;
1807 __CFRunLoopSourceUnlock(rls
);
1810 __CFRunLoopSourceUnlock(rls
);
1812 if (stopAfterHandle
&& sourceHandled
) {
1818 __CFRunLoopLock(rl
);
1819 __CFRunLoopModeLock(rlm
);
1821 return sourceHandled
;
1824 CF_INLINE
void __CFRunLoopDebugInfoForRunLoopSource(CFRunLoopSourceRef rls
) {
1827 // msg, size and reply are unused on Windows
1828 static Boolean
__CFRunLoopDoSource1() __attribute__((noinline
));
1829 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1830 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1831 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1833 ) { /* DOES CALLOUT */
1835 Boolean sourceHandled
= false;
1837 /* Fire a version 1 source */
1839 __CFRunLoopModeUnlock(rlm
);
1840 __CFRunLoopUnlock(rl
);
1841 __CFRunLoopSourceLock(rls
);
1842 if (__CFIsValid(rls
)) {
1843 __CFRunLoopSourceUnsetSignaled(rls
);
1844 __CFRunLoopSourceUnlock(rls
);
1845 __CFRunLoopDebugInfoForRunLoopSource(rls
);
1846 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(rls
->_context
.version1
.perform
,
1847 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1850 rls
->_context
.version1
.info
);
1852 sourceHandled
= true;
1854 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1855 __CFRunLoopSourceUnlock(rls
);
1858 __CFRunLoopLock(rl
);
1859 __CFRunLoopModeLock(rlm
);
1860 return sourceHandled
;
1863 static CFIndex
__CFRunLoopInsertionIndexInTimerArray(CFArrayRef array
, CFRunLoopTimerRef rlt
) __attribute__((noinline
));
1864 static CFIndex
__CFRunLoopInsertionIndexInTimerArray(CFArrayRef array
, CFRunLoopTimerRef rlt
) {
1865 CFIndex cnt
= CFArrayGetCount(array
);
1870 CFRunLoopTimerRef item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, cnt
- 1);
1871 if (item
->_fireTSR
<= rlt
->_fireTSR
) {
1874 item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, 0);
1875 if (rlt
->_fireTSR
< item
->_fireTSR
) {
1880 CFIndex add
= (1 << flsl(cnt
)) * 2;
1882 Boolean lastTestLEQ
;
1885 lastTestLEQ
= false;
1886 CFIndex testIdx
= idx
+ add
;
1887 if (testIdx
< cnt
) {
1888 CFRunLoopTimerRef item
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(array
, testIdx
);
1889 if (item
->_fireTSR
<= rlt
->_fireTSR
) {
1896 return lastTestLEQ
? idx
+ 1 : idx
;
1899 static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm
, CFRunLoopRef rl
) {
1900 uint64_t nextHardDeadline
= UINT64_MAX
;
1901 uint64_t nextSoftDeadline
= UINT64_MAX
;
1904 // Look at the list of timers. We will calculate two TSR values; the next soft and next hard deadline.
1905 // The next soft deadline is the first time we can fire any timer. This is the fire date of the first timer in our sorted list of timers.
1906 // The next hard deadline is the last time at which we can fire the timer before we've moved out of the allowable tolerance of the timers in our list.
1907 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(rlm
->_timers
); idx
< cnt
; idx
++) {
1908 CFRunLoopTimerRef t
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, idx
);
1909 // discount timers currently firing
1910 if (__CFRunLoopTimerIsFiring(t
)) continue;
1912 int32_t err
= CHECKINT_NO_ERROR
;
1913 uint64_t oneTimerSoftDeadline
= t
->_fireTSR
;
1914 uint64_t oneTimerHardDeadline
= check_uint64_add(t
->_fireTSR
, __CFTimeIntervalToTSR(t
->_tolerance
), &err
);
1915 if (err
!= CHECKINT_NO_ERROR
) oneTimerHardDeadline
= UINT64_MAX
;
1917 // We can stop searching if the soft deadline for this timer exceeds the current hard deadline. Otherwise, later timers with lower tolerance could still have earlier hard deadlines.
1918 if (oneTimerSoftDeadline
> nextHardDeadline
) {
1922 if (oneTimerSoftDeadline
< nextSoftDeadline
) {
1923 nextSoftDeadline
= oneTimerSoftDeadline
;
1926 if (oneTimerHardDeadline
< nextHardDeadline
) {
1927 nextHardDeadline
= oneTimerHardDeadline
;
1931 if (nextSoftDeadline
< UINT64_MAX
&& (nextHardDeadline
!= rlm
->_timerHardDeadline
|| nextSoftDeadline
!= rlm
->_timerSoftDeadline
)) {
1932 if (CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED()) {
1933 CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline
- mach_absolute_time()));
1935 #if USE_DISPATCH_SOURCE_FOR_TIMERS
1936 // We're going to hand off the range of allowable timer fire date to dispatch and let it fire when appropriate for the system.
1937 uint64_t leeway
= __CFTSRToNanoseconds(nextHardDeadline
- nextSoftDeadline
);
1938 dispatch_time_t deadline
= __CFTSRToDispatchTime(nextSoftDeadline
);
1939 #if USE_MK_TIMER_TOO
1941 // Only use the dispatch timer if we have any leeway
1942 // <rdar://problem/14447675>
1944 // Cancel the mk timer
1945 if (rlm
->_mkTimerArmed
&& rlm
->_timerPort
) {
1947 mk_timer_cancel(rlm
->_timerPort
, &dummy
);
1948 rlm
->_mkTimerArmed
= false;
1951 // Arm the dispatch timer
1952 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, deadline
, DISPATCH_TIME_FOREVER
, leeway
);
1953 rlm
->_dispatchTimerArmed
= true;
1955 // Cancel the dispatch timer
1956 if (rlm
->_dispatchTimerArmed
) {
1957 // Cancel the dispatch timer
1958 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, DISPATCH_TIME_FOREVER
, DISPATCH_TIME_FOREVER
, 888);
1959 rlm
->_dispatchTimerArmed
= false;
1963 if (rlm
->_timerPort
) {
1964 mk_timer_arm(rlm
->_timerPort
, __CFUInt64ToAbsoluteTime(nextSoftDeadline
));
1965 rlm
->_mkTimerArmed
= true;
1969 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, deadline
, DISPATCH_TIME_FOREVER
, leeway
);
1972 if (rlm
->_timerPort
) {
1973 mk_timer_arm(rlm
->_timerPort
, __CFUInt64ToAbsoluteTime(nextSoftDeadline
));
1976 } else if (nextSoftDeadline
== UINT64_MAX
) {
1977 // Disarm the timers - there is no timer scheduled
1979 if (rlm
->_mkTimerArmed
&& rlm
->_timerPort
) {
1981 mk_timer_cancel(rlm
->_timerPort
, &dummy
);
1982 rlm
->_mkTimerArmed
= false;
1985 #if USE_DISPATCH_SOURCE_FOR_TIMERS
1986 if (rlm
->_dispatchTimerArmed
) {
1987 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, DISPATCH_TIME_FOREVER
, DISPATCH_TIME_FOREVER
, 333);
1988 rlm
->_dispatchTimerArmed
= false;
1993 rlm
->_timerHardDeadline
= nextHardDeadline
;
1994 rlm
->_timerSoftDeadline
= nextSoftDeadline
;
1997 // call with rlm and its run loop locked, and the TSRLock locked; rlt not locked; returns with same state
1998 static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
, Boolean isInArray
) __attribute__((noinline
));
1999 static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
, Boolean isInArray
) {
2002 CFMutableArrayRef timerArray
= rlm
->_timers
;
2003 if (!timerArray
) return;
2004 Boolean found
= false;
2006 // If we know in advance that the timer is not in the array (just being added now) then we can skip this search
2008 CFIndex idx
= CFArrayGetFirstIndexOfValue(timerArray
, CFRangeMake(0, CFArrayGetCount(timerArray
)), rlt
);
2009 if (kCFNotFound
!= idx
) {
2011 CFArrayRemoveValueAtIndex(timerArray
, idx
);
2015 if (!found
&& isInArray
) return;
2016 CFIndex newIdx
= __CFRunLoopInsertionIndexInTimerArray(timerArray
, rlt
);
2017 CFArrayInsertValueAtIndex(timerArray
, newIdx
, rlt
);
2018 __CFArmNextTimerInMode(rlm
, rlt
->_runLoop
);
2019 if (isInArray
) CFRelease(rlt
);
2023 // mode and rl are locked on entry and exit
2024 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
2025 Boolean timerHandled
= false;
2026 uint64_t oldFireTSR
= 0;
2030 __CFRunLoopTimerLock(rlt
);
2032 if (__CFIsValid(rlt
) && rlt
->_fireTSR
<= mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt
) && rlt
->_runLoop
== rl
) {
2033 void *context_info
= NULL
;
2034 void (*context_release
)(const void *) = NULL
;
2035 if (rlt
->_context
.retain
) {
2036 context_info
= (void *)rlt
->_context
.retain(rlt
->_context
.info
);
2037 context_release
= rlt
->_context
.release
;
2039 context_info
= rlt
->_context
.info
;
2041 Boolean doInvalidate
= (0.0 == rlt
->_interval
);
2042 __CFRunLoopTimerSetFiring(rlt
);
2043 // Just in case the next timer has exactly the same deadlines as this one, we reset these values so that the arm next timer code can correctly find the next timer in the list and arm the underlying timer.
2044 rlm
->_timerSoftDeadline
= UINT64_MAX
;
2045 rlm
->_timerHardDeadline
= UINT64_MAX
;
2046 __CFRunLoopTimerUnlock(rlt
);
2047 __CFRunLoopTimerFireTSRLock();
2048 oldFireTSR
= rlt
->_fireTSR
;
2049 __CFRunLoopTimerFireTSRUnlock();
2051 __CFArmNextTimerInMode(rlm
, rl
);
2053 __CFRunLoopModeUnlock(rlm
);
2054 __CFRunLoopUnlock(rl
);
2055 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt
->_callout
, rlt
, context_info
);
2058 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
2060 if (context_release
) {
2061 context_release(context_info
);
2063 __CFRunLoopLock(rl
);
2064 __CFRunLoopModeLock(rlm
);
2065 __CFRunLoopTimerLock(rlt
);
2066 timerHandled
= true;
2067 __CFRunLoopTimerUnsetFiring(rlt
);
2069 if (__CFIsValid(rlt
) && timerHandled
) {
2070 /* This is just a little bit tricky: we want to support calling
2071 * CFRunLoopTimerSetNextFireDate() from within the callout and
2072 * honor that new time here if it is a later date, otherwise
2073 * it is completely ignored. */
2074 if (oldFireTSR
< rlt
->_fireTSR
) {
2075 /* Next fire TSR was set, and set to a date after the previous
2076 * fire date, so we honor it. */
2077 __CFRunLoopTimerUnlock(rlt
);
2078 // The timer was adjusted and repositioned, during the
2079 // callout, but if it was still the min timer, it was
2080 // skipped because it was firing. Need to redo the
2081 // min timer calculation in case rlt should now be that
2082 // timer instead of whatever was chosen.
2083 __CFArmNextTimerInMode(rlm
, rl
);
2085 uint64_t nextFireTSR
= 0LL;
2086 uint64_t intervalTSR
= 0LL;
2087 if (rlt
->_interval
<= 0.0) {
2088 } else if (TIMER_INTERVAL_LIMIT
< rlt
->_interval
) {
2089 intervalTSR
= __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
2091 intervalTSR
= __CFTimeIntervalToTSR(rlt
->_interval
);
2093 if (LLONG_MAX
- intervalTSR
<= oldFireTSR
) {
2094 nextFireTSR
= LLONG_MAX
;
2096 if (intervalTSR
== 0) {
2097 // 15304159: Make sure we don't accidentally loop forever here
2098 CRSetCrashLogMessage("A CFRunLoopTimer with an interval of 0 is set to repeat");
2101 uint64_t currentTSR
= mach_absolute_time();
2102 nextFireTSR
= oldFireTSR
;
2103 while (nextFireTSR
<= currentTSR
) {
2104 nextFireTSR
+= intervalTSR
;
2107 CFRunLoopRef rlt_rl
= rlt
->_runLoop
;
2110 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
2111 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
2112 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
2113 // To avoid A->B, B->A lock ordering issues when coming up
2114 // towards the run loop from a source, the timer has to be
2115 // unlocked, which means we have to protect from object
2116 // invalidation, although that's somewhat expensive.
2117 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2118 CFRetain(modes
[idx
]);
2120 __CFRunLoopTimerUnlock(rlt
);
2121 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2122 CFStringRef name
= (CFStringRef
)modes
[idx
];
2123 modes
[idx
] = (CFTypeRef
)__CFRunLoopFindMode(rlt_rl
, name
, false);
2126 __CFRunLoopTimerFireTSRLock();
2127 rlt
->_fireTSR
= nextFireTSR
;
2128 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR
);
2129 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2130 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
2132 __CFRepositionTimerInMode(rlm
, rlt
, true);
2135 __CFRunLoopTimerFireTSRUnlock();
2136 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2137 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
2141 __CFRunLoopTimerUnlock(rlt
);
2142 __CFRunLoopTimerFireTSRLock();
2143 rlt
->_fireTSR
= nextFireTSR
;
2144 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR
);
2145 __CFRunLoopTimerFireTSRUnlock();
2149 __CFRunLoopTimerUnlock(rlt
);
2152 return timerHandled
;
2156 // rl and rlm are locked on entry and exit
2157 static Boolean
__CFRunLoopDoTimers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, uint64_t limitTSR
) { /* DOES CALLOUT */
2158 Boolean timerHandled
= false;
2159 CFMutableArrayRef timers
= NULL
;
2160 for (CFIndex idx
= 0, cnt
= rlm
->_timers
? CFArrayGetCount(rlm
->_timers
) : 0; idx
< cnt
; idx
++) {
2161 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, idx
);
2163 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
2164 if (rlt
->_fireTSR
<= limitTSR
) {
2165 if (!timers
) timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2166 CFArrayAppendValue(timers
, rlt
);
2171 for (CFIndex idx
= 0, cnt
= timers
? CFArrayGetCount(timers
) : 0; idx
< cnt
; idx
++) {
2172 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timers
, idx
);
2173 Boolean did
= __CFRunLoopDoTimer(rl
, rlm
, rlt
);
2174 timerHandled
= timerHandled
|| did
;
2176 if (timers
) CFRelease(timers
);
2177 return timerHandled
;
2181 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
2183 CFRunLoopModeRef rlm
;
2184 Boolean result
= false;
2185 __CFRunLoopLock(rl
);
2186 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2187 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
, NULL
)) {
2190 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2191 __CFRunLoopUnlock(rl
);
2195 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) __attribute__((noinline
));
2197 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2199 #define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0)
2201 static Boolean
__CFRunLoopServiceMachPort(mach_port_name_t port
, mach_msg_header_t
**buffer
, size_t buffer_size
, mach_port_t
*livePort
, mach_msg_timeout_t timeout
, voucher_mach_msg_state_t
*voucherState
, voucher_t
*voucherCopy
) {
2202 Boolean originalBuffer
= true;
2203 kern_return_t ret
= KERN_SUCCESS
;
2204 for (;;) { /* In that sleep of death what nightmares may come ... */
2205 mach_msg_header_t
*msg
= (mach_msg_header_t
*)*buffer
;
2207 msg
->msgh_local_port
= port
;
2208 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2209 msg
->msgh_size
= buffer_size
;
2211 if (TIMEOUT_INFINITY
== timeout
) { CFRUNLOOP_SLEEP(); } else { CFRUNLOOP_POLL(); }
2212 ret
= mach_msg(msg
, MACH_RCV_MSG
|(voucherState
? MACH_RCV_VOUCHER
: 0)|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
);
2214 // Take care of all voucher-related work right after mach_msg.
2215 // If we don't release the previous voucher we're going to leak it.
2216 voucher_mach_msg_revert(*voucherState
);
2218 // Someone will be responsible for calling voucher_mach_msg_revert. This call makes the received voucher the current one.
2219 *voucherState
= voucher_mach_msg_adopt(msg
);
2222 if (*voucherState
!= VOUCHER_MACH_MSG_STATE_UNCHANGED
) {
2223 // Caller requested a copy of the voucher at this point. By doing this right next to mach_msg we make sure that no voucher has been set in between the return of mach_msg and the use of the voucher copy.
2224 // CFMachPortBoost uses the voucher to drop importance explicitly. However, we want to make sure we only drop importance for a new voucher (not unchanged), so we only set the TSD when the voucher is not state_unchanged.
2225 *voucherCopy
= voucher_copy();
2227 *voucherCopy
= NULL
;
2231 CFRUNLOOP_WAKEUP(ret
);
2232 if (MACH_MSG_SUCCESS
== ret
) {
2233 *livePort
= msg
? msg
->msgh_local_port
: MACH_PORT_NULL
;
2236 if (MACH_RCV_TIMED_OUT
== ret
) {
2237 if (!originalBuffer
) free(msg
);
2239 *livePort
= MACH_PORT_NULL
;
2242 if (MACH_RCV_TOO_LARGE
!= ret
) break;
2243 buffer_size
= round_msg(msg
->msgh_size
+ MAX_TRAILER_SIZE
);
2244 if (originalBuffer
) *buffer
= NULL
;
2245 originalBuffer
= false;
2246 *buffer
= realloc(*buffer
, buffer_size
);
2252 #elif DEPLOYMENT_TARGET_WINDOWS
2254 #define TIMEOUT_INFINITY INFINITE
2256 // pass in either a portSet or onePort
2257 static Boolean
__CFRunLoopWaitForMultipleObjects(__CFPortSet portSet
, HANDLE
*onePort
, DWORD timeout
, DWORD mask
, HANDLE
*livePort
, Boolean
*msgReceived
) {
2258 DWORD waitResult
= WAIT_TIMEOUT
;
2259 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
2260 HANDLE
*handles
= NULL
;
2261 uint32_t handleCount
= 0;
2262 Boolean freeHandles
= false;
2263 Boolean result
= false;
2266 // copy out the handles to be safe from other threads at work
2267 handles
= __CFPortSetGetPorts(portSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
2268 freeHandles
= (handles
!= handleBuf
);
2272 freeHandles
= FALSE
;
2275 // The run loop mode and loop are already in proper unlocked state from caller
2276 waitResult
= MsgWaitForMultipleObjectsEx(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, timeout
, mask
, MWMO_INPUTAVAILABLE
);
2278 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
2280 if (waitResult
== WAIT_TIMEOUT
) {
2281 // do nothing, just return to caller
2283 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
2284 // a handle was signaled
2285 if (livePort
) *livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
2287 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
2288 // windows message received
2289 if (msgReceived
) *msgReceived
= true;
2291 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
2292 // an "abandoned mutex object"
2293 if (livePort
) *livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
2296 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
2301 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
2309 struct __timeout_context
{
2310 dispatch_source_t ds
;
2315 static void __CFRunLoopTimeoutCancel(void *arg
) {
2316 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2317 CFRelease(context
->rl
);
2318 dispatch_release(context
->ds
);
2322 static void __CFRunLoopTimeout(void *arg
) {
2323 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2324 context
->termTSR
= 0ULL;
2325 CFRUNLOOP_WAKEUP_FOR_TIMEOUT();
2326 CFRunLoopWakeUp(context
->rl
);
2327 // The interval is DISPATCH_TIME_FOREVER, so this won't fire again
2330 /* rl, rlm are locked on entrance and exit */
2331 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) {
2332 uint64_t startTSR
= mach_absolute_time();
2334 if (__CFRunLoopIsStopped(rl
)) {
2335 __CFRunLoopUnsetStopped(rl
);
2336 return kCFRunLoopRunStopped
;
2337 } else if (rlm
->_stopped
) {
2338 rlm
->_stopped
= false;
2339 return kCFRunLoopRunStopped
;
2342 mach_port_name_t dispatchPort
= MACH_PORT_NULL
;
2343 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
2344 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) dispatchPort
= _dispatch_get_main_queue_port_4CF();
2346 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2347 mach_port_name_t modeQueuePort
= MACH_PORT_NULL
;
2349 modeQueuePort
= _dispatch_runloop_root_queue_get_port_4CF(rlm
->_queue
);
2350 if (!modeQueuePort
) {
2351 CRASH("Unable to get port for run loop mode queue (%d)", -1);
2356 dispatch_source_t timeout_timer
= NULL
;
2357 struct __timeout_context
*timeout_context
= (struct __timeout_context
*)malloc(sizeof(*timeout_context
));
2358 if (seconds
<= 0.0) { // instant timeout
2360 timeout_context
->termTSR
= 0ULL;
2361 } else if (seconds
<= TIMER_INTERVAL_LIMIT
) {
2362 dispatch_queue_t queue
= pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
2363 timeout_timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, queue
);
2364 dispatch_retain(timeout_timer
);
2365 timeout_context
->ds
= timeout_timer
;
2366 timeout_context
->rl
= (CFRunLoopRef
)CFRetain(rl
);
2367 timeout_context
->termTSR
= startTSR
+ __CFTimeIntervalToTSR(seconds
);
2368 dispatch_set_context(timeout_timer
, timeout_context
); // source gets ownership of context
2369 dispatch_source_set_event_handler_f(timeout_timer
, __CFRunLoopTimeout
);
2370 dispatch_source_set_cancel_handler_f(timeout_timer
, __CFRunLoopTimeoutCancel
);
2371 uint64_t ns_at
= (uint64_t)((__CFTSRToTimeInterval(startTSR
) + seconds
) * 1000000000ULL);
2372 dispatch_source_set_timer(timeout_timer
, dispatch_time(1, ns_at
), DISPATCH_TIME_FOREVER
, 1000ULL);
2373 dispatch_resume(timeout_timer
);
2374 } else { // infinite timeout
2375 seconds
= 9999999999.0;
2376 timeout_context
->termTSR
= UINT64_MAX
;
2379 Boolean didDispatchPortLastTime
= true;
2382 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2383 voucher_mach_msg_state_t voucherState
= VOUCHER_MACH_MSG_STATE_UNCHANGED
;
2384 voucher_t voucherCopy
= NULL
;
2386 uint8_t msg_buffer
[3 * 1024];
2387 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2388 mach_msg_header_t
*msg
= NULL
;
2389 mach_port_t livePort
= MACH_PORT_NULL
;
2390 #elif DEPLOYMENT_TARGET_WINDOWS
2391 HANDLE livePort
= NULL
;
2392 Boolean windowsMessageReceived
= false;
2394 __CFPortSet waitSet
= rlm
->_portSet
;
2396 __CFRunLoopUnsetIgnoreWakeUps(rl
);
2398 if (rlm
->_observerMask
& kCFRunLoopBeforeTimers
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
2399 if (rlm
->_observerMask
& kCFRunLoopBeforeSources
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
2401 __CFRunLoopDoBlocks(rl
, rlm
);
2403 Boolean sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
2404 if (sourceHandledThisLoop
) {
2405 __CFRunLoopDoBlocks(rl
, rlm
);
2408 Boolean poll
= sourceHandledThisLoop
|| (0ULL == timeout_context
->termTSR
);
2410 if (MACH_PORT_NULL
!= dispatchPort
&& !didDispatchPortLastTime
) {
2411 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2412 msg
= (mach_msg_header_t
*)msg_buffer
;
2413 if (__CFRunLoopServiceMachPort(dispatchPort
, &msg
, sizeof(msg_buffer
), &livePort
, 0, &voucherState
, NULL
)) {
2416 #elif DEPLOYMENT_TARGET_WINDOWS
2417 if (__CFRunLoopWaitForMultipleObjects(NULL
, &dispatchPort
, 0, 0, &livePort
, NULL
)) {
2423 didDispatchPortLastTime
= false;
2425 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopBeforeWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
2426 __CFRunLoopSetSleeping(rl
);
2427 // do not do any user callouts after this point (after notifying of sleeping)
2429 // Must push the local-to-this-activation ports in on every loop
2430 // iteration, as this mode could be run re-entrantly and we don't
2431 // want these ports to get serviced.
2433 __CFPortSetInsert(dispatchPort
, waitSet
);
2435 __CFRunLoopModeUnlock(rlm
);
2436 __CFRunLoopUnlock(rl
);
2438 CFAbsoluteTime sleepStart
= poll
? 0.0 : CFAbsoluteTimeGetCurrent();
2440 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2441 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2443 if (kCFUseCollectableAllocator
) {
2444 // objc_clear_stack(0);
2445 // <rdar://problem/16393959>
2446 memset(msg_buffer
, 0, sizeof(msg_buffer
));
2448 msg
= (mach_msg_header_t
*)msg_buffer
;
2450 __CFRunLoopServiceMachPort(waitSet
, &msg
, sizeof(msg_buffer
), &livePort
, poll
? 0 : TIMEOUT_INFINITY
, &voucherState
, &voucherCopy
);
2452 if (modeQueuePort
!= MACH_PORT_NULL
&& livePort
== modeQueuePort
) {
2453 // Drain the internal queue. If one of the callout blocks sets the timerFired flag, break out and service the timer.
2454 while (_dispatch_runloop_root_queue_perform_4CF(rlm
->_queue
));
2455 if (rlm
->_timerFired
) {
2456 // Leave livePort as the queue port, and service timers below
2457 rlm
->_timerFired
= false;
2460 if (msg
&& msg
!= (mach_msg_header_t
*)msg_buffer
) free(msg
);
2463 // Go ahead and leave the inner loop.
2468 if (kCFUseCollectableAllocator
) {
2469 // objc_clear_stack(0);
2470 // <rdar://problem/16393959>
2471 memset(msg_buffer
, 0, sizeof(msg_buffer
));
2473 msg
= (mach_msg_header_t
*)msg_buffer
;
2474 __CFRunLoopServiceMachPort(waitSet
, &msg
, sizeof(msg_buffer
), &livePort
, poll
? 0 : TIMEOUT_INFINITY
, &voucherState
, &voucherCopy
);
2478 #elif DEPLOYMENT_TARGET_WINDOWS
2479 // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages.
2480 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, poll
? 0 : TIMEOUT_INFINITY
, rlm
->_msgQMask
, &livePort
, &windowsMessageReceived
);
2483 __CFRunLoopLock(rl
);
2484 __CFRunLoopModeLock(rlm
);
2486 rl
->_sleepTime
+= (poll
? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart
));
2488 // Must remove the local-to-this-activation ports in on every loop
2489 // iteration, as this mode could be run re-entrantly and we don't
2490 // want these ports to get serviced. Also, we don't want them left
2491 // in there if this function returns.
2493 __CFPortSetRemove(dispatchPort
, waitSet
);
2495 __CFRunLoopSetIgnoreWakeUps(rl
);
2497 // user callouts now OK again
2498 __CFRunLoopUnsetSleeping(rl
);
2499 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopAfterWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
2502 __CFRunLoopSetIgnoreWakeUps(rl
);
2504 #if DEPLOYMENT_TARGET_WINDOWS
2505 if (windowsMessageReceived
) {
2506 // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after
2507 __CFRunLoopModeUnlock(rlm
);
2508 __CFRunLoopUnlock(rl
);
2510 if (rlm
->_msgPump
) {
2514 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
2515 TranslateMessage(&msg
);
2516 DispatchMessage(&msg
);
2520 __CFRunLoopLock(rl
);
2521 __CFRunLoopModeLock(rlm
);
2522 sourceHandledThisLoop
= true;
2524 // To prevent starvation of sources other than the message queue, we check again to see if any other sources need to be serviced
2525 // 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.
2526 // 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.
2527 __CFRunLoopSetSleeping(rl
);
2528 __CFRunLoopModeUnlock(rlm
);
2529 __CFRunLoopUnlock(rl
);
2531 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, 0, 0, &livePort
, NULL
);
2533 __CFRunLoopLock(rl
);
2534 __CFRunLoopModeLock(rlm
);
2535 __CFRunLoopUnsetSleeping(rl
);
2536 // If we have a new live port then it will be handled below as normal
2541 if (MACH_PORT_NULL
== livePort
) {
2542 CFRUNLOOP_WAKEUP_FOR_NOTHING();
2544 } else if (livePort
== rl
->_wakeUpPort
) {
2545 CFRUNLOOP_WAKEUP_FOR_WAKEUP();
2546 // do nothing on Mac OS
2547 #if DEPLOYMENT_TARGET_WINDOWS
2548 // Always reset the wake up port, or risk spinning forever
2549 ResetEvent(rl
->_wakeUpPort
);
2552 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2553 else if (modeQueuePort
!= MACH_PORT_NULL
&& livePort
== modeQueuePort
) {
2554 CFRUNLOOP_WAKEUP_FOR_TIMER();
2555 if (!__CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time())) {
2556 // Re-arm the next timer, because we apparently fired early
2557 __CFArmNextTimerInMode(rlm
, rl
);
2561 #if USE_MK_TIMER_TOO
2562 else if (rlm
->_timerPort
!= MACH_PORT_NULL
&& livePort
== rlm
->_timerPort
) {
2563 CFRUNLOOP_WAKEUP_FOR_TIMER();
2564 // 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. 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.
2565 // 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
2566 if (!__CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time())) {
2567 // Re-arm the next timer
2568 __CFArmNextTimerInMode(rlm
, rl
);
2572 else if (livePort
== dispatchPort
) {
2573 CFRUNLOOP_WAKEUP_FOR_DISPATCH();
2574 __CFRunLoopModeUnlock(rlm
);
2575 __CFRunLoopUnlock(rl
);
2576 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)6, NULL
);
2577 #if DEPLOYMENT_TARGET_WINDOWS
2580 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg
);
2581 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)0, NULL
);
2582 __CFRunLoopLock(rl
);
2583 __CFRunLoopModeLock(rlm
);
2584 sourceHandledThisLoop
= true;
2585 didDispatchPortLastTime
= true;
2587 CFRUNLOOP_WAKEUP_FOR_SOURCE();
2589 // If we received a voucher from this mach_msg, then put a copy of the new voucher into TSD. CFMachPortBoost will look in the TSD for the voucher. By using the value in the TSD we tie the CFMachPortBoost to this received mach_msg explicitly without a chance for anything in between the two pieces of code to set the voucher again.
2590 voucher_t previousVoucher
= _CFSetTSD(__CFTSDKeyMachMessageHasVoucher
, (void *)voucherCopy
, os_release
);
2592 // Despite the name, this works for windows handles as well
2593 CFRunLoopSourceRef rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
);
2595 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2596 mach_msg_header_t
*reply
= NULL
;
2597 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
) || sourceHandledThisLoop
;
2598 if (NULL
!= reply
) {
2599 (void)mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
2600 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
2602 #elif DEPLOYMENT_TARGET_WINDOWS
2603 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
) || sourceHandledThisLoop
;
2607 // Restore the previous voucher
2608 _CFSetTSD(__CFTSDKeyMachMessageHasVoucher
, previousVoucher
, os_release
);
2611 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2612 if (msg
&& msg
!= (mach_msg_header_t
*)msg_buffer
) free(msg
);
2615 __CFRunLoopDoBlocks(rl
, rlm
);
2618 if (sourceHandledThisLoop
&& stopAfterHandle
) {
2619 retVal
= kCFRunLoopRunHandledSource
;
2620 } else if (timeout_context
->termTSR
< mach_absolute_time()) {
2621 retVal
= kCFRunLoopRunTimedOut
;
2622 } else if (__CFRunLoopIsStopped(rl
)) {
2623 __CFRunLoopUnsetStopped(rl
);
2624 retVal
= kCFRunLoopRunStopped
;
2625 } else if (rlm
->_stopped
) {
2626 rlm
->_stopped
= false;
2627 retVal
= kCFRunLoopRunStopped
;
2628 } else if (__CFRunLoopModeIsEmpty(rl
, rlm
, previousMode
)) {
2629 retVal
= kCFRunLoopRunFinished
;
2632 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2633 voucher_mach_msg_revert(voucherState
);
2634 os_release(voucherCopy
);
2637 } while (0 == retVal
);
2639 if (timeout_timer
) {
2640 dispatch_source_cancel(timeout_timer
);
2641 dispatch_release(timeout_timer
);
2643 free(timeout_context
);
2649 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2651 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
2652 __CFRunLoopLock(rl
);
2653 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
2654 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
, rl
->_currentMode
)) {
2655 Boolean did
= false;
2656 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2657 __CFRunLoopUnlock(rl
);
2658 return did
? kCFRunLoopRunHandledSource
: kCFRunLoopRunFinished
;
2660 volatile _per_run_data
*previousPerRun
= __CFRunLoopPushPerRunData(rl
);
2661 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
2662 rl
->_currentMode
= currentMode
;
2663 int32_t result
= kCFRunLoopRunFinished
;
2665 if (currentMode
->_observerMask
& kCFRunLoopEntry
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
2666 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, previousMode
);
2667 if (currentMode
->_observerMask
& kCFRunLoopExit
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
2669 __CFRunLoopModeUnlock(currentMode
);
2670 __CFRunLoopPopPerRunData(rl
, previousPerRun
);
2671 rl
->_currentMode
= previousMode
;
2672 __CFRunLoopUnlock(rl
);
2676 void CFRunLoopRun(void) { /* DOES CALLOUT */
2679 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
2681 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
2684 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2686 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
2689 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
2691 __CFRunLoopLock(rl
);
2692 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2693 CFAbsoluteTime at
= 0.0;
2694 CFRunLoopTimerRef nextTimer
= (rlm
&& rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) ? (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, 0) : NULL
;
2696 at
= CFRunLoopTimerGetNextFireDate(nextTimer
);
2698 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2699 __CFRunLoopUnlock(rl
);
2703 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
2705 return __CFRunLoopIsSleeping(rl
);
2708 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
2710 // This lock is crucial to ignorable wakeups, do not remove it.
2711 __CFRunLoopLock(rl
);
2712 if (__CFRunLoopIsIgnoringWakeUps(rl
)) {
2713 __CFRunLoopUnlock(rl
);
2716 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2718 /* We unconditionally try to send the message, since we don't want
2719 * to lose a wakeup, but the send may fail if there is already a
2720 * wakeup pending, since the queue length is 1. */
2721 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
2722 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) CRASH("*** Unable to send message to wake up port. (%d) ***", ret
);
2723 #elif DEPLOYMENT_TARGET_WINDOWS
2724 SetEvent(rl
->_wakeUpPort
);
2726 __CFRunLoopUnlock(rl
);
2729 void CFRunLoopStop(CFRunLoopRef rl
) {
2730 Boolean doWake
= false;
2732 __CFRunLoopLock(rl
);
2733 if (rl
->_currentMode
) {
2734 __CFRunLoopSetStopped(rl
);
2737 __CFRunLoopUnlock(rl
);
2739 CFRunLoopWakeUp(rl
);
2743 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
2745 CFRunLoopModeRef rlm
;
2746 __CFRunLoopLock(rl
);
2747 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2749 rlm
->_stopped
= true;
2750 __CFRunLoopModeUnlock(rlm
);
2752 __CFRunLoopUnlock(rl
);
2753 CFRunLoopWakeUp(rl
);
2756 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2761 void CFRunLoopPerformBlock(CFRunLoopRef rl
, CFTypeRef mode
, void (^block
)(void)) {
2763 if (CFStringGetTypeID() == CFGetTypeID(mode
)) {
2764 mode
= CFStringCreateCopy(kCFAllocatorSystemDefault
, (CFStringRef
)mode
);
2765 __CFRunLoopLock(rl
);
2766 // ensure mode exists
2767 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)mode
, true);
2768 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2769 __CFRunLoopUnlock(rl
);
2770 } else if (CFArrayGetTypeID() == CFGetTypeID(mode
)) {
2771 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)mode
);
2772 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2773 CFArrayGetValues((CFArrayRef
)mode
, CFRangeMake(0, cnt
), values
);
2774 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2775 __CFRunLoopLock(rl
);
2776 // ensure modes exist
2777 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2778 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2779 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2781 __CFRunLoopUnlock(rl
);
2783 } else if (CFSetGetTypeID() == CFGetTypeID(mode
)) {
2784 CFIndex cnt
= CFSetGetCount((CFSetRef
)mode
);
2785 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2786 CFSetGetValues((CFSetRef
)mode
, values
);
2787 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2788 __CFRunLoopLock(rl
);
2789 // ensure modes exist
2790 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2791 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2792 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2794 __CFRunLoopUnlock(rl
);
2799 block
= Block_copy(block
);
2800 if (!mode
|| !block
) {
2801 if (mode
) CFRelease(mode
);
2802 if (block
) Block_release(block
);
2805 __CFRunLoopLock(rl
);
2806 struct _block_item
*new_item
= (struct _block_item
*)malloc(sizeof(struct _block_item
));
2807 new_item
->_next
= NULL
;
2808 new_item
->_mode
= mode
;
2809 new_item
->_block
= block
;
2810 if (!rl
->_blocks_tail
) {
2811 rl
->_blocks_head
= new_item
;
2813 rl
->_blocks_tail
->_next
= new_item
;
2815 rl
->_blocks_tail
= new_item
;
2816 __CFRunLoopUnlock(rl
);
2819 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2821 CFRunLoopModeRef rlm
;
2822 Boolean hasValue
= false;
2823 __CFRunLoopLock(rl
);
2824 if (modeName
== kCFRunLoopCommonModes
) {
2825 if (NULL
!= rl
->_commonModeItems
) {
2826 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2829 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2831 hasValue
= (rlm
->_sources0
? CFSetContainsValue(rlm
->_sources0
, rls
) : false) || (rlm
->_sources1
? CFSetContainsValue(rlm
->_sources1
, rls
) : false);
2832 __CFRunLoopModeUnlock(rlm
);
2835 __CFRunLoopUnlock(rl
);
2839 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2841 if (__CFRunLoopIsDeallocating(rl
)) return;
2842 if (!__CFIsValid(rls
)) return;
2843 Boolean doVer0Callout
= false;
2844 __CFRunLoopLock(rl
);
2845 if (modeName
== kCFRunLoopCommonModes
) {
2846 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2847 if (NULL
== rl
->_commonModeItems
) {
2848 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2850 CFSetAddValue(rl
->_commonModeItems
, rls
);
2852 CFTypeRef context
[2] = {rl
, rls
};
2853 /* add new item to all common-modes */
2854 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2858 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2859 if (NULL
!= rlm
&& NULL
== rlm
->_sources0
) {
2860 rlm
->_sources0
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2861 rlm
->_sources1
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2862 rlm
->_portToV1SourceMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
2864 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources0
, rls
) && !CFSetContainsValue(rlm
->_sources1
, rls
)) {
2865 if (0 == rls
->_context
.version0
.version
) {
2866 CFSetAddValue(rlm
->_sources0
, rls
);
2867 } else if (1 == rls
->_context
.version0
.version
) {
2868 CFSetAddValue(rlm
->_sources1
, rls
);
2869 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2870 if (CFPORT_NULL
!= src_port
) {
2871 CFDictionarySetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
, rls
);
2872 __CFPortSetInsert(src_port
, rlm
->_portSet
);
2875 __CFRunLoopSourceLock(rls
);
2876 if (NULL
== rls
->_runLoops
) {
2877 rls
->_runLoops
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeBagCallBacks
); // sources retain run loops!
2879 CFBagAddValue(rls
->_runLoops
, rl
);
2880 __CFRunLoopSourceUnlock(rls
);
2881 if (0 == rls
->_context
.version0
.version
) {
2882 if (NULL
!= rls
->_context
.version0
.schedule
) {
2883 doVer0Callout
= true;
2888 __CFRunLoopModeUnlock(rlm
);
2891 __CFRunLoopUnlock(rl
);
2892 if (doVer0Callout
) {
2893 // although it looses some protection for the source, we have no choice but
2894 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2895 // where the source wants to take a lock which is already held in another
2896 // thread which is itself waiting for a run loop/mode lock
2897 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2901 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2903 Boolean doVer0Callout
= false, doRLSRelease
= false;
2904 __CFRunLoopLock(rl
);
2905 if (modeName
== kCFRunLoopCommonModes
) {
2906 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2907 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2908 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2910 CFTypeRef context
[2] = {rl
, rls
};
2911 /* remove new item from all common-modes */
2912 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2918 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2919 if (NULL
!= rlm
&& ((NULL
!= rlm
->_sources0
&& CFSetContainsValue(rlm
->_sources0
, rls
)) || (NULL
!= rlm
->_sources1
&& CFSetContainsValue(rlm
->_sources1
, rls
)))) {
2921 if (1 == rls
->_context
.version0
.version
) {
2922 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2923 if (CFPORT_NULL
!= src_port
) {
2924 CFDictionaryRemoveValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
);
2925 __CFPortSetRemove(src_port
, rlm
->_portSet
);
2928 CFSetRemoveValue(rlm
->_sources0
, rls
);
2929 CFSetRemoveValue(rlm
->_sources1
, rls
);
2930 __CFRunLoopSourceLock(rls
);
2931 if (NULL
!= rls
->_runLoops
) {
2932 CFBagRemoveValue(rls
->_runLoops
, rl
);
2934 __CFRunLoopSourceUnlock(rls
);
2935 if (0 == rls
->_context
.version0
.version
) {
2936 if (NULL
!= rls
->_context
.version0
.cancel
) {
2937 doVer0Callout
= true;
2940 doRLSRelease
= true;
2943 __CFRunLoopModeUnlock(rlm
);
2946 __CFRunLoopUnlock(rl
);
2947 if (doVer0Callout
) {
2948 // although it looses some protection for the source, we have no choice but
2949 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2950 // where the source wants to take a lock which is already held in another
2951 // thread which is itself waiting for a run loop/mode lock
2952 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2954 if (doRLSRelease
) CFRelease(rls
);
2957 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value
, void *ctx
) {
2958 CFStringRef modeName
= (CFStringRef
)value
;
2959 CFRunLoopRef rl
= (CFRunLoopRef
)ctx
;
2960 __CFRunLoopRemoveAllSources(rl
, modeName
);
2963 static void __CFRunLoopRemoveSourceFromMode(const void *value
, void *ctx
) {
2964 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
2965 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
2966 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
2967 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2970 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
) {
2972 CFRunLoopModeRef rlm
;
2973 __CFRunLoopLock(rl
);
2974 if (modeName
== kCFRunLoopCommonModes
) {
2975 if (NULL
!= rl
->_commonModeItems
) {
2976 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2978 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourcesFromCommonMode
), (void *)rl
);
2984 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2985 if (NULL
!= rlm
&& NULL
!= rlm
->_sources0
) {
2986 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources0
);
2987 CFTypeRef context
[2] = {rl
, modeName
};
2988 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2991 if (NULL
!= rlm
&& NULL
!= rlm
->_sources1
) {
2992 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources1
);
2993 CFTypeRef context
[2] = {rl
, modeName
};
2994 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2998 __CFRunLoopModeUnlock(rlm
);
3001 __CFRunLoopUnlock(rl
);
3004 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
3006 CFRunLoopModeRef rlm
;
3007 Boolean hasValue
= false;
3008 __CFRunLoopLock(rl
);
3009 if (modeName
== kCFRunLoopCommonModes
) {
3010 if (NULL
!= rl
->_commonModeItems
) {
3011 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
3014 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3015 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
3016 hasValue
= CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
3019 __CFRunLoopModeUnlock(rlm
);
3022 __CFRunLoopUnlock(rl
);
3026 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
3028 CFRunLoopModeRef rlm
;
3029 if (__CFRunLoopIsDeallocating(rl
)) return;
3030 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
3031 __CFRunLoopLock(rl
);
3032 if (modeName
== kCFRunLoopCommonModes
) {
3033 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3034 if (NULL
== rl
->_commonModeItems
) {
3035 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3037 CFSetAddValue(rl
->_commonModeItems
, rlo
);
3039 CFTypeRef context
[2] = {rl
, rlo
};
3040 /* add new item to all common-modes */
3041 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
3045 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
3046 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
3047 rlm
->_observers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
3049 if (NULL
!= rlm
&& !CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
)) {
3050 Boolean inserted
= false;
3051 for (CFIndex idx
= CFArrayGetCount(rlm
->_observers
); idx
--; ) {
3052 CFRunLoopObserverRef obs
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(rlm
->_observers
, idx
);
3053 if (obs
->_order
<= rlo
->_order
) {
3054 CFArrayInsertValueAtIndex(rlm
->_observers
, idx
+ 1, rlo
);
3060 CFArrayInsertValueAtIndex(rlm
->_observers
, 0, rlo
);
3062 rlm
->_observerMask
|= rlo
->_activities
;
3063 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
3066 __CFRunLoopModeUnlock(rlm
);
3069 __CFRunLoopUnlock(rl
);
3072 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
3074 CFRunLoopModeRef rlm
;
3075 __CFRunLoopLock(rl
);
3076 if (modeName
== kCFRunLoopCommonModes
) {
3077 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
3078 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3079 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
3081 CFTypeRef context
[2] = {rl
, rlo
};
3082 /* remove new item from all common-modes */
3083 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3089 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3090 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
3092 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
3093 if (kCFNotFound
!= idx
) {
3094 CFArrayRemoveValueAtIndex(rlm
->_observers
, idx
);
3095 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
3100 __CFRunLoopModeUnlock(rlm
);
3103 __CFRunLoopUnlock(rl
);
3106 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3108 if (NULL
== rlt
->_runLoop
|| rl
!= rlt
->_runLoop
) return false;
3109 Boolean hasValue
= false;
3110 __CFRunLoopLock(rl
);
3111 if (modeName
== kCFRunLoopCommonModes
) {
3112 if (NULL
!= rl
->_commonModeItems
) {
3113 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
3116 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3118 if (NULL
!= rlm
->_timers
) {
3119 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), rlt
);
3120 hasValue
= (kCFNotFound
!= idx
);
3122 __CFRunLoopModeUnlock(rlm
);
3125 __CFRunLoopUnlock(rl
);
3129 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3131 if (__CFRunLoopIsDeallocating(rl
)) return;
3132 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
3133 __CFRunLoopLock(rl
);
3134 if (modeName
== kCFRunLoopCommonModes
) {
3135 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3136 if (NULL
== rl
->_commonModeItems
) {
3137 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3139 CFSetAddValue(rl
->_commonModeItems
, rlt
);
3141 CFTypeRef context
[2] = {rl
, rlt
};
3142 /* add new item to all common-modes */
3143 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
3147 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
3149 if (NULL
== rlm
->_timers
) {
3150 CFArrayCallBacks cb
= kCFTypeArrayCallBacks
;
3152 rlm
->_timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &cb
);
3155 if (NULL
!= rlm
&& !CFSetContainsValue(rlt
->_rlModes
, rlm
->_name
)) {
3156 __CFRunLoopTimerLock(rlt
);
3157 if (NULL
== rlt
->_runLoop
) {
3159 } else if (rl
!= rlt
->_runLoop
) {
3160 __CFRunLoopTimerUnlock(rlt
);
3161 __CFRunLoopModeUnlock(rlm
);
3162 __CFRunLoopUnlock(rl
);
3165 CFSetAddValue(rlt
->_rlModes
, rlm
->_name
);
3166 __CFRunLoopTimerUnlock(rlt
);
3167 __CFRunLoopTimerFireTSRLock();
3168 __CFRepositionTimerInMode(rlm
, rlt
, false);
3169 __CFRunLoopTimerFireTSRUnlock();
3170 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion
)) {
3171 // Normally we don't do this on behalf of clients, but for
3172 // backwards compatibility due to the change in timer handling...
3173 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
3177 __CFRunLoopModeUnlock(rlm
);
3180 __CFRunLoopUnlock(rl
);
3183 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3185 __CFRunLoopLock(rl
);
3186 if (modeName
== kCFRunLoopCommonModes
) {
3187 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
3188 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3189 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
3191 CFTypeRef context
[2] = {rl
, rlt
};
3192 /* remove new item from all common-modes */
3193 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3199 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3200 CFIndex idx
= kCFNotFound
;
3201 CFMutableArrayRef timerList
= NULL
;
3203 timerList
= rlm
->_timers
;
3204 if (NULL
!= timerList
) {
3205 idx
= CFArrayGetFirstIndexOfValue(timerList
, CFRangeMake(0, CFArrayGetCount(timerList
)), rlt
);
3208 if (kCFNotFound
!= idx
) {
3209 __CFRunLoopTimerLock(rlt
);
3210 CFSetRemoveValue(rlt
->_rlModes
, rlm
->_name
);
3211 if (0 == CFSetGetCount(rlt
->_rlModes
)) {
3212 rlt
->_runLoop
= NULL
;
3214 __CFRunLoopTimerUnlock(rlt
);
3215 CFArrayRemoveValueAtIndex(timerList
, idx
);
3216 __CFArmNextTimerInMode(rlm
, rl
);
3219 __CFRunLoopModeUnlock(rlm
);
3222 __CFRunLoopUnlock(rl
);
3225 /* CFRunLoopSource */
3227 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
3228 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
3229 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
3230 if (rls1
== rls2
) return true;
3231 if (__CFIsValid(rls1
) != __CFIsValid(rls2
)) return false;
3232 if (rls1
->_order
!= rls2
->_order
) return false;
3233 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
3234 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
3235 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
3236 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
3237 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
3238 if (rls1
->_context
.version0
.equal
)
3239 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
3240 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
3243 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
3244 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3245 if (rls
->_context
.version0
.hash
)
3246 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
3247 return (CFHashCode
)rls
->_context
.version0
.info
;
3250 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3251 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3253 CFStringRef contextDesc
= NULL
;
3254 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
3255 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
3257 if (NULL
== contextDesc
) {
3258 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
3259 #if DEPLOYMENT_TARGET_WINDOWS
3260 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, addr
);
3261 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3263 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3264 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
3267 #if DEPLOYMENT_TARGET_WINDOWS
3268 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
);
3270 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource %p [%p]>{signalled = %s, valid = %s, order = %ld, context = %@}"), cf
, CFGetAllocator(rls
), __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", (unsigned long)rls
->_order
, contextDesc
);
3272 CFRelease(contextDesc
);
3276 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3277 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3278 CFRunLoopSourceInvalidate(rls
);
3279 if (rls
->_context
.version0
.release
) {
3280 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
3282 pthread_mutex_destroy(&rls
->_lock
);
3283 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0, sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
));
3286 static const CFRuntimeClass __CFRunLoopSourceClass
= {
3287 _kCFRuntimeScannedObject
,
3291 __CFRunLoopSourceDeallocate
,
3292 __CFRunLoopSourceEqual
,
3293 __CFRunLoopSourceHash
,
3295 __CFRunLoopSourceCopyDescription
3298 CFTypeID
CFRunLoopSourceGetTypeID(void) {
3299 static dispatch_once_t initOnce
;
3300 dispatch_once(&initOnce
, ^{ __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
); });
3301 return __kCFRunLoopSourceTypeID
;
3304 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
3306 CFRunLoopSourceRef memory
;
3308 if (NULL
== context
) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
3310 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
3311 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, CFRunLoopSourceGetTypeID(), size
, NULL
);
3312 if (NULL
== memory
) {
3315 __CFSetValid(memory
);
3316 __CFRunLoopSourceUnsetSignaled(memory
);
3317 __CFRunLoopLockInit(&memory
->_lock
);
3319 memory
->_order
= order
;
3320 memory
->_runLoops
= NULL
;
3322 switch (context
->version
) {
3324 size
= sizeof(CFRunLoopSourceContext
);
3327 size
= sizeof(CFRunLoopSourceContext1
);
3330 objc_memmove_collectable(&memory
->_context
, context
, size
);
3331 if (context
->retain
) {
3332 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
3337 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
3339 __CFGenericValidateType(rls
, CFRunLoopSourceGetTypeID());
3343 static void __CFRunLoopSourceWakeUpLoop(const void *value
, void *context
) {
3344 CFRunLoopWakeUp((CFRunLoopRef
)value
);
3347 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
3348 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
3349 CFTypeRef
*params
= (CFTypeRef
*)context
;
3350 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
3352 if (rl
== params
[1]) return;
3354 // CFRunLoopRemoveSource will lock the run loop while it
3355 // needs that, but we also lock it out here to keep
3356 // changes from occurring for this whole sequence.
3357 __CFRunLoopLock(rl
);
3358 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3359 for (idx
= CFArrayGetCount(array
); idx
--;) {
3360 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3361 CFRunLoopRemoveSource(rl
, rls
, modeName
);
3363 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
3364 __CFRunLoopUnlock(rl
);
3369 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
3371 __CFGenericValidateType(rls
, CFRunLoopSourceGetTypeID());
3372 __CFRunLoopSourceLock(rls
);
3374 if (__CFIsValid(rls
)) {
3375 CFBagRef rloops
= rls
->_runLoops
;
3376 __CFUnsetValid(rls
);
3377 __CFRunLoopSourceUnsetSignaled(rls
);
3378 if (NULL
!= rloops
) {
3379 // To avoid A->B, B->A lock ordering issues when coming up
3380 // towards the run loop from a source, the source has to be
3381 // unlocked, which means we have to protect from object
3383 rls
->_runLoops
= NULL
; // transfer ownership to local stack
3384 __CFRunLoopSourceUnlock(rls
);
3385 CFTypeRef params
[2] = {rls
, NULL
};
3386 CFBagApplyFunction(rloops
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
3388 __CFRunLoopSourceLock(rls
);
3390 /* for hashing- and equality-use purposes, can't actually release the context here */
3392 __CFRunLoopSourceUnlock(rls
);
3396 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
3398 __CFGenericValidateType(rls
, CFRunLoopSourceGetTypeID());
3399 return __CFIsValid(rls
);
3402 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
3404 __CFGenericValidateType(rls
, CFRunLoopSourceGetTypeID());
3405 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
3407 switch (context
->version
) {
3409 size
= sizeof(CFRunLoopSourceContext
);
3412 size
= sizeof(CFRunLoopSourceContext1
);
3415 memmove(context
, &rls
->_context
, size
);
3418 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
3420 __CFRunLoopSourceLock(rls
);
3421 if (__CFIsValid(rls
)) {
3422 __CFRunLoopSourceSetSignaled(rls
);
3424 __CFRunLoopSourceUnlock(rls
);
3427 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
3429 __CFRunLoopSourceLock(rls
);
3430 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
3431 __CFRunLoopSourceUnlock(rls
);
3435 CF_PRIVATE
void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
) {
3436 CFBagRef loops
= NULL
;
3437 __CFRunLoopSourceLock(rls
);
3438 if (__CFIsValid(rls
) && NULL
!= rls
->_runLoops
) {
3439 loops
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
3441 __CFRunLoopSourceUnlock(rls
);
3443 CFBagApplyFunction(loops
, __CFRunLoopSourceWakeUpLoop
, NULL
);
3448 /* CFRunLoopObserver */
3450 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3451 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3453 CFStringRef contextDesc
= NULL
;
3454 if (NULL
!= rlo
->_context
.copyDescription
) {
3455 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
3458 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
3460 #if DEPLOYMENT_TARGET_WINDOWS
3461 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
);
3462 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3463 void *addr
= rlo
->_callout
;
3465 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3466 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{valid = %s, activities = 0x%lx, repeats = %s, order = %ld, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlo
), __CFIsValid(rlo
) ? "Yes" : "No", (long)rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", (long)rlo
->_order
, name
, addr
, contextDesc
);
3468 CFRelease(contextDesc
);
3472 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3473 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3474 CFRunLoopObserverInvalidate(rlo
);
3475 pthread_mutex_destroy(&rlo
->_lock
);
3478 static const CFRuntimeClass __CFRunLoopObserverClass
= {
3480 "CFRunLoopObserver",
3483 __CFRunLoopObserverDeallocate
,
3487 __CFRunLoopObserverCopyDescription
3490 CFTypeID
CFRunLoopObserverGetTypeID(void) {
3491 static dispatch_once_t initOnce
;
3492 dispatch_once(&initOnce
, ^{ __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
); });
3493 return __kCFRunLoopObserverTypeID
;
3496 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
3498 CFRunLoopObserverRef memory
;
3500 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
3501 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, CFRunLoopObserverGetTypeID(), size
, NULL
);
3502 if (NULL
== memory
) {
3505 __CFSetValid(memory
);
3506 __CFRunLoopObserverUnsetFiring(memory
);
3508 __CFRunLoopObserverSetRepeats(memory
);
3510 __CFRunLoopObserverUnsetRepeats(memory
);
3512 __CFRunLoopLockInit(&memory
->_lock
);
3513 memory
->_runLoop
= NULL
;
3514 memory
->_rlCount
= 0;
3515 memory
->_activities
= activities
;
3516 memory
->_order
= order
;
3517 memory
->_callout
= callout
;
3519 if (context
->retain
) {
3520 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3522 memory
->_context
.info
= context
->info
;
3524 memory
->_context
.retain
= context
->retain
;
3525 memory
->_context
.release
= context
->release
;
3526 memory
->_context
.copyDescription
= context
->copyDescription
;
3528 memory
->_context
.info
= 0;
3529 memory
->_context
.retain
= 0;
3530 memory
->_context
.release
= 0;
3531 memory
->_context
.copyDescription
= 0;
3536 static void _runLoopObserverWithBlockContext(CFRunLoopObserverRef observer
, CFRunLoopActivity activity
, void *opaqueBlock
) {
3537 typedef void (^observer_block_t
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
);
3538 observer_block_t block
= (observer_block_t
)opaqueBlock
;
3539 block(observer
, activity
);
3542 CFRunLoopObserverRef
CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
,
3543 void (^block
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
)) {
3544 CFRunLoopObserverContext blockContext
;
3545 blockContext
.version
= 0;
3546 blockContext
.info
= (void *)block
;
3547 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3548 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3549 blockContext
.copyDescription
= NULL
;
3550 return CFRunLoopObserverCreate(allocator
, activities
, repeats
, order
, _runLoopObserverWithBlockContext
, &blockContext
);
3553 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
3555 __CFGenericValidateType(rlo
, CFRunLoopObserverGetTypeID());
3556 return rlo
->_activities
;
3559 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
3561 __CFGenericValidateType(rlo
, CFRunLoopObserverGetTypeID());
3565 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
3567 __CFGenericValidateType(rlo
, CFRunLoopObserverGetTypeID());
3568 return __CFRunLoopObserverRepeats(rlo
);
3571 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
3573 __CFGenericValidateType(rlo
, CFRunLoopObserverGetTypeID());
3574 __CFRunLoopObserverLock(rlo
);
3576 if (__CFIsValid(rlo
)) {
3577 CFRunLoopRef rl
= rlo
->_runLoop
;
3578 void *info
= rlo
->_context
.info
;
3579 rlo
->_context
.info
= NULL
;
3580 __CFUnsetValid(rlo
);
3582 // To avoid A->B, B->A lock ordering issues when coming up
3583 // towards the run loop from an observer, it has to be
3584 // unlocked, which means we have to protect from object
3587 __CFRunLoopObserverUnlock(rlo
);
3588 // CFRunLoopRemoveObserver will lock the run loop while it
3589 // needs that, but we also lock it out here to keep
3590 // changes from occurring for this whole sequence.
3591 __CFRunLoopLock(rl
);
3592 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3593 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
3594 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3595 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
3597 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
3598 __CFRunLoopUnlock(rl
);
3601 __CFRunLoopObserverLock(rlo
);
3603 if (NULL
!= rlo
->_context
.release
) {
3604 rlo
->_context
.release(info
); /* CALLOUT */
3607 __CFRunLoopObserverUnlock(rlo
);
3611 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
3613 return __CFIsValid(rlo
);
3616 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
3618 __CFGenericValidateType(rlo
, CFRunLoopObserverGetTypeID());
3619 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3620 *context
= rlo
->_context
;
3624 #pragma mark CFRunLoopTimer
3626 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3627 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3628 CFStringRef contextDesc
= NULL
;
3629 if (NULL
!= rlt
->_context
.copyDescription
) {
3630 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
3632 if (NULL
== contextDesc
) {
3633 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
3635 void *addr
= (void *)rlt
->_callout
;
3636 char libraryName
[2048];
3637 char functionName
[2048];
3638 void *functionPtr
= NULL
;
3639 libraryName
[0] = '?'; libraryName
[1] = '\0';
3640 functionName
[0] = '?'; functionName
[1] = '\0';
3641 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
,
3642 CFSTR("<CFRunLoopTimer %p [%p]>{valid = %s, firing = %s, interval = %0.09g, tolerance = %0.09g, next fire date = %0.09g (%0.09g @ %lld), callout = %s (%p / %p) (%s), context = %@}"),
3644 CFGetAllocator(rlt
),
3645 __CFIsValid(rlt
) ? "Yes" : "No",
3646 __CFRunLoopTimerIsFiring(rlt
) ? "Yes" : "No",
3650 rlt
->_nextFireDate
- CFAbsoluteTimeGetCurrent(),
3657 CFRelease(contextDesc
);
3661 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3662 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3663 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3664 __CFRunLoopTimerSetDeallocating(rlt
);
3665 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
3666 CFRelease(rlt
->_rlModes
);
3667 rlt
->_rlModes
= NULL
;
3668 pthread_mutex_destroy(&rlt
->_lock
);
3671 static const CFRuntimeClass __CFRunLoopTimerClass
= {
3676 __CFRunLoopTimerDeallocate
,
3680 __CFRunLoopTimerCopyDescription
3683 CFTypeID
CFRunLoopTimerGetTypeID(void) {
3684 static dispatch_once_t initOnce
;
3685 dispatch_once(&initOnce
, ^{ __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
); });
3686 return __kCFRunLoopTimerTypeID
;
3689 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
3691 if (isnan(interval
)) {
3692 CRSetCrashLogMessage("NaN was used as an interval for a CFRunLoopTimer");
3695 CFRunLoopTimerRef memory
;
3697 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
3698 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, CFRunLoopTimerGetTypeID(), size
, NULL
);
3699 if (NULL
== memory
) {
3702 __CFSetValid(memory
);
3703 __CFRunLoopTimerUnsetFiring(memory
);
3704 __CFRunLoopLockInit(&memory
->_lock
);
3705 memory
->_runLoop
= NULL
;
3706 memory
->_rlModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3707 memory
->_order
= order
;
3708 if (interval
< 0.0) interval
= 0.0;
3709 memory
->_interval
= interval
;
3710 memory
->_tolerance
= 0.0;
3711 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3712 memory
->_nextFireDate
= fireDate
;
3713 memory
->_fireTSR
= 0ULL;
3714 uint64_t now2
= mach_absolute_time();
3715 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3716 if (fireDate
< now1
) {
3717 memory
->_fireTSR
= now2
;
3718 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3719 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3721 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3723 memory
->_callout
= callout
;
3724 if (NULL
!= context
) {
3725 if (context
->retain
) {
3726 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3728 memory
->_context
.info
= context
->info
;
3730 memory
->_context
.retain
= context
->retain
;
3731 memory
->_context
.release
= context
->release
;
3732 memory
->_context
.copyDescription
= context
->copyDescription
;
3734 memory
->_context
.info
= 0;
3735 memory
->_context
.retain
= 0;
3736 memory
->_context
.release
= 0;
3737 memory
->_context
.copyDescription
= 0;
3742 static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer
, void *opaqueBlock
) {
3743 typedef void (^timer_block_t
) (CFRunLoopTimerRef timer
);
3744 timer_block_t block
= (timer_block_t
)opaqueBlock
;
3748 CFRunLoopTimerRef
CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
,
3749 void (^block
) (CFRunLoopTimerRef timer
)) {
3751 CFRunLoopTimerContext blockContext
;
3752 blockContext
.version
= 0;
3753 blockContext
.info
= (void *)block
;
3754 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3755 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3756 blockContext
.copyDescription
= NULL
;
3757 return CFRunLoopTimerCreate(allocator
, fireDate
, interval
, flags
, order
, _runLoopTimerWithBlockContext
, &blockContext
);
3760 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
3762 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFAbsoluteTime
, (NSTimer
*)rlt
, _cffireTime
);
3763 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3764 CFAbsoluteTime at
= 0.0;
3765 __CFRunLoopTimerLock(rlt
);
3766 __CFRunLoopTimerFireTSRLock();
3767 if (__CFIsValid(rlt
)) {
3768 at
= rlt
->_nextFireDate
;
3770 __CFRunLoopTimerFireTSRUnlock();
3771 __CFRunLoopTimerUnlock(rlt
);
3775 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
3777 if (!__CFIsValid(rlt
)) return;
3778 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3779 uint64_t nextFireTSR
= 0ULL;
3780 uint64_t now2
= mach_absolute_time();
3781 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3782 if (fireDate
< now1
) {
3784 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3785 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3787 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3789 __CFRunLoopTimerLock(rlt
);
3790 if (NULL
!= rlt
->_runLoop
) {
3791 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3792 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
3793 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3794 // To avoid A->B, B->A lock ordering issues when coming up
3795 // towards the run loop from a source, the timer has to be
3796 // unlocked, which means we have to protect from object
3797 // invalidation, although that's somewhat expensive.
3798 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3799 CFRetain(modes
[idx
]);
3801 CFRunLoopRef rl
= (CFRunLoopRef
)CFRetain(rlt
->_runLoop
);
3802 __CFRunLoopTimerUnlock(rlt
);
3803 __CFRunLoopLock(rl
);
3804 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3805 CFStringRef name
= (CFStringRef
)modes
[idx
];
3806 modes
[idx
] = __CFRunLoopFindMode(rl
, name
, false);
3809 __CFRunLoopTimerFireTSRLock();
3810 rlt
->_fireTSR
= nextFireTSR
;
3811 rlt
->_nextFireDate
= fireDate
;
3812 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3813 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
3815 __CFRepositionTimerInMode(rlm
, rlt
, true);
3818 __CFRunLoopTimerFireTSRUnlock();
3819 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3820 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
3822 __CFRunLoopUnlock(rl
);
3823 // This is setting the date of a timer, not a direct
3824 // interaction with a run loop, so we'll do a wakeup
3825 // (which may be costly) for the caller, just in case.
3826 // (And useful for binary compatibility with older
3827 // code used to the older timer implementation.)
3828 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
3831 __CFRunLoopTimerFireTSRLock();
3832 rlt
->_fireTSR
= nextFireTSR
;
3833 rlt
->_nextFireDate
= fireDate
;
3834 __CFRunLoopTimerFireTSRUnlock();
3835 __CFRunLoopTimerUnlock(rlt
);
3839 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
3841 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFTimeInterval
, (NSTimer
*)rlt
, timeInterval
);
3842 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3843 return rlt
->_interval
;
3846 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
3848 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3849 return (0.0 < rlt
->_interval
);
3852 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
3854 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3858 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
3860 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), void, (NSTimer
*)rlt
, invalidate
);
3861 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3862 __CFRunLoopTimerLock(rlt
);
3863 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3866 if (__CFIsValid(rlt
)) {
3867 CFRunLoopRef rl
= rlt
->_runLoop
;
3868 void *info
= rlt
->_context
.info
;
3869 rlt
->_context
.info
= NULL
;
3870 __CFUnsetValid(rlt
);
3872 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3873 STACK_BUFFER_DECL(CFStringRef
, modes
, cnt
);
3874 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3875 // To avoid A->B, B->A lock ordering issues when coming up
3876 // towards the run loop from a source, the timer has to be
3877 // unlocked, which means we have to protect from object
3878 // invalidation, although that's somewhat expensive.
3879 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3880 CFRetain(modes
[idx
]);
3883 __CFRunLoopTimerUnlock(rlt
);
3884 // CFRunLoopRemoveTimer will lock the run loop while it
3885 // needs that, but we also lock it out here to keep
3886 // changes from occurring for this whole sequence.
3887 __CFRunLoopLock(rl
);
3888 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3889 CFRunLoopRemoveTimer(rl
, rlt
, modes
[idx
]);
3891 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
3892 __CFRunLoopUnlock(rl
);
3893 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3894 CFRelease(modes
[idx
]);
3897 __CFRunLoopTimerLock(rlt
);
3899 if (NULL
!= rlt
->_context
.release
) {
3900 rlt
->_context
.release(info
); /* CALLOUT */
3903 __CFRunLoopTimerUnlock(rlt
);
3904 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3909 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
3911 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), Boolean
, (NSTimer
*)rlt
, isValid
);
3912 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3913 return __CFIsValid(rlt
);
3916 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
3918 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3919 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3920 *context
= rlt
->_context
;
3923 CFTimeInterval
CFRunLoopTimerGetTolerance(CFRunLoopTimerRef rlt
) {
3924 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3926 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFTimeInterval
, (NSTimer
*)rlt
, tolerance
);
3927 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3928 return rlt
->_tolerance
;
3934 void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef rlt
, CFTimeInterval tolerance
) {
3935 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3937 CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), void, (NSTimer
*)rlt
, setTolerance
:tolerance
);
3938 __CFGenericValidateType(rlt
, CFRunLoopTimerGetTypeID());
3942 * For the initial timer fire at 'start', the upper limit to the allowable
3943 * delay is set to 'leeway' nanoseconds. For the subsequent timer fires at
3944 * 'start' + N * 'interval', the upper limit is MIN('leeway','interval'/2).
3946 if (rlt
->_interval
> 0) {
3947 rlt
->_tolerance
= MIN(tolerance
, rlt
->_interval
/ 2);
3949 // Tolerance must be a positive value or zero
3950 if (tolerance
< 0) tolerance
= 0.0;
3951 rlt
->_tolerance
= tolerance
;