2 * Copyright (c) 2014 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-2013, 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 extern mach_port_t
_dispatch_get_main_queue_port_4CF(void);
58 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t
*msg
);
59 #elif DEPLOYMENT_TARGET_WINDOWS
61 DISPATCH_EXPORT HANDLE
_dispatch_get_main_queue_handle_4CF(void);
62 DISPATCH_EXPORT
void _dispatch_main_queue_callback_4CF(void);
64 #define MACH_PORT_NULL 0
65 #define mach_port_name_t HANDLE
66 #define mach_port_t HANDLE
67 #define _dispatch_get_main_queue_port_4CF _dispatch_get_main_queue_handle_4CF
68 #define _dispatch_main_queue_callback_4CF(x) _dispatch_main_queue_callback_4CF()
70 #define AbsoluteTime LARGE_INTEGER
74 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
75 CF_EXPORT pthread_t
_CF_pthread_main_thread_np(void);
76 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
80 #include <Block_private.h>
82 #if DEPLOYMENT_TARGET_MACOSX
83 #define USE_DISPATCH_SOURCE_FOR_TIMERS 1
84 #define USE_MK_TIMER_TOO 1
86 #define USE_DISPATCH_SOURCE_FOR_TIMERS 0
87 #define USE_MK_TIMER_TOO 1
91 static int _LogCFRunLoop
= 0;
92 static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer
, void *opaqueBlock
);
94 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
95 #define TIMER_DATE_LIMIT 4039289856.0
96 #define TIMER_INTERVAL_LIMIT 504911232.0
98 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
100 #define CRASH(string, errcode) do { char msg[256]; snprintf(msg, 256, string, errcode); CRSetCrashLogMessage(msg); HALT; } while (0)
102 #if DEPLOYMENT_TARGET_WINDOWS
104 static pthread_t kNilPthreadT
= { nil
, nil
};
105 #define pthreadPointer(a) a.p
106 typedef int kern_return_t
;
107 #define KERN_SUCCESS 0
111 static pthread_t kNilPthreadT
= (pthread_t
)0;
112 #define pthreadPointer(a) a
113 #define lockCount(a) a
118 #define CF_RUN_LOOP_PROBES 0
120 #if CF_RUN_LOOP_PROBES
121 #include "CFRunLoopProbes.h"
123 #define CFRUNLOOP_NEXT_TIMER_ARMED(arg0) do { } while (0)
124 #define CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED() (0)
125 #define CFRUNLOOP_POLL() do { } while (0)
126 #define CFRUNLOOP_POLL_ENABLED() (0)
127 #define CFRUNLOOP_SLEEP() do { } while (0)
128 #define CFRUNLOOP_SLEEP_ENABLED() (0)
129 #define CFRUNLOOP_SOURCE_FIRED(arg0, arg1, arg2) do { } while (0)
130 #define CFRUNLOOP_SOURCE_FIRED_ENABLED() (0)
131 #define CFRUNLOOP_TIMER_CREATED(arg0, arg1, arg2, arg3, arg4, arg5, arg6) do { } while (0)
132 #define CFRUNLOOP_TIMER_CREATED_ENABLED() (0)
133 #define CFRUNLOOP_TIMER_FIRED(arg0, arg1, arg2, arg3, arg4) do { } while (0)
134 #define CFRUNLOOP_TIMER_FIRED_ENABLED() (0)
135 #define CFRUNLOOP_TIMER_RESCHEDULED(arg0, arg1, arg2, arg3, arg4, arg5) do { } while (0)
136 #define CFRUNLOOP_TIMER_RESCHEDULED_ENABLED() (0)
137 #define CFRUNLOOP_WAKEUP(arg0) do { } while (0)
138 #define CFRUNLOOP_WAKEUP_ENABLED() (0)
139 #define CFRUNLOOP_WAKEUP_FOR_DISPATCH() do { } while (0)
140 #define CFRUNLOOP_WAKEUP_FOR_DISPATCH_ENABLED() (0)
141 #define CFRUNLOOP_WAKEUP_FOR_NOTHING() do { } while (0)
142 #define CFRUNLOOP_WAKEUP_FOR_NOTHING_ENABLED() (0)
143 #define CFRUNLOOP_WAKEUP_FOR_SOURCE() do { } while (0)
144 #define CFRUNLOOP_WAKEUP_FOR_SOURCE_ENABLED() (0)
145 #define CFRUNLOOP_WAKEUP_FOR_TIMEOUT() do { } while (0)
146 #define CFRUNLOOP_WAKEUP_FOR_TIMEOUT_ENABLED() (0)
147 #define CFRUNLOOP_WAKEUP_FOR_TIMER() do { } while (0)
148 #define CFRUNLOOP_WAKEUP_FOR_TIMER_ENABLED() (0)
149 #define CFRUNLOOP_WAKEUP_FOR_WAKEUP() do { } while (0)
150 #define CFRUNLOOP_WAKEUP_FOR_WAKEUP_ENABLED() (0)
153 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
154 // simple abstraction layer spanning Mach ports and Windows HANDLES
155 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
157 CF_PRIVATE
uint32_t __CFGetProcessPortCount(void) {
158 ipc_info_space_t info
;
159 ipc_info_name_array_t table
= 0;
160 mach_msg_type_number_t tableCount
= 0;
161 ipc_info_tree_name_array_t tree
= 0;
162 mach_msg_type_number_t treeCount
= 0;
164 kern_return_t ret
= mach_port_space_info(mach_task_self(), &info
, &table
, &tableCount
, &tree
, &treeCount
);
165 if (ret
!= KERN_SUCCESS
) {
169 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)table
, tableCount
* sizeof(*table
));
172 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)tree
, treeCount
* sizeof(*tree
));
174 return (uint32_t)tableCount
;
177 CF_PRIVATE CFArrayRef
__CFStopAllThreads(void) {
178 CFMutableArrayRef suspended_list
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
179 mach_port_t my_task
= mach_task_self();
180 mach_port_t my_thread
= mach_thread_self();
181 thread_act_array_t thr_list
= 0;
182 mach_msg_type_number_t thr_cnt
= 0;
184 // really, should loop doing the stopping until no more threads get added to the list N times in a row
185 kern_return_t ret
= task_threads(my_task
, &thr_list
, &thr_cnt
);
186 if (ret
== KERN_SUCCESS
) {
187 for (CFIndex idx
= 0; idx
< thr_cnt
; idx
++) {
188 thread_act_t thread
= thr_list
[idx
];
189 if (thread
== my_thread
) continue;
190 if (CFArrayContainsValue(suspended_list
, CFRangeMake(0, CFArrayGetCount(suspended_list
)), (const void *)(uintptr_t)thread
)) continue;
191 ret
= thread_suspend(thread
);
192 if (ret
== KERN_SUCCESS
) {
193 CFArrayAppendValue(suspended_list
, (const void *)(uintptr_t)thread
);
195 mach_port_deallocate(my_task
, thread
);
198 vm_deallocate(my_task
, (vm_address_t
)thr_list
, sizeof(thread_t
) * thr_cnt
);
200 mach_port_deallocate(my_task
, my_thread
);
201 return suspended_list
;
204 CF_PRIVATE
void __CFRestartAllThreads(CFArrayRef threads
) {
205 for (CFIndex idx
= 0; idx
< CFArrayGetCount(threads
); idx
++) {
206 thread_act_t thread
= (thread_act_t
)(uintptr_t)CFArrayGetValueAtIndex(threads
, idx
);
207 kern_return_t ret
= thread_resume(thread
);
208 if (ret
!= KERN_SUCCESS
) CRASH("*** Failure from thread_resume (%d) ***", ret
);
209 mach_port_deallocate(mach_task_self(), thread
);
213 static uint32_t __CF_last_warned_port_count
= 0;
215 static void foo() __attribute__((unused
));
217 uint32_t pcnt
= __CFGetProcessPortCount();
218 if (__CF_last_warned_port_count
+ 1000 < pcnt
) {
219 CFArrayRef threads
= __CFStopAllThreads();
223 CFOptionFlags responseFlags
= 0;
224 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
);
226 CFLog(3, CFSTR("ERROR"));
228 switch (responseFlags
) {
229 case kCFUserNotificationDefaultResponse
: CFLog(3, CFSTR("DefaultR")); break;
230 case kCFUserNotificationAlternateResponse
: CFLog(3, CFSTR("AltR")); break;
231 case kCFUserNotificationOtherResponse
: CFLog(3, CFSTR("OtherR")); break;
232 case kCFUserNotificationCancelResponse
: CFLog(3, CFSTR("CancelR")); break;
237 __CFRestartAllThreads(threads
);
239 __CF_last_warned_port_count
= pcnt
;
244 typedef mach_port_t __CFPort
;
245 #define CFPORT_NULL MACH_PORT_NULL
246 typedef mach_port_t __CFPortSet
;
248 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
249 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret
) { HALT
; };
251 static __CFPort
__CFPortAllocate(void) {
252 __CFPort result
= CFPORT_NULL
;
253 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
254 if (KERN_SUCCESS
!= ret
) {
256 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
);
257 CRSetCrashLogMessage(msg
);
258 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret
);
262 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
263 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to set send right on mach port. (%d) ***", ret
);
266 mach_port_limits_t limits
;
267 limits
.mpl_qlimit
= 1;
268 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
269 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to set attributes on mach port. (%d) ***", ret
);
274 CF_INLINE
void __CFPortFree(__CFPort port
) {
275 mach_port_destroy(mach_task_self(), port
);
278 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) __attribute__((noinline
));
279 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret
) { HALT
; };
281 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
283 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
284 if (KERN_SUCCESS
!= ret
) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret
); }
285 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
288 CF_INLINE kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
289 if (MACH_PORT_NULL
== port
) {
292 return mach_port_insert_member(mach_task_self(), port
, portSet
);
295 CF_INLINE kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
296 if (MACH_PORT_NULL
== port
) {
299 return mach_port_extract_member(mach_task_self(), port
, portSet
);
302 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
304 mach_port_name_array_t array
;
305 mach_msg_type_number_t idx
, number
;
307 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
308 if (KERN_SUCCESS
== ret
) {
309 for (idx
= 0; idx
< number
; idx
++) {
310 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
312 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
314 mach_port_destroy(mach_task_self(), portSet
);
317 #elif DEPLOYMENT_TARGET_WINDOWS
319 typedef HANDLE __CFPort
;
320 #define CFPORT_NULL NULL
322 // A simple dynamic array of HANDLEs, which grows to a high-water mark
323 typedef struct ___CFPortSet
{
327 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
330 CF_INLINE __CFPort
__CFPortAllocate(void) {
331 return CreateEventA(NULL
, true, false, NULL
);
334 CF_INLINE
void __CFPortFree(__CFPort port
) {
338 static __CFPortSet
__CFPortSetAllocate(void) {
339 __CFPortSet result
= (__CFPortSet
)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
342 result
->handles
= (HANDLE
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
343 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
347 static void __CFPortSetFree(__CFPortSet portSet
) {
348 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
349 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
352 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
353 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
354 __CFSpinLock(&(portSet
->lock
));
355 __CFPort
*result
= portBuf
;
356 if (bufSize
< portSet
->used
)
357 result
= (__CFPort
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
358 if (portSet
->used
> 1) {
359 // rotate the ports to vaguely simulate round-robin behaviour
360 uint16_t lastPort
= portSet
->used
- 1;
361 HANDLE swapHandle
= portSet
->handles
[0];
362 memmove(portSet
->handles
, &portSet
->handles
[1], lastPort
* sizeof(HANDLE
));
363 portSet
->handles
[lastPort
] = swapHandle
;
365 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
366 *portsUsed
= portSet
->used
;
367 __CFSpinUnlock(&(portSet
->lock
));
371 static kern_return_t
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
375 __CFSpinLock(&(portSet
->lock
));
376 if (portSet
->used
>= portSet
->size
) {
378 portSet
->handles
= (HANDLE
*)CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
380 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
) {
381 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
383 portSet
->handles
[portSet
->used
++] = port
;
384 __CFSpinUnlock(&(portSet
->lock
));
388 static kern_return_t
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
393 __CFSpinLock(&(portSet
->lock
));
394 for (i
= 0; i
< portSet
->used
; i
++) {
395 if (portSet
->handles
[i
] == port
) {
396 for (j
= i
+1; j
< portSet
->used
; j
++) {
397 portSet
->handles
[j
-1] = portSet
->handles
[j
];
400 __CFSpinUnlock(&(portSet
->lock
));
404 __CFSpinUnlock(&(portSet
->lock
));
410 #if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H)
411 #if defined(__BIG_ENDIAN__)
412 typedef struct UnsignedWide
{
416 #elif defined(__LITTLE_ENDIAN__)
417 typedef struct UnsignedWide
{
422 typedef UnsignedWide AbsoluteTime
;
425 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
427 #if USE_DISPATCH_SOURCE_FOR_TIMERS
430 extern mach_port_name_t
mk_timer_create(void);
431 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
432 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
433 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
435 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(uint64_t x
) {
438 a
.lo
= x
& (uint64_t)0xFFFFFFFF;
443 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
444 kern_return_t result
;
445 mach_msg_header_t header
;
446 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
447 header
.msgh_size
= sizeof(mach_msg_header_t
);
448 header
.msgh_remote_port
= port
;
449 header
.msgh_local_port
= MACH_PORT_NULL
;
450 header
.msgh_id
= msg_id
;
451 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
452 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
455 #elif DEPLOYMENT_TARGET_WINDOWS
457 static HANDLE
mk_timer_create(void) {
458 return CreateWaitableTimer(NULL
, FALSE
, NULL
);
461 static kern_return_t
mk_timer_destroy(HANDLE name
) {
462 BOOL res
= CloseHandle(name
);
464 DWORD err
= GetLastError();
465 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to destroy timer: %d"), err
);
470 static kern_return_t
mk_timer_arm(HANDLE name
, LARGE_INTEGER expire_time
) {
471 BOOL res
= SetWaitableTimer(name
, &expire_time
, 0, NULL
, NULL
, FALSE
);
473 DWORD err
= GetLastError();
474 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to set timer: %d"), err
);
479 static kern_return_t
mk_timer_cancel(HANDLE name
, LARGE_INTEGER
*result_time
) {
480 BOOL res
= CancelWaitableTimer(name
);
482 DWORD err
= GetLastError();
483 CFLog(kCFLogLevelError
, CFSTR("CFRunLoop: Unable to cancel timer: %d"), err
);
488 // 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.
489 CF_INLINE LARGE_INTEGER
__CFUInt64ToAbsoluteTime(uint64_t desiredFireTime
) {
490 LARGE_INTEGER result
;
491 // 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.
492 uint64_t now
= mach_absolute_time();
493 if (now
> desiredFireTime
) {
496 uint64_t timeDiff
= desiredFireTime
- now
;
497 CFTimeInterval amountOfTimeToWait
= __CFTSRToTimeInterval(timeDiff
);
498 // Result is in 100 ns (10**-7 sec) units to be consistent with a FILETIME.
499 // CFTimeInterval is in seconds.
500 result
.QuadPart
= -(amountOfTimeToWait
* 10000000);
510 /* unlock a run loop and modes before doing callouts/sleeping */
511 /* never try to take the run loop lock with a mode locked */
512 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
513 /* run loop mode structures should never be deallocated, even if they become empty */
515 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
516 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
517 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
518 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
519 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
521 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
523 struct __CFRunLoopMode
{
525 pthread_mutex_t _lock
; /* must have the run loop locked before locking this */
529 CFMutableSetRef _sources0
;
530 CFMutableSetRef _sources1
;
531 CFMutableArrayRef _observers
;
532 CFMutableArrayRef _timers
;
533 CFMutableDictionaryRef _portToV1SourceMap
;
534 __CFPortSet _portSet
;
535 CFIndex _observerMask
;
536 #if USE_DISPATCH_SOURCE_FOR_TIMERS
537 dispatch_source_t _timerSource
;
538 dispatch_queue_t _queue
;
539 Boolean _timerFired
; // set to true by the source when a timer has fired
540 Boolean _dispatchTimerArmed
;
543 mach_port_t _timerPort
;
544 Boolean _mkTimerArmed
;
546 #if DEPLOYMENT_TARGET_WINDOWS
548 void (*_msgPump
)(void);
550 uint64_t _timerSoftDeadline
; /* TSR */
551 uint64_t _timerHardDeadline
; /* TSR */
554 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
555 pthread_mutex_lock(&(rlm
->_lock
));
556 //CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm);
559 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
560 //CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm);
561 pthread_mutex_unlock(&(rlm
->_lock
));
564 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
565 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
566 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
567 return CFEqual(rlm1
->_name
, rlm2
->_name
);
570 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
571 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
572 return CFHash(rlm
->_name
);
575 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
576 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
577 CFMutableStringRef result
;
578 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
579 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
);
580 CFStringAppendFormat(result
, NULL
, CFSTR("port set = 0x%x, "), rlm
->_portSet
);
581 #if USE_DISPATCH_SOURCE_FOR_TIMERS
582 CFStringAppendFormat(result
, NULL
, CFSTR("queue = %p, "), rlm
->_queue
);
583 CFStringAppendFormat(result
, NULL
, CFSTR("source = %p (%s), "), rlm
->_timerSource
, rlm
->_timerFired
? "fired" : "not fired");
586 CFStringAppendFormat(result
, NULL
, CFSTR("timer port = 0x%x, "), rlm
->_timerPort
);
588 #if DEPLOYMENT_TARGET_WINDOWS
589 CFStringAppendFormat(result
, NULL
, CFSTR("MSGQ mask = %p, "), rlm
->_msgQMask
);
591 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
);
595 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
596 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
597 if (NULL
!= rlm
->_sources0
) CFRelease(rlm
->_sources0
);
598 if (NULL
!= rlm
->_sources1
) CFRelease(rlm
->_sources1
);
599 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
600 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
601 if (NULL
!= rlm
->_portToV1SourceMap
) CFRelease(rlm
->_portToV1SourceMap
);
602 CFRelease(rlm
->_name
);
603 __CFPortSetFree(rlm
->_portSet
);
604 #if USE_DISPATCH_SOURCE_FOR_TIMERS
605 if (rlm
->_timerSource
) {
606 dispatch_source_cancel(rlm
->_timerSource
);
607 dispatch_release(rlm
->_timerSource
);
610 dispatch_release(rlm
->_queue
);
614 if (MACH_PORT_NULL
!= rlm
->_timerPort
) mk_timer_destroy(rlm
->_timerPort
);
616 pthread_mutex_destroy(&rlm
->_lock
);
617 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x7C, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
));
621 #pragma mark Run Loops
624 struct _block_item
*_next
;
625 CFTypeRef _mode
; // CFString or CFSet
626 void (^_block
)(void);
629 typedef struct _per_run_data
{
633 uint32_t ignoreWakeUps
;
638 pthread_mutex_t _lock
; /* locked for accessing mode list */
639 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
641 volatile _per_run_data
*_perRunData
; // reset for runs of the run loop
644 CFMutableSetRef _commonModes
;
645 CFMutableSetRef _commonModeItems
;
646 CFRunLoopModeRef _currentMode
;
647 CFMutableSetRef _modes
;
648 struct _block_item
*_blocks_head
;
649 struct _block_item
*_blocks_tail
;
650 CFTypeRef _counterpart
;
653 /* Bit 0 of the base reserved bits is used for stopped state */
654 /* Bit 1 of the base reserved bits is used for sleeping state */
655 /* Bit 2 of the base reserved bits is used for deallocating state */
657 CF_INLINE
volatile _per_run_data
*__CFRunLoopPushPerRunData(CFRunLoopRef rl
) {
658 volatile _per_run_data
*previous
= rl
->_perRunData
;
659 rl
->_perRunData
= (volatile _per_run_data
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(_per_run_data
), 0);
660 rl
->_perRunData
->a
= 0x4346524C;
661 rl
->_perRunData
->b
= 0x4346524C; // 'CFRL'
662 rl
->_perRunData
->stopped
= 0x00000000;
663 rl
->_perRunData
->ignoreWakeUps
= 0x00000000;
667 CF_INLINE
void __CFRunLoopPopPerRunData(CFRunLoopRef rl
, volatile _per_run_data
*previous
) {
668 if (rl
->_perRunData
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (void *)rl
->_perRunData
);
669 rl
->_perRunData
= previous
;
672 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
673 return (rl
->_perRunData
->stopped
) ? true : false;
676 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
677 rl
->_perRunData
->stopped
= 0x53544F50; // 'STOP'
680 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
681 rl
->_perRunData
->stopped
= 0x0;
684 CF_INLINE Boolean
__CFRunLoopIsIgnoringWakeUps(CFRunLoopRef rl
) {
685 return (rl
->_perRunData
->ignoreWakeUps
) ? true : false;
688 CF_INLINE
void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl
) {
689 rl
->_perRunData
->ignoreWakeUps
= 0x57414B45; // 'WAKE'
692 CF_INLINE
void __CFRunLoopUnsetIgnoreWakeUps(CFRunLoopRef rl
) {
693 rl
->_perRunData
->ignoreWakeUps
= 0x0;
696 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
697 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
700 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
701 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
704 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
705 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
708 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
709 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
712 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
713 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
716 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
717 pthread_mutex_lock(&(((CFRunLoopRef
)rl
)->_lock
));
718 // CFLog(6, CFSTR("__CFRunLoopLock locked %p"), rl);
721 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
722 // CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl);
723 pthread_mutex_unlock(&(((CFRunLoopRef
)rl
)->_lock
));
726 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
727 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
728 CFMutableStringRef result
;
729 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
730 #if DEPLOYMENT_TARGET_WINDOWS
731 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)"));
733 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)"));
735 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
739 CF_PRIVATE
void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
740 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
743 CF_INLINE
void __CFRunLoopLockInit(pthread_mutex_t
*lock
) {
744 pthread_mutexattr_t mattr
;
745 pthread_mutexattr_init(&mattr
);
746 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_RECURSIVE
);
747 int32_t mret
= pthread_mutex_init(lock
, &mattr
);
748 pthread_mutexattr_destroy(&mattr
);
753 /* call with rl locked, returns mode locked */
754 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
756 CFRunLoopModeRef rlm
;
757 struct __CFRunLoopMode srlm
;
758 memset(&srlm
, 0, sizeof(srlm
));
759 _CFRuntimeSetInstanceTypeIDAndIsa(&srlm
, __kCFRunLoopModeTypeID
);
760 srlm
._name
= modeName
;
761 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
763 __CFRunLoopModeLock(rlm
);
769 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
773 __CFRunLoopLockInit(&rlm
->_lock
);
774 rlm
->_name
= CFStringCreateCopy(kCFAllocatorSystemDefault
, modeName
);
775 rlm
->_stopped
= false;
776 rlm
->_portToV1SourceMap
= NULL
;
777 rlm
->_sources0
= NULL
;
778 rlm
->_sources1
= NULL
;
779 rlm
->_observers
= NULL
;
781 rlm
->_observerMask
= 0;
782 rlm
->_portSet
= __CFPortSetAllocate();
783 rlm
->_timerSoftDeadline
= UINT64_MAX
;
784 rlm
->_timerHardDeadline
= UINT64_MAX
;
786 kern_return_t ret
= KERN_SUCCESS
;
787 #if USE_DISPATCH_SOURCE_FOR_TIMERS
788 rlm
->_timerFired
= false;
789 rlm
->_queue
= _dispatch_runloop_root_queue_create_4CF("Run Loop Mode Queue", 0);
790 mach_port_t queuePort
= _dispatch_runloop_root_queue_get_port_4CF(rlm
->_queue
);
791 if (queuePort
== MACH_PORT_NULL
) CRASH("*** Unable to create run loop mode queue port. (%d) ***", -1);
792 rlm
->_timerSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, rlm
->_queue
);
794 __block Boolean
*timerFiredPointer
= &(rlm
->_timerFired
);
795 dispatch_source_set_event_handler(rlm
->_timerSource
, ^{
796 *timerFiredPointer
= true;
799 // Set timer to far out there. The unique leeway makes this timer easy to spot in debug output.
800 _dispatch_source_set_runloop_timer_4CF(rlm
->_timerSource
, DISPATCH_TIME_FOREVER
, DISPATCH_TIME_FOREVER
, 321);
801 dispatch_resume(rlm
->_timerSource
);
803 ret
= __CFPortSetInsert(queuePort
, rlm
->_portSet
);
804 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret
);
808 rlm
->_timerPort
= mk_timer_create();
809 ret
= __CFPortSetInsert(rlm
->_timerPort
, rlm
->_portSet
);
810 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret
);
813 ret
= __CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
);
814 if (KERN_SUCCESS
!= ret
) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret
);
816 #if DEPLOYMENT_TARGET_WINDOWS
818 rlm
->_msgPump
= NULL
;
820 CFSetAddValue(rl
->_modes
, rlm
);
822 __CFRunLoopModeLock(rlm
); /* return mode locked */
827 // expects rl and rlm locked
828 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopModeRef previousMode
) {
830 if (NULL
== rlm
) return true;
831 #if DEPLOYMENT_TARGET_WINDOWS
832 if (0 != rlm
->_msgQMask
) return false;
834 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
835 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) return false; // represents the libdispatch main queue
836 if (NULL
!= rlm
->_sources0
&& 0 < CFSetGetCount(rlm
->_sources0
)) return false;
837 if (NULL
!= rlm
->_sources1
&& 0 < CFSetGetCount(rlm
->_sources1
)) return false;
838 if (NULL
!= rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) return false;
839 struct _block_item
*item
= rl
->_blocks_head
;
841 struct _block_item
*curr
= item
;
843 Boolean doit
= false;
844 if (CFStringGetTypeID() == CFGetTypeID(curr
->_mode
)) {
845 doit
= CFEqual(curr
->_mode
, rlm
->_name
) || (CFEqual(curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
847 doit
= CFSetContainsValue((CFSetRef
)curr
->_mode
, rlm
->_name
) || (CFSetContainsValue((CFSetRef
)curr
->_mode
, kCFRunLoopCommonModes
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
));
849 if (doit
) return false;
854 #if DEPLOYMENT_TARGET_WINDOWS
856 uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl
, CFStringRef modeName
) {
857 if (modeName
== kCFRunLoopCommonModes
) {
858 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
863 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
865 result
= rlm
->_msgQMask
;
866 __CFRunLoopModeUnlock(rlm
);
868 __CFRunLoopUnlock(rl
);
869 return (uint32_t)result
;
872 void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl
, uint32_t mask
, CFStringRef modeName
) {
873 if (modeName
== kCFRunLoopCommonModes
) {
874 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
878 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
879 rlm
->_msgQMask
= (DWORD
)mask
;
880 __CFRunLoopModeUnlock(rlm
);
881 __CFRunLoopUnlock(rl
);
884 uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl
) {
885 return rl
->_winthread
;
888 CFWindowsMessageQueueHandler
_CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
) {
889 if (modeName
== kCFRunLoopCommonModes
) {
890 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
893 if (rl
!= CFRunLoopGetCurrent()) {
894 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
897 void (*result
)(void) = NULL
;
899 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
901 result
= rlm
->_msgPump
;
902 __CFRunLoopModeUnlock(rlm
);
904 __CFRunLoopUnlock(rl
);
908 void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl
, CFStringRef modeName
, CFWindowsMessageQueueHandler func
) {
909 if (modeName
== kCFRunLoopCommonModes
) {
910 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
913 if (rl
!= CFRunLoopGetCurrent()) {
914 CFLog(kCFLogLevelError
, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
918 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
919 rlm
->_msgPump
= func
;
920 __CFRunLoopModeUnlock(rlm
);
921 __CFRunLoopUnlock(rl
);
929 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
931 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
932 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
935 CF_INLINE
void __CFSetValid(void *cf
) {
936 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
939 CF_INLINE
void __CFUnsetValid(void *cf
) {
940 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
943 struct __CFRunLoopSource
{
946 pthread_mutex_t _lock
;
947 CFIndex _order
; /* immutable */
948 CFMutableBagRef _runLoops
;
950 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
951 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
955 /* Bit 1 of the base reserved bits is used for signalled state */
957 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
958 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
961 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
962 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
965 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
966 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
969 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
970 pthread_mutex_lock(&(rls
->_lock
));
971 // CFLog(6, CFSTR("__CFRunLoopSourceLock locked %p"), rls);
974 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
975 // CFLog(6, CFSTR("__CFRunLoopSourceLock unlocking %p"), rls);
976 pthread_mutex_unlock(&(rls
->_lock
));
979 #pragma mark Observers
981 struct __CFRunLoopObserver
{
983 pthread_mutex_t _lock
;
984 CFRunLoopRef _runLoop
;
986 CFOptionFlags _activities
; /* immutable */
987 CFIndex _order
; /* immutable */
988 CFRunLoopObserverCallBack _callout
; /* immutable */
989 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
992 /* Bit 0 of the base reserved bits is used for firing state */
993 /* Bit 1 of the base reserved bits is used for repeats state */
995 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
996 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
999 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
1000 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
1003 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
1004 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
1007 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
1008 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
1011 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
1012 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
1015 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
1016 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
1019 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
1020 pthread_mutex_lock(&(rlo
->_lock
));
1021 // CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo);
1024 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
1025 // CFLog(6, CFSTR("__CFRunLoopObserverLock unlocking %p"), rlo);
1026 pthread_mutex_unlock(&(rlo
->_lock
));
1029 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1030 __CFRunLoopObserverLock(rlo
);
1031 if (0 == rlo
->_rlCount
) {
1035 __CFRunLoopObserverUnlock(rlo
);
1038 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1039 __CFRunLoopObserverLock(rlo
);
1041 if (0 == rlo
->_rlCount
) {
1042 rlo
->_runLoop
= NULL
;
1044 __CFRunLoopObserverUnlock(rlo
);
1049 struct __CFRunLoopTimer
{
1050 CFRuntimeBase _base
;
1052 pthread_mutex_t _lock
;
1053 CFRunLoopRef _runLoop
;
1054 CFMutableSetRef _rlModes
;
1055 CFAbsoluteTime _nextFireDate
;
1056 CFTimeInterval _interval
; /* immutable */
1057 CFTimeInterval _tolerance
; /* mutable */
1058 uint64_t _fireTSR
; /* TSR units */
1059 CFIndex _order
; /* immutable */
1060 CFRunLoopTimerCallBack _callout
; /* immutable */
1061 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
1064 /* Bit 0 of the base reserved bits is used for firing state */
1065 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
1066 /* Bit 2 of the base reserved bits is used for waking state */
1068 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
1069 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 0, 0);
1072 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
1073 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 1);
1076 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
1077 __CFBitfieldSetValue(rlt
->_bits
, 0, 0, 0);
1080 CF_INLINE Boolean
__CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt
) {
1081 return (Boolean
)__CFBitfieldGetValue(rlt
->_bits
, 2, 2);
1084 CF_INLINE
void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt
) {
1085 __CFBitfieldSetValue(rlt
->_bits
, 2, 2, 1);
1088 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
1089 pthread_mutex_lock(&(rlt
->_lock
));
1090 // CFLog(6, CFSTR("__CFRunLoopTimerLock locked %p"), rlt);
1093 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
1094 // CFLog(6, CFSTR("__CFRunLoopTimerLock unlocking %p"), rlt);
1095 pthread_mutex_unlock(&(rlt
->_lock
));
1098 static CFSpinLock_t __CFRLTFireTSRLock
= CFSpinLockInit
;
1100 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
1101 __CFSpinLock(&__CFRLTFireTSRLock
);
1104 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
1105 __CFSpinUnlock(&__CFRLTFireTSRLock
);
1112 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
1113 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
1115 // call with rl and rlm locked
1116 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
1118 CFRunLoopSourceRef found
= rlm
->_portToV1SourceMap
? (CFRunLoopSourceRef
)CFDictionaryGetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)port
) : NULL
;
1122 // Remove backreferences the mode's sources have to the rl (context);
1123 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1124 // the source from the run loops it is in, but during deallocation of a
1125 // run loop, we already know that the sources are going to be punted
1126 // from it, so invalidation of sources does not need to remove from a
1127 // deallocating run loop.
1128 static void __CFRunLoopCleanseSources(const void *value
, void *context
) {
1129 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1130 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1132 const void **list
, *buffer
[256];
1133 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1135 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1136 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1137 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1138 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1139 for (idx
= 0; idx
< cnt
; idx
++) {
1140 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1141 __CFRunLoopSourceLock(rls
);
1142 if (NULL
!= rls
->_runLoops
) {
1143 CFBagRemoveValue(rls
->_runLoops
, rl
);
1145 __CFRunLoopSourceUnlock(rls
);
1147 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1150 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
1151 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1152 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1154 const void **list
, *buffer
[256];
1155 if (NULL
== rlm
->_sources0
&& NULL
== rlm
->_sources1
) return;
1157 cnt
= (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0) + (rlm
->_sources1
? CFSetGetCount(rlm
->_sources1
) : 0);
1158 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1159 if (rlm
->_sources0
) CFSetGetValues(rlm
->_sources0
, list
);
1160 if (rlm
->_sources1
) CFSetGetValues(rlm
->_sources1
, list
+ (rlm
->_sources0
? CFSetGetCount(rlm
->_sources0
) : 0));
1161 for (idx
= 0; idx
< cnt
; idx
++) {
1162 CFRetain(list
[idx
]);
1164 if (rlm
->_sources0
) CFSetRemoveAllValues(rlm
->_sources0
);
1165 if (rlm
->_sources1
) CFSetRemoveAllValues(rlm
->_sources1
);
1166 for (idx
= 0; idx
< cnt
; idx
++) {
1167 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1168 __CFRunLoopSourceLock(rls
);
1169 if (NULL
!= rls
->_runLoops
) {
1170 CFBagRemoveValue(rls
->_runLoops
, rl
);
1172 __CFRunLoopSourceUnlock(rls
);
1173 if (0 == rls
->_context
.version0
.version
) {
1174 if (NULL
!= rls
->_context
.version0
.cancel
) {
1175 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
1177 } else if (1 == rls
->_context
.version0
.version
) {
1178 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1179 if (CFPORT_NULL
!= port
) {
1180 __CFPortSetRemove(port
, rlm
->_portSet
);
1185 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1188 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
1189 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1190 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
1192 const void **list
, *buffer
[256];
1193 if (NULL
== rlm
->_observers
) return;
1194 cnt
= CFArrayGetCount(rlm
->_observers
);
1195 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1196 CFArrayGetValues(rlm
->_observers
, CFRangeMake(0, cnt
), list
);
1197 for (idx
= 0; idx
< cnt
; idx
++) {
1198 CFRetain(list
[idx
]);
1200 CFArrayRemoveAllValues(rlm
->_observers
);
1201 for (idx
= 0; idx
< cnt
; idx
++) {
1202 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
1203 CFRelease(list
[idx
]);
1205 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1208 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
1209 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1210 if (NULL
== rlm
->_timers
) return;
1211 void (^deallocateTimers
)(CFMutableArrayRef timers
) = ^(CFMutableArrayRef timers
) {
1213 const void **list
, *buffer
[256];
1214 cnt
= CFArrayGetCount(timers
);
1215 list
= (const void **)((cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0));
1216 CFArrayGetValues(timers
, CFRangeMake(0, CFArrayGetCount(timers
)), list
);
1217 for (idx
= 0; idx
< cnt
; idx
++) {
1218 CFRetain(list
[idx
]);
1220 CFArrayRemoveAllValues(timers
);
1221 for (idx
= 0; idx
< cnt
; idx
++) {
1222 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1223 __CFRunLoopTimerLock(rlt
);
1224 // if the run loop is deallocating, and since a timer can only be in one
1225 // run loop, we're going to be removing the timer from all modes, so be
1226 // a little heavy-handed and direct
1227 CFSetRemoveAllValues(rlt
->_rlModes
);
1228 rlt
->_runLoop
= NULL
;
1229 __CFRunLoopTimerUnlock(rlt
);
1230 CFRelease(list
[idx
]);
1232 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1235 if (rlm
->_timers
&& CFArrayGetCount(rlm
->_timers
)) deallocateTimers(rlm
->_timers
);
1238 CF_EXPORT CFRunLoopRef
_CFRunLoopGet0b(pthread_t t
);
1240 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
1241 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
1243 if (_CFRunLoopGet0b(pthread_main_thread_np()) == cf
) HALT
;
1245 /* We try to keep the run loop in a valid state as long as possible,
1246 since sources may have non-retained references to the run loop.
1247 Another reason is that we don't want to lock the run loop for
1248 callback reasons, if we can get away without that. We start by
1249 eliminating the sources, since they are the most likely to call
1250 back into the run loop during their "cancellation". Common mode
1251 items will be removed from the mode indirectly by the following
1253 __CFRunLoopSetDeallocating(rl
);
1254 if (NULL
!= rl
->_modes
) {
1255 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopCleanseSources
), rl
); // remove references to rl
1256 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
1257 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
1258 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
1260 __CFRunLoopLock(rl
);
1261 struct _block_item
*item
= rl
->_blocks_head
;
1263 struct _block_item
*curr
= item
;
1265 CFRelease(curr
->_mode
);
1266 Block_release(curr
->_block
);
1269 if (NULL
!= rl
->_commonModeItems
) {
1270 CFRelease(rl
->_commonModeItems
);
1272 if (NULL
!= rl
->_commonModes
) {
1273 CFRelease(rl
->_commonModes
);
1275 if (NULL
!= rl
->_modes
) {
1276 CFRelease(rl
->_modes
);
1278 __CFPortFree(rl
->_wakeUpPort
);
1279 rl
->_wakeUpPort
= CFPORT_NULL
;
1280 __CFRunLoopPopPerRunData(rl
, NULL
);
1281 __CFRunLoopUnlock(rl
);
1282 pthread_mutex_destroy(&rl
->_lock
);
1283 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0x8C, sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
));
1286 static const CFRuntimeClass __CFRunLoopModeClass
= {
1291 __CFRunLoopModeDeallocate
,
1292 __CFRunLoopModeEqual
,
1293 __CFRunLoopModeHash
,
1295 __CFRunLoopModeCopyDescription
1298 static const CFRuntimeClass __CFRunLoopClass
= {
1303 __CFRunLoopDeallocate
,
1307 __CFRunLoopCopyDescription
1310 CF_PRIVATE
void __CFFinalizeRunLoop(uintptr_t data
);
1312 CF_PRIVATE
void __CFRunLoopInitialize(void) {
1313 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
1314 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
1317 CFTypeID
CFRunLoopGetTypeID(void) {
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
, __kCFRunLoopTypeID
, 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 CFSpinLock_t loopsLock
= CFSpinLockInit
;
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 __CFSpinLock(&loopsLock
);
1363 if (!__CFRunLoops
) {
1364 __CFSpinUnlock(&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 __CFSpinLock(&loopsLock
);
1374 CFRunLoopRef loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1375 __CFSpinUnlock(&loopsLock
);
1377 CFRunLoopRef newLoop
= __CFRunLoopCreate(t
);
1378 __CFSpinLock(&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 __CFSpinUnlock(&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 __CFSpinLock(&loopsLock
);
1403 CFRunLoopRef loop
= NULL
;
1405 loop
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(t
));
1407 __CFSpinUnlock(&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 __CFSpinLock(&loopsLock
);
1419 rl
= (CFRunLoopRef
)CFDictionaryGetValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1420 if (rl
) CFRetain(rl
);
1421 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1423 __CFSpinUnlock(&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 __CFSpinLock(&loopsLock
);
1452 ret
= rl
->_counterpart
;
1453 __CFSpinUnlock(&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 __CFSpinLock(&loopsLock
);
1470 CFDictionarySetValue(__CFRunLoops
, pthreadPointer(pthread_self()), rl
);
1472 CFDictionaryRemoveValue(__CFRunLoops
, pthreadPointer(pthread_self()));
1474 __CFSpinUnlock(&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
) == __kCFRunLoopSourceTypeID
) {
1528 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1529 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1530 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1531 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
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
) == __kCFRunLoopSourceTypeID
) {
1541 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1542 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1543 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1544 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
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
) == __kCFRunLoopSourceTypeID
) {
1554 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1555 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1556 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1557 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
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 getpid(); // 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 getpid(); // 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 getpid(); // 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 getpid(); // 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
) == __kCFRunLoopSourceTypeID
) {
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 getpid(); // 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 getpid(); // 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
) == __kCFRunLoopSourceTypeID
) {
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 uint64_t currentTSR
= mach_absolute_time();
2097 nextFireTSR
= oldFireTSR
;
2098 while (nextFireTSR
<= currentTSR
) {
2099 nextFireTSR
+= intervalTSR
;
2102 CFRunLoopRef rlt_rl
= rlt
->_runLoop
;
2105 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
2106 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
2107 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
2108 // To avoid A->B, B->A lock ordering issues when coming up
2109 // towards the run loop from a source, the timer has to be
2110 // unlocked, which means we have to protect from object
2111 // invalidation, although that's somewhat expensive.
2112 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2113 CFRetain(modes
[idx
]);
2115 __CFRunLoopTimerUnlock(rlt
);
2116 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2117 CFStringRef name
= (CFStringRef
)modes
[idx
];
2118 modes
[idx
] = (CFTypeRef
)__CFRunLoopFindMode(rlt_rl
, name
, false);
2121 __CFRunLoopTimerFireTSRLock();
2122 rlt
->_fireTSR
= nextFireTSR
;
2123 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR
);
2124 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2125 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
2127 __CFRepositionTimerInMode(rlm
, rlt
, true);
2130 __CFRunLoopTimerFireTSRUnlock();
2131 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2132 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
2136 __CFRunLoopTimerUnlock(rlt
);
2137 __CFRunLoopTimerFireTSRLock();
2138 rlt
->_fireTSR
= nextFireTSR
;
2139 rlt
->_nextFireDate
= CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR
);
2140 __CFRunLoopTimerFireTSRUnlock();
2144 __CFRunLoopTimerUnlock(rlt
);
2147 return timerHandled
;
2151 // rl and rlm are locked on entry and exit
2152 static Boolean
__CFRunLoopDoTimers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, uint64_t limitTSR
) { /* DOES CALLOUT */
2153 Boolean timerHandled
= false;
2154 CFMutableArrayRef timers
= NULL
;
2155 for (CFIndex idx
= 0, cnt
= rlm
->_timers
? CFArrayGetCount(rlm
->_timers
) : 0; idx
< cnt
; idx
++) {
2156 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, idx
);
2158 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
2159 if (rlt
->_fireTSR
<= limitTSR
) {
2160 if (!timers
) timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2161 CFArrayAppendValue(timers
, rlt
);
2166 for (CFIndex idx
= 0, cnt
= timers
? CFArrayGetCount(timers
) : 0; idx
< cnt
; idx
++) {
2167 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(timers
, idx
);
2168 Boolean did
= __CFRunLoopDoTimer(rl
, rlm
, rlt
);
2169 timerHandled
= timerHandled
|| did
;
2171 if (timers
) CFRelease(timers
);
2172 return timerHandled
;
2176 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
2178 CFRunLoopModeRef rlm
;
2179 Boolean result
= false;
2180 __CFRunLoopLock(rl
);
2181 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2182 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
, NULL
)) {
2185 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2186 __CFRunLoopUnlock(rl
);
2190 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) __attribute__((noinline
));
2192 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2194 #define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0)
2196 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
) {
2197 Boolean originalBuffer
= true;
2198 kern_return_t ret
= KERN_SUCCESS
;
2199 for (;;) { /* In that sleep of death what nightmares may come ... */
2200 mach_msg_header_t
*msg
= (mach_msg_header_t
*)*buffer
;
2202 msg
->msgh_local_port
= port
;
2203 msg
->msgh_remote_port
= MACH_PORT_NULL
;
2204 msg
->msgh_size
= buffer_size
;
2206 if (TIMEOUT_INFINITY
== timeout
) { CFRUNLOOP_SLEEP(); } else { CFRUNLOOP_POLL(); }
2207 ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|((TIMEOUT_INFINITY
!= timeout
) ? MACH_RCV_TIMEOUT
: 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV
), 0, msg
->msgh_size
, port
, timeout
, MACH_PORT_NULL
);
2208 CFRUNLOOP_WAKEUP(ret
);
2209 if (MACH_MSG_SUCCESS
== ret
) {
2210 *livePort
= msg
? msg
->msgh_local_port
: MACH_PORT_NULL
;
2213 if (MACH_RCV_TIMED_OUT
== ret
) {
2214 if (!originalBuffer
) free(msg
);
2216 *livePort
= MACH_PORT_NULL
;
2219 if (MACH_RCV_TOO_LARGE
!= ret
) break;
2220 buffer_size
= round_msg(msg
->msgh_size
+ MAX_TRAILER_SIZE
);
2221 if (originalBuffer
) *buffer
= NULL
;
2222 originalBuffer
= false;
2223 *buffer
= realloc(*buffer
, buffer_size
);
2229 #elif DEPLOYMENT_TARGET_WINDOWS
2231 #define TIMEOUT_INFINITY INFINITE
2233 // pass in either a portSet or onePort
2234 static Boolean
__CFRunLoopWaitForMultipleObjects(__CFPortSet portSet
, HANDLE
*onePort
, DWORD timeout
, DWORD mask
, HANDLE
*livePort
, Boolean
*msgReceived
) {
2235 DWORD waitResult
= WAIT_TIMEOUT
;
2236 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
2237 HANDLE
*handles
= NULL
;
2238 uint32_t handleCount
= 0;
2239 Boolean freeHandles
= false;
2240 Boolean result
= false;
2243 // copy out the handles to be safe from other threads at work
2244 handles
= __CFPortSetGetPorts(portSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
2245 freeHandles
= (handles
!= handleBuf
);
2249 freeHandles
= FALSE
;
2252 // The run loop mode and loop are already in proper unlocked state from caller
2253 waitResult
= MsgWaitForMultipleObjectsEx(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, timeout
, mask
, MWMO_INPUTAVAILABLE
);
2255 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
2257 if (waitResult
== WAIT_TIMEOUT
) {
2258 // do nothing, just return to caller
2260 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
2261 // a handle was signaled
2262 if (livePort
) *livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
2264 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
2265 // windows message received
2266 if (msgReceived
) *msgReceived
= true;
2268 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
2269 // an "abandoned mutex object"
2270 if (livePort
) *livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
2273 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
2278 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
2286 struct __timeout_context
{
2287 dispatch_source_t ds
;
2292 static void __CFRunLoopTimeoutCancel(void *arg
) {
2293 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2294 CFRelease(context
->rl
);
2295 dispatch_release(context
->ds
);
2299 static void __CFRunLoopTimeout(void *arg
) {
2300 struct __timeout_context
*context
= (struct __timeout_context
*)arg
;
2301 context
->termTSR
= 0ULL;
2302 CFRUNLOOP_WAKEUP_FOR_TIMEOUT();
2303 CFRunLoopWakeUp(context
->rl
);
2304 // The interval is DISPATCH_TIME_FOREVER, so this won't fire again
2307 /* rl, rlm are locked on entrance and exit */
2308 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, CFRunLoopModeRef previousMode
) {
2309 uint64_t startTSR
= mach_absolute_time();
2311 if (__CFRunLoopIsStopped(rl
)) {
2312 __CFRunLoopUnsetStopped(rl
);
2313 return kCFRunLoopRunStopped
;
2314 } else if (rlm
->_stopped
) {
2315 rlm
->_stopped
= false;
2316 return kCFRunLoopRunStopped
;
2319 mach_port_name_t dispatchPort
= MACH_PORT_NULL
;
2320 Boolean libdispatchQSafe
= pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& NULL
== previousMode
) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY
&& 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ
)));
2321 if (libdispatchQSafe
&& (CFRunLoopGetMain() == rl
) && CFSetContainsValue(rl
->_commonModes
, rlm
->_name
)) dispatchPort
= _dispatch_get_main_queue_port_4CF();
2323 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2324 mach_port_name_t modeQueuePort
= MACH_PORT_NULL
;
2326 modeQueuePort
= _dispatch_runloop_root_queue_get_port_4CF(rlm
->_queue
);
2327 if (!modeQueuePort
) {
2328 CRASH("Unable to get port for run loop mode queue (%d)", -1);
2333 dispatch_source_t timeout_timer
= NULL
;
2334 struct __timeout_context
*timeout_context
= (struct __timeout_context
*)malloc(sizeof(*timeout_context
));
2335 if (seconds
<= 0.0) { // instant timeout
2337 timeout_context
->termTSR
= 0ULL;
2338 } else if (seconds
<= TIMER_INTERVAL_LIMIT
) {
2339 dispatch_queue_t queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH
, DISPATCH_QUEUE_OVERCOMMIT
);
2340 timeout_timer
= dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER
, 0, 0, queue
);
2341 dispatch_retain(timeout_timer
);
2342 timeout_context
->ds
= timeout_timer
;
2343 timeout_context
->rl
= (CFRunLoopRef
)CFRetain(rl
);
2344 timeout_context
->termTSR
= startTSR
+ __CFTimeIntervalToTSR(seconds
);
2345 dispatch_set_context(timeout_timer
, timeout_context
); // source gets ownership of context
2346 dispatch_source_set_event_handler_f(timeout_timer
, __CFRunLoopTimeout
);
2347 dispatch_source_set_cancel_handler_f(timeout_timer
, __CFRunLoopTimeoutCancel
);
2348 uint64_t ns_at
= (uint64_t)((__CFTSRToTimeInterval(startTSR
) + seconds
) * 1000000000ULL);
2349 dispatch_source_set_timer(timeout_timer
, dispatch_time(1, ns_at
), DISPATCH_TIME_FOREVER
, 1000ULL);
2350 dispatch_resume(timeout_timer
);
2351 } else { // infinite timeout
2352 seconds
= 9999999999.0;
2353 timeout_context
->termTSR
= UINT64_MAX
;
2356 Boolean didDispatchPortLastTime
= true;
2359 uint8_t msg_buffer
[3 * 1024];
2360 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2361 mach_msg_header_t
*msg
= NULL
;
2362 mach_port_t livePort
= MACH_PORT_NULL
;
2363 #elif DEPLOYMENT_TARGET_WINDOWS
2364 HANDLE livePort
= NULL
;
2365 Boolean windowsMessageReceived
= false;
2367 __CFPortSet waitSet
= rlm
->_portSet
;
2369 __CFRunLoopUnsetIgnoreWakeUps(rl
);
2371 if (rlm
->_observerMask
& kCFRunLoopBeforeTimers
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
2372 if (rlm
->_observerMask
& kCFRunLoopBeforeSources
) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
2374 __CFRunLoopDoBlocks(rl
, rlm
);
2376 Boolean sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
2377 if (sourceHandledThisLoop
) {
2378 __CFRunLoopDoBlocks(rl
, rlm
);
2381 Boolean poll
= sourceHandledThisLoop
|| (0ULL == timeout_context
->termTSR
);
2383 if (MACH_PORT_NULL
!= dispatchPort
&& !didDispatchPortLastTime
) {
2384 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2385 msg
= (mach_msg_header_t
*)msg_buffer
;
2386 if (__CFRunLoopServiceMachPort(dispatchPort
, &msg
, sizeof(msg_buffer
), &livePort
, 0)) {
2389 #elif DEPLOYMENT_TARGET_WINDOWS
2390 if (__CFRunLoopWaitForMultipleObjects(NULL
, &dispatchPort
, 0, 0, &livePort
, NULL
)) {
2396 didDispatchPortLastTime
= false;
2398 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopBeforeWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
2399 __CFRunLoopSetSleeping(rl
);
2400 // do not do any user callouts after this point (after notifying of sleeping)
2402 // Must push the local-to-this-activation ports in on every loop
2403 // iteration, as this mode could be run re-entrantly and we don't
2404 // want these ports to get serviced.
2406 __CFPortSetInsert(dispatchPort
, waitSet
);
2408 __CFRunLoopModeUnlock(rlm
);
2409 __CFRunLoopUnlock(rl
);
2411 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2412 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2414 if (kCFUseCollectableAllocator
) {
2415 objc_clear_stack(0);
2416 memset(msg_buffer
, 0, sizeof(msg_buffer
));
2418 msg
= (mach_msg_header_t
*)msg_buffer
;
2419 __CFRunLoopServiceMachPort(waitSet
, &msg
, sizeof(msg_buffer
), &livePort
, poll
? 0 : TIMEOUT_INFINITY
);
2421 if (modeQueuePort
!= MACH_PORT_NULL
&& livePort
== modeQueuePort
) {
2422 // Drain the internal queue. If one of the callout blocks sets the timerFired flag, break out and service the timer.
2423 while (_dispatch_runloop_root_queue_perform_4CF(rlm
->_queue
));
2424 if (rlm
->_timerFired
) {
2425 // Leave livePort as the queue port, and service timers below
2426 rlm
->_timerFired
= false;
2429 if (msg
&& msg
!= (mach_msg_header_t
*)msg_buffer
) free(msg
);
2432 // Go ahead and leave the inner loop.
2437 if (kCFUseCollectableAllocator
) {
2438 objc_clear_stack(0);
2439 memset(msg_buffer
, 0, sizeof(msg_buffer
));
2441 msg
= (mach_msg_header_t
*)msg_buffer
;
2442 __CFRunLoopServiceMachPort(waitSet
, &msg
, sizeof(msg_buffer
), &livePort
, poll
? 0 : TIMEOUT_INFINITY
);
2446 #elif DEPLOYMENT_TARGET_WINDOWS
2447 // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages.
2448 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, poll
? 0 : TIMEOUT_INFINITY
, rlm
->_msgQMask
, &livePort
, &windowsMessageReceived
);
2451 __CFRunLoopLock(rl
);
2452 __CFRunLoopModeLock(rlm
);
2454 // Must remove the local-to-this-activation ports in on every loop
2455 // iteration, as this mode could be run re-entrantly and we don't
2456 // want these ports to get serviced. Also, we don't want them left
2457 // in there if this function returns.
2459 __CFPortSetRemove(dispatchPort
, waitSet
);
2461 __CFRunLoopSetIgnoreWakeUps(rl
);
2463 // user callouts now OK again
2464 __CFRunLoopUnsetSleeping(rl
);
2465 if (!poll
&& (rlm
->_observerMask
& kCFRunLoopAfterWaiting
)) __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
2468 __CFRunLoopSetIgnoreWakeUps(rl
);
2470 #if DEPLOYMENT_TARGET_WINDOWS
2471 if (windowsMessageReceived
) {
2472 // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after
2473 __CFRunLoopModeUnlock(rlm
);
2474 __CFRunLoopUnlock(rl
);
2476 if (rlm
->_msgPump
) {
2480 if (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
| PM_NOYIELD
)) {
2481 TranslateMessage(&msg
);
2482 DispatchMessage(&msg
);
2486 __CFRunLoopLock(rl
);
2487 __CFRunLoopModeLock(rlm
);
2488 sourceHandledThisLoop
= true;
2490 // To prevent starvation of sources other than the message queue, we check again to see if any other sources need to be serviced
2491 // 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.
2492 // 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.
2493 __CFRunLoopSetSleeping(rl
);
2494 __CFRunLoopModeUnlock(rlm
);
2495 __CFRunLoopUnlock(rl
);
2497 __CFRunLoopWaitForMultipleObjects(waitSet
, NULL
, 0, 0, &livePort
, NULL
);
2499 __CFRunLoopLock(rl
);
2500 __CFRunLoopModeLock(rlm
);
2501 __CFRunLoopUnsetSleeping(rl
);
2502 // If we have a new live port then it will be handled below as normal
2507 if (MACH_PORT_NULL
== livePort
) {
2508 CFRUNLOOP_WAKEUP_FOR_NOTHING();
2510 } else if (livePort
== rl
->_wakeUpPort
) {
2511 CFRUNLOOP_WAKEUP_FOR_WAKEUP();
2512 // do nothing on Mac OS
2513 #if DEPLOYMENT_TARGET_WINDOWS
2514 // Always reset the wake up port, or risk spinning forever
2515 ResetEvent(rl
->_wakeUpPort
);
2518 #if USE_DISPATCH_SOURCE_FOR_TIMERS
2519 else if (modeQueuePort
!= MACH_PORT_NULL
&& livePort
== modeQueuePort
) {
2520 CFRUNLOOP_WAKEUP_FOR_TIMER();
2521 if (!__CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time())) {
2522 // Re-arm the next timer, because we apparently fired early
2523 __CFArmNextTimerInMode(rlm
, rl
);
2527 #if USE_MK_TIMER_TOO
2528 else if (rlm
->_timerPort
!= MACH_PORT_NULL
&& livePort
== rlm
->_timerPort
) {
2529 CFRUNLOOP_WAKEUP_FOR_TIMER();
2530 // 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.
2531 // 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
2532 if (!__CFRunLoopDoTimers(rl
, rlm
, mach_absolute_time())) {
2533 // Re-arm the next timer
2534 __CFArmNextTimerInMode(rlm
, rl
);
2538 else if (livePort
== dispatchPort
) {
2539 CFRUNLOOP_WAKEUP_FOR_DISPATCH();
2540 __CFRunLoopModeUnlock(rlm
);
2541 __CFRunLoopUnlock(rl
);
2542 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)6, NULL
);
2543 #if DEPLOYMENT_TARGET_WINDOWS
2546 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg
);
2547 _CFSetTSD(__CFTSDKeyIsInGCDMainQ
, (void *)0, NULL
);
2548 __CFRunLoopLock(rl
);
2549 __CFRunLoopModeLock(rlm
);
2550 sourceHandledThisLoop
= true;
2551 didDispatchPortLastTime
= true;
2553 CFRUNLOOP_WAKEUP_FOR_SOURCE();
2554 // Despite the name, this works for windows handles as well
2555 CFRunLoopSourceRef rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
);
2557 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2558 mach_msg_header_t
*reply
= NULL
;
2559 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
) || sourceHandledThisLoop
;
2560 if (NULL
!= reply
) {
2561 (void)mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
2562 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
2564 #elif DEPLOYMENT_TARGET_WINDOWS
2565 sourceHandledThisLoop
= __CFRunLoopDoSource1(rl
, rlm
, rls
) || sourceHandledThisLoop
;
2569 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2570 if (msg
&& msg
!= (mach_msg_header_t
*)msg_buffer
) free(msg
);
2573 __CFRunLoopDoBlocks(rl
, rlm
);
2576 if (sourceHandledThisLoop
&& stopAfterHandle
) {
2577 retVal
= kCFRunLoopRunHandledSource
;
2578 } else if (timeout_context
->termTSR
< mach_absolute_time()) {
2579 retVal
= kCFRunLoopRunTimedOut
;
2580 } else if (__CFRunLoopIsStopped(rl
)) {
2581 __CFRunLoopUnsetStopped(rl
);
2582 retVal
= kCFRunLoopRunStopped
;
2583 } else if (rlm
->_stopped
) {
2584 rlm
->_stopped
= false;
2585 retVal
= kCFRunLoopRunStopped
;
2586 } else if (__CFRunLoopModeIsEmpty(rl
, rlm
, previousMode
)) {
2587 retVal
= kCFRunLoopRunFinished
;
2589 } while (0 == retVal
);
2591 if (timeout_timer
) {
2592 dispatch_source_cancel(timeout_timer
);
2593 dispatch_release(timeout_timer
);
2595 free(timeout_context
);
2601 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2603 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
2604 __CFRunLoopLock(rl
);
2605 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
2606 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
, rl
->_currentMode
)) {
2607 Boolean did
= false;
2608 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2609 __CFRunLoopUnlock(rl
);
2610 return did
? kCFRunLoopRunHandledSource
: kCFRunLoopRunFinished
;
2612 volatile _per_run_data
*previousPerRun
= __CFRunLoopPushPerRunData(rl
);
2613 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
2614 rl
->_currentMode
= currentMode
;
2615 int32_t result
= kCFRunLoopRunFinished
;
2617 if (currentMode
->_observerMask
& kCFRunLoopEntry
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
2618 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, previousMode
);
2619 if (currentMode
->_observerMask
& kCFRunLoopExit
) __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
2621 __CFRunLoopModeUnlock(currentMode
);
2622 __CFRunLoopPopPerRunData(rl
, previousPerRun
);
2623 rl
->_currentMode
= previousMode
;
2624 __CFRunLoopUnlock(rl
);
2628 void CFRunLoopRun(void) { /* DOES CALLOUT */
2631 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
2633 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
2636 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
2638 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
2641 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
2643 __CFRunLoopLock(rl
);
2644 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2645 CFAbsoluteTime at
= 0.0;
2646 CFRunLoopTimerRef nextTimer
= (rlm
&& rlm
->_timers
&& 0 < CFArrayGetCount(rlm
->_timers
)) ? (CFRunLoopTimerRef
)CFArrayGetValueAtIndex(rlm
->_timers
, 0) : NULL
;
2648 at
= CFRunLoopTimerGetNextFireDate(nextTimer
);
2650 if (rlm
) __CFRunLoopModeUnlock(rlm
);
2651 __CFRunLoopUnlock(rl
);
2655 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
2657 return __CFRunLoopIsSleeping(rl
);
2660 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
2662 // This lock is crucial to ignorable wakeups, do not remove it.
2663 __CFRunLoopLock(rl
);
2664 if (__CFRunLoopIsIgnoringWakeUps(rl
)) {
2665 __CFRunLoopUnlock(rl
);
2668 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2670 /* We unconditionally try to send the message, since we don't want
2671 * to lose a wakeup, but the send may fail if there is already a
2672 * wakeup pending, since the queue length is 1. */
2673 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
2674 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) CRASH("*** Unable to send message to wake up port. (%d) ***", ret
);
2675 #elif DEPLOYMENT_TARGET_WINDOWS
2676 SetEvent(rl
->_wakeUpPort
);
2678 __CFRunLoopUnlock(rl
);
2681 void CFRunLoopStop(CFRunLoopRef rl
) {
2682 Boolean doWake
= false;
2684 __CFRunLoopLock(rl
);
2685 if (rl
->_currentMode
) {
2686 __CFRunLoopSetStopped(rl
);
2689 __CFRunLoopUnlock(rl
);
2691 CFRunLoopWakeUp(rl
);
2695 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
2697 CFRunLoopModeRef rlm
;
2698 __CFRunLoopLock(rl
);
2699 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2701 rlm
->_stopped
= true;
2702 __CFRunLoopModeUnlock(rlm
);
2704 __CFRunLoopUnlock(rl
);
2705 CFRunLoopWakeUp(rl
);
2708 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2713 void CFRunLoopPerformBlock(CFRunLoopRef rl
, CFTypeRef mode
, void (^block
)(void)) {
2715 if (CFStringGetTypeID() == CFGetTypeID(mode
)) {
2716 mode
= CFStringCreateCopy(kCFAllocatorSystemDefault
, (CFStringRef
)mode
);
2717 __CFRunLoopLock(rl
);
2718 // ensure mode exists
2719 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)mode
, true);
2720 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2721 __CFRunLoopUnlock(rl
);
2722 } else if (CFArrayGetTypeID() == CFGetTypeID(mode
)) {
2723 CFIndex cnt
= CFArrayGetCount((CFArrayRef
)mode
);
2724 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2725 CFArrayGetValues((CFArrayRef
)mode
, CFRangeMake(0, cnt
), values
);
2726 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2727 __CFRunLoopLock(rl
);
2728 // ensure modes exist
2729 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2730 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2731 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2733 __CFRunLoopUnlock(rl
);
2735 } else if (CFSetGetTypeID() == CFGetTypeID(mode
)) {
2736 CFIndex cnt
= CFSetGetCount((CFSetRef
)mode
);
2737 const void **values
= (const void **)malloc(sizeof(const void *) * cnt
);
2738 CFSetGetValues((CFSetRef
)mode
, values
);
2739 mode
= CFSetCreate(kCFAllocatorSystemDefault
, values
, cnt
, &kCFTypeSetCallBacks
);
2740 __CFRunLoopLock(rl
);
2741 // ensure modes exist
2742 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
2743 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, (CFStringRef
)values
[idx
], true);
2744 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
2746 __CFRunLoopUnlock(rl
);
2751 block
= Block_copy(block
);
2752 if (!mode
|| !block
) {
2753 if (mode
) CFRelease(mode
);
2754 if (block
) Block_release(block
);
2757 __CFRunLoopLock(rl
);
2758 struct _block_item
*new_item
= (struct _block_item
*)malloc(sizeof(struct _block_item
));
2759 new_item
->_next
= NULL
;
2760 new_item
->_mode
= mode
;
2761 new_item
->_block
= block
;
2762 if (!rl
->_blocks_tail
) {
2763 rl
->_blocks_head
= new_item
;
2765 rl
->_blocks_tail
->_next
= new_item
;
2767 rl
->_blocks_tail
= new_item
;
2768 __CFRunLoopUnlock(rl
);
2771 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2773 CFRunLoopModeRef rlm
;
2774 Boolean hasValue
= false;
2775 __CFRunLoopLock(rl
);
2776 if (modeName
== kCFRunLoopCommonModes
) {
2777 if (NULL
!= rl
->_commonModeItems
) {
2778 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2781 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2783 hasValue
= (rlm
->_sources0
? CFSetContainsValue(rlm
->_sources0
, rls
) : false) || (rlm
->_sources1
? CFSetContainsValue(rlm
->_sources1
, rls
) : false);
2784 __CFRunLoopModeUnlock(rlm
);
2787 __CFRunLoopUnlock(rl
);
2791 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2793 if (__CFRunLoopIsDeallocating(rl
)) return;
2794 if (!__CFIsValid(rls
)) return;
2795 Boolean doVer0Callout
= false;
2796 __CFRunLoopLock(rl
);
2797 if (modeName
== kCFRunLoopCommonModes
) {
2798 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2799 if (NULL
== rl
->_commonModeItems
) {
2800 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2802 CFSetAddValue(rl
->_commonModeItems
, rls
);
2804 CFTypeRef context
[2] = {rl
, rls
};
2805 /* add new item to all common-modes */
2806 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2810 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2811 if (NULL
!= rlm
&& NULL
== rlm
->_sources0
) {
2812 rlm
->_sources0
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2813 rlm
->_sources1
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2814 rlm
->_portToV1SourceMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
2816 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources0
, rls
) && !CFSetContainsValue(rlm
->_sources1
, rls
)) {
2817 if (0 == rls
->_context
.version0
.version
) {
2818 CFSetAddValue(rlm
->_sources0
, rls
);
2819 } else if (1 == rls
->_context
.version0
.version
) {
2820 CFSetAddValue(rlm
->_sources1
, rls
);
2821 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2822 if (CFPORT_NULL
!= src_port
) {
2823 CFDictionarySetValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
, rls
);
2824 __CFPortSetInsert(src_port
, rlm
->_portSet
);
2827 __CFRunLoopSourceLock(rls
);
2828 if (NULL
== rls
->_runLoops
) {
2829 rls
->_runLoops
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeBagCallBacks
); // sources retain run loops!
2831 CFBagAddValue(rls
->_runLoops
, rl
);
2832 __CFRunLoopSourceUnlock(rls
);
2833 if (0 == rls
->_context
.version0
.version
) {
2834 if (NULL
!= rls
->_context
.version0
.schedule
) {
2835 doVer0Callout
= true;
2840 __CFRunLoopModeUnlock(rlm
);
2843 __CFRunLoopUnlock(rl
);
2844 if (doVer0Callout
) {
2845 // although it looses some protection for the source, we have no choice but
2846 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2847 // where the source wants to take a lock which is already held in another
2848 // thread which is itself waiting for a run loop/mode lock
2849 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2853 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2855 Boolean doVer0Callout
= false, doRLSRelease
= false;
2856 __CFRunLoopLock(rl
);
2857 if (modeName
== kCFRunLoopCommonModes
) {
2858 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2859 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2860 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2862 CFTypeRef context
[2] = {rl
, rls
};
2863 /* remove new item from all common-modes */
2864 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2870 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2871 if (NULL
!= rlm
&& ((NULL
!= rlm
->_sources0
&& CFSetContainsValue(rlm
->_sources0
, rls
)) || (NULL
!= rlm
->_sources1
&& CFSetContainsValue(rlm
->_sources1
, rls
)))) {
2873 if (1 == rls
->_context
.version0
.version
) {
2874 __CFPort src_port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
2875 if (CFPORT_NULL
!= src_port
) {
2876 CFDictionaryRemoveValue(rlm
->_portToV1SourceMap
, (const void *)(uintptr_t)src_port
);
2877 __CFPortSetRemove(src_port
, rlm
->_portSet
);
2880 CFSetRemoveValue(rlm
->_sources0
, rls
);
2881 CFSetRemoveValue(rlm
->_sources1
, rls
);
2882 __CFRunLoopSourceLock(rls
);
2883 if (NULL
!= rls
->_runLoops
) {
2884 CFBagRemoveValue(rls
->_runLoops
, rl
);
2886 __CFRunLoopSourceUnlock(rls
);
2887 if (0 == rls
->_context
.version0
.version
) {
2888 if (NULL
!= rls
->_context
.version0
.cancel
) {
2889 doVer0Callout
= true;
2892 doRLSRelease
= true;
2895 __CFRunLoopModeUnlock(rlm
);
2898 __CFRunLoopUnlock(rl
);
2899 if (doVer0Callout
) {
2900 // although it looses some protection for the source, we have no choice but
2901 // to do this after unlocking the run loop and mode locks, to avoid deadlocks
2902 // where the source wants to take a lock which is already held in another
2903 // thread which is itself waiting for a run loop/mode lock
2904 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, modeName
); /* CALLOUT */
2906 if (doRLSRelease
) CFRelease(rls
);
2909 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value
, void *ctx
) {
2910 CFStringRef modeName
= (CFStringRef
)value
;
2911 CFRunLoopRef rl
= (CFRunLoopRef
)ctx
;
2912 __CFRunLoopRemoveAllSources(rl
, modeName
);
2915 static void __CFRunLoopRemoveSourceFromMode(const void *value
, void *ctx
) {
2916 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
2917 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
2918 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
2919 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2922 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl
, CFStringRef modeName
) {
2924 CFRunLoopModeRef rlm
;
2925 __CFRunLoopLock(rl
);
2926 if (modeName
== kCFRunLoopCommonModes
) {
2927 if (NULL
!= rl
->_commonModeItems
) {
2928 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2930 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourcesFromCommonMode
), (void *)rl
);
2936 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2937 if (NULL
!= rlm
&& NULL
!= rlm
->_sources0
) {
2938 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources0
);
2939 CFTypeRef context
[2] = {rl
, modeName
};
2940 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2943 if (NULL
!= rlm
&& NULL
!= rlm
->_sources1
) {
2944 CFSetRef set
= CFSetCreateCopy(kCFAllocatorSystemDefault
, rlm
->_sources1
);
2945 CFTypeRef context
[2] = {rl
, modeName
};
2946 CFSetApplyFunction(set
, (__CFRunLoopRemoveSourceFromMode
), (void *)context
);
2950 __CFRunLoopModeUnlock(rlm
);
2953 __CFRunLoopUnlock(rl
);
2956 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2958 CFRunLoopModeRef rlm
;
2959 Boolean hasValue
= false;
2960 __CFRunLoopLock(rl
);
2961 if (modeName
== kCFRunLoopCommonModes
) {
2962 if (NULL
!= rl
->_commonModeItems
) {
2963 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2966 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2967 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2968 hasValue
= CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
2971 __CFRunLoopModeUnlock(rlm
);
2974 __CFRunLoopUnlock(rl
);
2978 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2980 CFRunLoopModeRef rlm
;
2981 if (__CFRunLoopIsDeallocating(rl
)) return;
2982 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2983 __CFRunLoopLock(rl
);
2984 if (modeName
== kCFRunLoopCommonModes
) {
2985 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2986 if (NULL
== rl
->_commonModeItems
) {
2987 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
2989 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2991 CFTypeRef context
[2] = {rl
, rlo
};
2992 /* add new item to all common-modes */
2993 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2997 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2998 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2999 rlm
->_observers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
3001 if (NULL
!= rlm
&& !CFArrayContainsValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
)) {
3002 Boolean inserted
= false;
3003 for (CFIndex idx
= CFArrayGetCount(rlm
->_observers
); idx
--; ) {
3004 CFRunLoopObserverRef obs
= (CFRunLoopObserverRef
)CFArrayGetValueAtIndex(rlm
->_observers
, idx
);
3005 if (obs
->_order
<= rlo
->_order
) {
3006 CFArrayInsertValueAtIndex(rlm
->_observers
, idx
+ 1, rlo
);
3012 CFArrayInsertValueAtIndex(rlm
->_observers
, 0, rlo
);
3014 rlm
->_observerMask
|= rlo
->_activities
;
3015 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
3018 __CFRunLoopModeUnlock(rlm
);
3021 __CFRunLoopUnlock(rl
);
3024 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
3026 CFRunLoopModeRef rlm
;
3027 __CFRunLoopLock(rl
);
3028 if (modeName
== kCFRunLoopCommonModes
) {
3029 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
3030 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3031 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
3033 CFTypeRef context
[2] = {rl
, rlo
};
3034 /* remove new item from all common-modes */
3035 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3041 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3042 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
3044 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_observers
, CFRangeMake(0, CFArrayGetCount(rlm
->_observers
)), rlo
);
3045 if (kCFNotFound
!= idx
) {
3046 CFArrayRemoveValueAtIndex(rlm
->_observers
, idx
);
3047 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
3052 __CFRunLoopModeUnlock(rlm
);
3055 __CFRunLoopUnlock(rl
);
3058 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3060 if (NULL
== rlt
->_runLoop
|| rl
!= rlt
->_runLoop
) return false;
3061 Boolean hasValue
= false;
3062 __CFRunLoopLock(rl
);
3063 if (modeName
== kCFRunLoopCommonModes
) {
3064 if (NULL
!= rl
->_commonModeItems
) {
3065 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
3068 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3070 if (NULL
!= rlm
->_timers
) {
3071 CFIndex idx
= CFArrayGetFirstIndexOfValue(rlm
->_timers
, CFRangeMake(0, CFArrayGetCount(rlm
->_timers
)), rlt
);
3072 hasValue
= (kCFNotFound
!= idx
);
3074 __CFRunLoopModeUnlock(rlm
);
3077 __CFRunLoopUnlock(rl
);
3081 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3083 if (__CFRunLoopIsDeallocating(rl
)) return;
3084 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
3085 __CFRunLoopLock(rl
);
3086 if (modeName
== kCFRunLoopCommonModes
) {
3087 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3088 if (NULL
== rl
->_commonModeItems
) {
3089 rl
->_commonModeItems
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3091 CFSetAddValue(rl
->_commonModeItems
, rlt
);
3093 CFTypeRef context
[2] = {rl
, rlt
};
3094 /* add new item to all common-modes */
3095 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
3099 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
3101 if (NULL
== rlm
->_timers
) {
3102 CFArrayCallBacks cb
= kCFTypeArrayCallBacks
;
3104 rlm
->_timers
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &cb
);
3107 if (NULL
!= rlm
&& !CFSetContainsValue(rlt
->_rlModes
, rlm
->_name
)) {
3108 __CFRunLoopTimerLock(rlt
);
3109 if (NULL
== rlt
->_runLoop
) {
3111 } else if (rl
!= rlt
->_runLoop
) {
3112 __CFRunLoopTimerUnlock(rlt
);
3113 __CFRunLoopModeUnlock(rlm
);
3114 __CFRunLoopUnlock(rl
);
3117 CFSetAddValue(rlt
->_rlModes
, rlm
->_name
);
3118 __CFRunLoopTimerUnlock(rlt
);
3119 __CFRunLoopTimerFireTSRLock();
3120 __CFRepositionTimerInMode(rlm
, rlt
, false);
3121 __CFRunLoopTimerFireTSRUnlock();
3122 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion
)) {
3123 // Normally we don't do this on behalf of clients, but for
3124 // backwards compatibility due to the change in timer handling...
3125 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
3129 __CFRunLoopModeUnlock(rlm
);
3132 __CFRunLoopUnlock(rl
);
3135 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
3137 __CFRunLoopLock(rl
);
3138 if (modeName
== kCFRunLoopCommonModes
) {
3139 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
3140 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
3141 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
3143 CFTypeRef context
[2] = {rl
, rlt
};
3144 /* remove new item from all common-modes */
3145 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
3151 CFRunLoopModeRef rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
3152 CFIndex idx
= kCFNotFound
;
3153 CFMutableArrayRef timerList
= NULL
;
3155 timerList
= rlm
->_timers
;
3156 if (NULL
!= timerList
) {
3157 idx
= CFArrayGetFirstIndexOfValue(timerList
, CFRangeMake(0, CFArrayGetCount(timerList
)), rlt
);
3160 if (kCFNotFound
!= idx
) {
3161 __CFRunLoopTimerLock(rlt
);
3162 CFSetRemoveValue(rlt
->_rlModes
, rlm
->_name
);
3163 if (0 == CFSetGetCount(rlt
->_rlModes
)) {
3164 rlt
->_runLoop
= NULL
;
3166 __CFRunLoopTimerUnlock(rlt
);
3167 CFArrayRemoveValueAtIndex(timerList
, idx
);
3168 __CFArmNextTimerInMode(rlm
, rl
);
3171 __CFRunLoopModeUnlock(rlm
);
3174 __CFRunLoopUnlock(rl
);
3177 /* CFRunLoopSource */
3179 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
3180 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
3181 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
3182 if (rls1
== rls2
) return true;
3183 if (__CFIsValid(rls1
) != __CFIsValid(rls2
)) return false;
3184 if (rls1
->_order
!= rls2
->_order
) return false;
3185 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
3186 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
3187 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
3188 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
3189 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
3190 if (rls1
->_context
.version0
.equal
)
3191 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
3192 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
3195 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
3196 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3197 if (rls
->_context
.version0
.hash
)
3198 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
3199 return (CFHashCode
)rls
->_context
.version0
.info
;
3202 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3203 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3205 CFStringRef contextDesc
= NULL
;
3206 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
3207 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
3209 if (NULL
== contextDesc
) {
3210 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
3211 #if DEPLOYMENT_TARGET_WINDOWS
3212 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, addr
);
3213 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3215 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3216 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
3219 #if DEPLOYMENT_TARGET_WINDOWS
3220 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
);
3222 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
);
3224 CFRelease(contextDesc
);
3228 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3229 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
3230 CFRunLoopSourceInvalidate(rls
);
3231 if (rls
->_context
.version0
.release
) {
3232 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
3234 pthread_mutex_destroy(&rls
->_lock
);
3235 memset((char *)cf
+ sizeof(CFRuntimeBase
), 0, sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
));
3238 static const CFRuntimeClass __CFRunLoopSourceClass
= {
3239 _kCFRuntimeScannedObject
,
3243 __CFRunLoopSourceDeallocate
,
3244 __CFRunLoopSourceEqual
,
3245 __CFRunLoopSourceHash
,
3247 __CFRunLoopSourceCopyDescription
3250 CF_PRIVATE
void __CFRunLoopSourceInitialize(void) {
3251 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
3254 CFTypeID
CFRunLoopSourceGetTypeID(void) {
3255 return __kCFRunLoopSourceTypeID
;
3258 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
3260 CFRunLoopSourceRef memory
;
3262 if (NULL
== context
) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
3264 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
3265 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
3266 if (NULL
== memory
) {
3269 __CFSetValid(memory
);
3270 __CFRunLoopSourceUnsetSignaled(memory
);
3271 __CFRunLoopLockInit(&memory
->_lock
);
3273 memory
->_order
= order
;
3274 memory
->_runLoops
= NULL
;
3276 switch (context
->version
) {
3278 size
= sizeof(CFRunLoopSourceContext
);
3281 size
= sizeof(CFRunLoopSourceContext1
);
3284 objc_memmove_collectable(&memory
->_context
, context
, size
);
3285 if (context
->retain
) {
3286 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
3291 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
3293 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3297 static void __CFRunLoopSourceWakeUpLoop(const void *value
, void *context
) {
3298 CFRunLoopWakeUp((CFRunLoopRef
)value
);
3301 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
3302 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
3303 CFTypeRef
*params
= (CFTypeRef
*)context
;
3304 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
3306 if (rl
== params
[1]) return;
3308 // CFRunLoopRemoveSource will lock the run loop while it
3309 // needs that, but we also lock it out here to keep
3310 // changes from occurring for this whole sequence.
3311 __CFRunLoopLock(rl
);
3312 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3313 for (idx
= CFArrayGetCount(array
); idx
--;) {
3314 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3315 CFRunLoopRemoveSource(rl
, rls
, modeName
);
3317 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
3318 __CFRunLoopUnlock(rl
);
3323 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
3325 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3326 __CFRunLoopSourceLock(rls
);
3328 if (__CFIsValid(rls
)) {
3329 CFBagRef rloops
= rls
->_runLoops
;
3330 __CFUnsetValid(rls
);
3331 __CFRunLoopSourceUnsetSignaled(rls
);
3332 if (NULL
!= rloops
) {
3333 // To avoid A->B, B->A lock ordering issues when coming up
3334 // towards the run loop from a source, the source has to be
3335 // unlocked, which means we have to protect from object
3337 rls
->_runLoops
= NULL
; // transfer ownership to local stack
3338 __CFRunLoopSourceUnlock(rls
);
3339 CFTypeRef params
[2] = {rls
, NULL
};
3340 CFBagApplyFunction(rloops
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
3342 __CFRunLoopSourceLock(rls
);
3344 /* for hashing- and equality-use purposes, can't actually release the context here */
3346 __CFRunLoopSourceUnlock(rls
);
3350 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
3352 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3353 return __CFIsValid(rls
);
3356 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
3358 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
3359 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
3361 switch (context
->version
) {
3363 size
= sizeof(CFRunLoopSourceContext
);
3366 size
= sizeof(CFRunLoopSourceContext1
);
3369 memmove(context
, &rls
->_context
, size
);
3372 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
3374 __CFRunLoopSourceLock(rls
);
3375 if (__CFIsValid(rls
)) {
3376 __CFRunLoopSourceSetSignaled(rls
);
3378 __CFRunLoopSourceUnlock(rls
);
3381 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
3383 __CFRunLoopSourceLock(rls
);
3384 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
3385 __CFRunLoopSourceUnlock(rls
);
3389 CF_PRIVATE
void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls
) {
3390 CFBagRef loops
= NULL
;
3391 __CFRunLoopSourceLock(rls
);
3392 if (__CFIsValid(rls
) && NULL
!= rls
->_runLoops
) {
3393 loops
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
3395 __CFRunLoopSourceUnlock(rls
);
3397 CFBagApplyFunction(loops
, __CFRunLoopSourceWakeUpLoop
, NULL
);
3402 /* CFRunLoopObserver */
3404 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3405 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3407 CFStringRef contextDesc
= NULL
;
3408 if (NULL
!= rlo
->_context
.copyDescription
) {
3409 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
3412 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
3414 #if DEPLOYMENT_TARGET_WINDOWS
3415 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
);
3416 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3417 void *addr
= rlo
->_callout
;
3419 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
3420 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
);
3422 CFRelease(contextDesc
);
3426 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3427 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
3428 CFRunLoopObserverInvalidate(rlo
);
3429 pthread_mutex_destroy(&rlo
->_lock
);
3432 static const CFRuntimeClass __CFRunLoopObserverClass
= {
3434 "CFRunLoopObserver",
3437 __CFRunLoopObserverDeallocate
,
3441 __CFRunLoopObserverCopyDescription
3444 CF_PRIVATE
void __CFRunLoopObserverInitialize(void) {
3445 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
3448 CFTypeID
CFRunLoopObserverGetTypeID(void) {
3449 return __kCFRunLoopObserverTypeID
;
3452 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
3454 CFRunLoopObserverRef memory
;
3456 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
3457 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
3458 if (NULL
== memory
) {
3461 __CFSetValid(memory
);
3462 __CFRunLoopObserverUnsetFiring(memory
);
3464 __CFRunLoopObserverSetRepeats(memory
);
3466 __CFRunLoopObserverUnsetRepeats(memory
);
3468 __CFRunLoopLockInit(&memory
->_lock
);
3469 memory
->_runLoop
= NULL
;
3470 memory
->_rlCount
= 0;
3471 memory
->_activities
= activities
;
3472 memory
->_order
= order
;
3473 memory
->_callout
= callout
;
3475 if (context
->retain
) {
3476 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3478 memory
->_context
.info
= context
->info
;
3480 memory
->_context
.retain
= context
->retain
;
3481 memory
->_context
.release
= context
->release
;
3482 memory
->_context
.copyDescription
= context
->copyDescription
;
3484 memory
->_context
.info
= 0;
3485 memory
->_context
.retain
= 0;
3486 memory
->_context
.release
= 0;
3487 memory
->_context
.copyDescription
= 0;
3492 static void _runLoopObserverWithBlockContext(CFRunLoopObserverRef observer
, CFRunLoopActivity activity
, void *opaqueBlock
) {
3493 typedef void (^observer_block_t
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
);
3494 observer_block_t block
= (observer_block_t
)opaqueBlock
;
3495 block(observer
, activity
);
3498 CFRunLoopObserverRef
CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
,
3499 void (^block
) (CFRunLoopObserverRef observer
, CFRunLoopActivity activity
)) {
3500 CFRunLoopObserverContext blockContext
;
3501 blockContext
.version
= 0;
3502 blockContext
.info
= (void *)block
;
3503 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3504 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3505 blockContext
.copyDescription
= NULL
;
3506 return CFRunLoopObserverCreate(allocator
, activities
, repeats
, order
, _runLoopObserverWithBlockContext
, &blockContext
);
3509 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
3511 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3512 return rlo
->_activities
;
3515 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
3517 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3521 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
3523 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3524 return __CFRunLoopObserverRepeats(rlo
);
3527 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
3529 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3530 __CFRunLoopObserverLock(rlo
);
3532 if (__CFIsValid(rlo
)) {
3533 CFRunLoopRef rl
= rlo
->_runLoop
;
3534 void *info
= rlo
->_context
.info
;
3535 rlo
->_context
.info
= NULL
;
3536 __CFUnsetValid(rlo
);
3538 // To avoid A->B, B->A lock ordering issues when coming up
3539 // towards the run loop from an observer, it has to be
3540 // unlocked, which means we have to protect from object
3543 __CFRunLoopObserverUnlock(rlo
);
3544 // CFRunLoopRemoveObserver will lock the run loop while it
3545 // needs that, but we also lock it out here to keep
3546 // changes from occurring for this whole sequence.
3547 __CFRunLoopLock(rl
);
3548 CFArrayRef array
= CFRunLoopCopyAllModes(rl
);
3549 for (CFIndex idx
= CFArrayGetCount(array
); idx
--;) {
3550 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(array
, idx
);
3551 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
3553 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
3554 __CFRunLoopUnlock(rl
);
3557 __CFRunLoopObserverLock(rlo
);
3559 if (NULL
!= rlo
->_context
.release
) {
3560 rlo
->_context
.release(info
); /* CALLOUT */
3563 __CFRunLoopObserverUnlock(rlo
);
3567 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
3569 return __CFIsValid(rlo
);
3572 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
3574 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
3575 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3576 *context
= rlo
->_context
;
3580 #pragma mark CFRunLoopTimer
3582 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
3583 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3584 CFStringRef contextDesc
= NULL
;
3585 if (NULL
!= rlt
->_context
.copyDescription
) {
3586 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
3588 if (NULL
== contextDesc
) {
3589 contextDesc
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
3591 void *addr
= (void *)rlt
->_callout
;
3592 char libraryName
[2048];
3593 char functionName
[2048];
3594 void *functionPtr
= NULL
;
3595 libraryName
[0] = '?'; libraryName
[1] = '\0';
3596 functionName
[0] = '?'; functionName
[1] = '\0';
3597 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
,
3598 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 = %@}"),
3600 CFGetAllocator(rlt
),
3601 __CFIsValid(rlt
) ? "Yes" : "No",
3602 __CFRunLoopTimerIsFiring(rlt
) ? "Yes" : "No",
3606 rlt
->_nextFireDate
- CFAbsoluteTimeGetCurrent(),
3613 CFRelease(contextDesc
);
3617 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
3618 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3619 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
3620 __CFRunLoopTimerSetDeallocating(rlt
);
3621 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
3622 CFRelease(rlt
->_rlModes
);
3623 rlt
->_rlModes
= NULL
;
3624 pthread_mutex_destroy(&rlt
->_lock
);
3627 static const CFRuntimeClass __CFRunLoopTimerClass
= {
3632 __CFRunLoopTimerDeallocate
,
3636 __CFRunLoopTimerCopyDescription
3639 CF_PRIVATE
void __CFRunLoopTimerInitialize(void) {
3640 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
3643 CFTypeID
CFRunLoopTimerGetTypeID(void) {
3644 return __kCFRunLoopTimerTypeID
;
3647 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
3649 CFRunLoopTimerRef memory
;
3651 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
3652 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
3653 if (NULL
== memory
) {
3656 __CFSetValid(memory
);
3657 __CFRunLoopTimerUnsetFiring(memory
);
3658 __CFRunLoopLockInit(&memory
->_lock
);
3659 memory
->_runLoop
= NULL
;
3660 memory
->_rlModes
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
3661 memory
->_order
= order
;
3662 if (interval
< 0.0) interval
= 0.0;
3663 memory
->_interval
= interval
;
3664 memory
->_tolerance
= 0.0;
3665 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3666 memory
->_nextFireDate
= fireDate
;
3667 memory
->_fireTSR
= 0ULL;
3668 uint64_t now2
= mach_absolute_time();
3669 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3670 if (fireDate
< now1
) {
3671 memory
->_fireTSR
= now2
;
3672 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3673 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3675 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3677 memory
->_callout
= callout
;
3678 if (NULL
!= context
) {
3679 if (context
->retain
) {
3680 memory
->_context
.info
= (void *)context
->retain(context
->info
);
3682 memory
->_context
.info
= context
->info
;
3684 memory
->_context
.retain
= context
->retain
;
3685 memory
->_context
.release
= context
->release
;
3686 memory
->_context
.copyDescription
= context
->copyDescription
;
3688 memory
->_context
.info
= 0;
3689 memory
->_context
.retain
= 0;
3690 memory
->_context
.release
= 0;
3691 memory
->_context
.copyDescription
= 0;
3696 static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer
, void *opaqueBlock
) {
3697 typedef void (^timer_block_t
) (CFRunLoopTimerRef timer
);
3698 timer_block_t block
= (timer_block_t
)opaqueBlock
;
3702 CFRunLoopTimerRef
CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
,
3703 void (^block
) (CFRunLoopTimerRef timer
)) {
3705 CFRunLoopTimerContext blockContext
;
3706 blockContext
.version
= 0;
3707 blockContext
.info
= (void *)block
;
3708 blockContext
.retain
= (const void *(*)(const void *info
))_Block_copy
;
3709 blockContext
.release
= (void (*)(const void *info
))_Block_release
;
3710 blockContext
.copyDescription
= NULL
;
3711 return CFRunLoopTimerCreate(allocator
, fireDate
, interval
, flags
, order
, _runLoopTimerWithBlockContext
, &blockContext
);
3714 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
3716 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, (NSTimer
*)rlt
, _cffireTime
);
3717 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3718 CFAbsoluteTime at
= 0.0;
3719 __CFRunLoopTimerLock(rlt
);
3720 __CFRunLoopTimerFireTSRLock();
3721 if (__CFIsValid(rlt
)) {
3722 at
= rlt
->_nextFireDate
;
3724 __CFRunLoopTimerFireTSRUnlock();
3725 __CFRunLoopTimerUnlock(rlt
);
3729 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
3731 if (!__CFIsValid(rlt
)) return;
3732 if (TIMER_DATE_LIMIT
< fireDate
) fireDate
= TIMER_DATE_LIMIT
;
3733 uint64_t nextFireTSR
= 0ULL;
3734 uint64_t now2
= mach_absolute_time();
3735 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
3736 if (fireDate
< now1
) {
3738 } else if (TIMER_INTERVAL_LIMIT
< fireDate
- now1
) {
3739 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT
);
3741 nextFireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
3743 __CFRunLoopTimerLock(rlt
);
3744 if (NULL
!= rlt
->_runLoop
) {
3745 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3746 STACK_BUFFER_DECL(CFTypeRef
, modes
, cnt
);
3747 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3748 // To avoid A->B, B->A lock ordering issues when coming up
3749 // towards the run loop from a source, the timer has to be
3750 // unlocked, which means we have to protect from object
3751 // invalidation, although that's somewhat expensive.
3752 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3753 CFRetain(modes
[idx
]);
3755 CFRunLoopRef rl
= (CFRunLoopRef
)CFRetain(rlt
->_runLoop
);
3756 __CFRunLoopTimerUnlock(rlt
);
3757 __CFRunLoopLock(rl
);
3758 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3759 CFStringRef name
= (CFStringRef
)modes
[idx
];
3760 modes
[idx
] = __CFRunLoopFindMode(rl
, name
, false);
3763 __CFRunLoopTimerFireTSRLock();
3764 rlt
->_fireTSR
= nextFireTSR
;
3765 rlt
->_nextFireDate
= fireDate
;
3766 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3767 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)modes
[idx
];
3769 __CFRepositionTimerInMode(rlm
, rlt
, true);
3772 __CFRunLoopTimerFireTSRUnlock();
3773 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3774 __CFRunLoopModeUnlock((CFRunLoopModeRef
)modes
[idx
]);
3776 __CFRunLoopUnlock(rl
);
3777 // This is setting the date of a timer, not a direct
3778 // interaction with a run loop, so we'll do a wakeup
3779 // (which may be costly) for the caller, just in case.
3780 // (And useful for binary compatibility with older
3781 // code used to the older timer implementation.)
3782 if (rl
!= CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl
);
3785 __CFRunLoopTimerFireTSRLock();
3786 rlt
->_fireTSR
= nextFireTSR
;
3787 rlt
->_nextFireDate
= fireDate
;
3788 __CFRunLoopTimerFireTSRUnlock();
3789 __CFRunLoopTimerUnlock(rlt
);
3793 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
3795 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, CFTimeInterval
, (NSTimer
*)rlt
, timeInterval
);
3796 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3797 return rlt
->_interval
;
3800 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
3802 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3803 return (0.0 < rlt
->_interval
);
3806 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
3808 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3812 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
3814 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, void, (NSTimer
*)rlt
, invalidate
);
3815 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3816 __CFRunLoopTimerLock(rlt
);
3817 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3820 if (__CFIsValid(rlt
)) {
3821 CFRunLoopRef rl
= rlt
->_runLoop
;
3822 void *info
= rlt
->_context
.info
;
3823 rlt
->_context
.info
= NULL
;
3824 __CFUnsetValid(rlt
);
3826 CFIndex cnt
= CFSetGetCount(rlt
->_rlModes
);
3827 STACK_BUFFER_DECL(CFStringRef
, modes
, cnt
);
3828 CFSetGetValues(rlt
->_rlModes
, (const void **)modes
);
3829 // To avoid A->B, B->A lock ordering issues when coming up
3830 // towards the run loop from a source, the timer has to be
3831 // unlocked, which means we have to protect from object
3832 // invalidation, although that's somewhat expensive.
3833 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3834 CFRetain(modes
[idx
]);
3837 __CFRunLoopTimerUnlock(rlt
);
3838 // CFRunLoopRemoveTimer will lock the run loop while it
3839 // needs that, but we also lock it out here to keep
3840 // changes from occurring for this whole sequence.
3841 __CFRunLoopLock(rl
);
3842 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3843 CFRunLoopRemoveTimer(rl
, rlt
, modes
[idx
]);
3845 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
3846 __CFRunLoopUnlock(rl
);
3847 for (CFIndex idx
= 0; idx
< cnt
; idx
++) {
3848 CFRelease(modes
[idx
]);
3851 __CFRunLoopTimerLock(rlt
);
3853 if (NULL
!= rlt
->_context
.release
) {
3854 rlt
->_context
.release(info
); /* CALLOUT */
3857 __CFRunLoopTimerUnlock(rlt
);
3858 if (!__CFRunLoopTimerIsDeallocating(rlt
)) {
3863 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
3865 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, Boolean
, (NSTimer
*)rlt
, isValid
);
3866 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3867 return __CFIsValid(rlt
);
3870 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
3872 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3873 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
3874 *context
= rlt
->_context
;
3877 CFTimeInterval
CFRunLoopTimerGetTolerance(CFRunLoopTimerRef rlt
) {
3878 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3880 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, CFTimeInterval
, (NSTimer
*)rlt
, tolerance
);
3881 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3882 return rlt
->_tolerance
;
3888 void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef rlt
, CFTimeInterval tolerance
) {
3889 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3891 CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID
, void, (NSTimer
*)rlt
, setTolerance
:tolerance
);
3892 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
3896 * For the initial timer fire at 'start', the upper limit to the allowable
3897 * delay is set to 'leeway' nanoseconds. For the subsequent timer fires at
3898 * 'start' + N * 'interval', the upper limit is MIN('leeway','interval'/2).
3900 if (rlt
->_interval
> 0) {
3901 rlt
->_tolerance
= MIN(tolerance
, rlt
->_interval
/ 2);
3903 // Tolerance must be a positive value or zero
3904 if (tolerance
< 0) tolerance
= 0.0;
3905 rlt
->_tolerance
= tolerance
;