1/*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*	CFRunLoop.c
25	Copyright (c) 1998-2013, Apple Inc. All rights reserved.
26	Responsibility: Tony Parker
27*/
28
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"
35#include <math.h>
36#include <stdio.h>
37#include <limits.h>
38#include <pthread.h>
39#include <dispatch/dispatch.h>
40
41
42#if DEPLOYMENT_TARGET_WINDOWS
43#include <typeinfo.h>
44#endif
45#include <checkint.h>
46
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>
54#include <unistd.h>
55#include <dlfcn.h>
56#include <pthread/private.h>
57extern mach_port_t _dispatch_get_main_queue_port_4CF(void);
58extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg);
59#elif DEPLOYMENT_TARGET_WINDOWS
60#include <process.h>
61DISPATCH_EXPORT HANDLE _dispatch_get_main_queue_handle_4CF(void);
62DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void);
63
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()
69
70#define AbsoluteTime LARGE_INTEGER
71
72#endif
73
74#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
75CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
76#define pthread_main_thread_np() _CF_pthread_main_thread_np()
77#endif
78
79#include <Block.h>
80#include <Block_private.h>
81
82#if DEPLOYMENT_TARGET_MACOSX
83#define USE_DISPATCH_SOURCE_FOR_TIMERS 1
84#define USE_MK_TIMER_TOO 1
85#else
86#define USE_DISPATCH_SOURCE_FOR_TIMERS 0
87#define USE_MK_TIMER_TOO 1
88#endif
89
90
91static int _LogCFRunLoop = 0;
92static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer, void *opaqueBlock);
93
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
97
98#define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
99
100#define CRASH(string, errcode) do { char msg[256]; snprintf(msg, 256, string, errcode); CRSetCrashLogMessage(msg); HALT; } while (0)
101
102#if DEPLOYMENT_TARGET_WINDOWS
103
104static pthread_t kNilPthreadT = { nil, nil };
105#define pthreadPointer(a) a.p
106typedef	int kern_return_t;
107#define KERN_SUCCESS 0
108
109#else
110
111static pthread_t kNilPthreadT = (pthread_t)0;
112#define pthreadPointer(a) a
113#define lockCount(a) a
114#endif
115
116#pragma mark -
117
118#define CF_RUN_LOOP_PROBES 0
119
120#if CF_RUN_LOOP_PROBES
121#include "CFRunLoopProbes.h"
122#else
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)
151#endif
152
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
156
157CF_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;
163
164    kern_return_t ret = mach_port_space_info(mach_task_self(), &info, &table, &tableCount, &tree, &treeCount);
165    if (ret != KERN_SUCCESS) {
166        return (uint32_t)0;
167    }
168    if (table != NULL) {
169        ret = vm_deallocate(mach_task_self(), (vm_address_t)table, tableCount * sizeof(*table));
170    }
171    if (tree != NULL) {
172        ret = vm_deallocate(mach_task_self(), (vm_address_t)tree, treeCount * sizeof(*tree));
173    }
174    return (uint32_t)tableCount;
175}
176
177CF_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;
183
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);
194            } else {
195                mach_port_deallocate(my_task, thread);
196            }
197        }
198        vm_deallocate(my_task, (vm_address_t)thr_list, sizeof(thread_t) * thr_cnt);
199    }
200    mach_port_deallocate(my_task, my_thread);
201    return suspended_list;
202}
203
204CF_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);
210    }
211}
212
213static uint32_t __CF_last_warned_port_count = 0;
214
215static void foo() __attribute__((unused));
216static void foo() {
217    uint32_t pcnt = __CFGetProcessPortCount();
218    if (__CF_last_warned_port_count + 1000 < pcnt) {
219        CFArrayRef threads = __CFStopAllThreads();
220
221
222// do stuff here
223CFOptionFlags responseFlags = 0;
224SInt32 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);
225if (0 != result) {
226    CFLog(3, CFSTR("ERROR"));
227} else {
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;
233    }
234}
235
236
237        __CFRestartAllThreads(threads);
238        CFRelease(threads);
239        __CF_last_warned_port_count = pcnt;
240    }
241}
242
243
244typedef mach_port_t __CFPort;
245#define CFPORT_NULL MACH_PORT_NULL
246typedef mach_port_t __CFPortSet;
247
248static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
249static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) { HALT; };
250
251static __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) {
255        char msg[256];
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);
259        return CFPORT_NULL;
260    }
261
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);
264
265
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);
270
271    return result;
272}
273
274CF_INLINE void __CFPortFree(__CFPort port) {
275    mach_port_destroy(mach_task_self(), port);
276}
277
278static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
279static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) { HALT; };
280
281CF_INLINE __CFPortSet __CFPortSetAllocate(void) {
282    __CFPortSet result;
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;
286}
287
288CF_INLINE kern_return_t __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
289    if (MACH_PORT_NULL == port) {
290        return -1;
291    }
292    return mach_port_insert_member(mach_task_self(), port, portSet);
293}
294
295CF_INLINE kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
296    if (MACH_PORT_NULL == port) {
297        return -1;
298    }
299    return mach_port_extract_member(mach_task_self(), port, portSet);
300}
301
302CF_INLINE void __CFPortSetFree(__CFPortSet portSet) {
303    kern_return_t ret;
304    mach_port_name_array_t array;
305    mach_msg_type_number_t idx, number;
306
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);
311        }
312        vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t));
313    }
314    mach_port_destroy(mach_task_self(), portSet);
315}
316
317#elif DEPLOYMENT_TARGET_WINDOWS
318
319typedef HANDLE __CFPort;
320#define CFPORT_NULL NULL
321
322// A simple dynamic array of HANDLEs, which grows to a high-water mark
323typedef struct ___CFPortSet {
324    uint16_t	used;
325    uint16_t	size;
326    HANDLE	*handles;
327    CFSpinLock_t lock;		// insert and remove must be thread safe, like the Mach calls
328} *__CFPortSet;
329
330CF_INLINE __CFPort __CFPortAllocate(void) {
331    return CreateEventA(NULL, true, false, NULL);
332}
333
334CF_INLINE void __CFPortFree(__CFPort port) {
335    CloseHandle(port);
336}
337
338static __CFPortSet __CFPortSetAllocate(void) {
339    __CFPortSet result = (__CFPortSet)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0);
340    result->used = 0;
341    result->size = 4;
342    result->handles = (HANDLE *)CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0);
343    CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock);
344    return result;
345}
346
347static void __CFPortSetFree(__CFPortSet portSet) {
348    CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles);
349    CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet);
350}
351
352// Returns portBuf if ports fit in that space, else returns another ptr that must be freed
353static __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;
364    }
365    memmove(result, portSet->handles, portSet->used * sizeof(HANDLE));
366    *portsUsed = portSet->used;
367    __CFSpinUnlock(&(portSet->lock));
368    return result;
369}
370
371static kern_return_t __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
372    if (NULL == port) {
373        return -1;
374    }
375    __CFSpinLock(&(portSet->lock));
376    if (portSet->used >= portSet->size) {
377        portSet->size += 4;
378        portSet->handles = (HANDLE *)CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0);
379    }
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);
382    }
383    portSet->handles[portSet->used++] = port;
384    __CFSpinUnlock(&(portSet->lock));
385    return KERN_SUCCESS;
386}
387
388static kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
389    int i, j;
390    if (NULL == port) {
391        return -1;
392    }
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];
398            }
399            portSet->used--;
400            __CFSpinUnlock(&(portSet->lock));
401            return true;
402        }
403    }
404    __CFSpinUnlock(&(portSet->lock));
405    return KERN_SUCCESS;
406}
407
408#endif
409
410#if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H)
411#if defined(__BIG_ENDIAN__)
412typedef	struct UnsignedWide {
413    UInt32		hi;
414    UInt32		lo;
415} UnsignedWide;
416#elif defined(__LITTLE_ENDIAN__)
417typedef	struct UnsignedWide {
418    UInt32		lo;
419    UInt32		hi;
420} UnsignedWide;
421#endif
422typedef UnsignedWide		AbsoluteTime;
423#endif
424
425#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
426
427#if USE_DISPATCH_SOURCE_FOR_TIMERS
428#endif
429#if USE_MK_TIMER_TOO
430extern mach_port_name_t mk_timer_create(void);
431extern kern_return_t mk_timer_destroy(mach_port_name_t name);
432extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time);
433extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time);
434
435CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(uint64_t x) {
436    AbsoluteTime a;
437    a.hi = x >> 32;
438    a.lo = x & (uint64_t)0xFFFFFFFF;
439    return a;
440}
441#endif
442
443static 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);
453    return result;
454}
455#elif DEPLOYMENT_TARGET_WINDOWS
456
457static HANDLE mk_timer_create(void) {
458    return CreateWaitableTimer(NULL, FALSE, NULL);
459}
460
461static kern_return_t mk_timer_destroy(HANDLE name) {
462    BOOL res = CloseHandle(name);
463    if (!res) {
464        DWORD err = GetLastError();
465        CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to destroy timer: %d"), err);
466    }
467    return (int)res;
468}
469
470static kern_return_t mk_timer_arm(HANDLE name, LARGE_INTEGER expire_time) {
471    BOOL res = SetWaitableTimer(name, &expire_time, 0, NULL, NULL, FALSE);
472    if (!res) {
473        DWORD err = GetLastError();
474        CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to set timer: %d"), err);
475    }
476    return (int)res;
477}
478
479static kern_return_t mk_timer_cancel(HANDLE name, LARGE_INTEGER *result_time) {
480    BOOL res = CancelWaitableTimer(name);
481    if (!res) {
482        DWORD err = GetLastError();
483        CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to cancel timer: %d"), err);
484    }
485    return (int)res;
486}
487
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.
489CF_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) {
494        result.QuadPart = 0;
495    } else {
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);
501    }
502    return result;
503}
504
505#endif
506
507#pragma mark -
508#pragma mark Modes
509
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 */
514
515static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID;
516static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID;
517static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID;
518static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID;
519static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID;
520
521typedef struct __CFRunLoopMode *CFRunLoopModeRef;
522
523struct __CFRunLoopMode {
524    CFRuntimeBase _base;
525    pthread_mutex_t _lock;	/* must have the run loop locked before locking this */
526    CFStringRef _name;
527    Boolean _stopped;
528    char _padding[3];
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;
541#endif
542#if USE_MK_TIMER_TOO
543    mach_port_t _timerPort;
544    Boolean _mkTimerArmed;
545#endif
546#if DEPLOYMENT_TARGET_WINDOWS
547    DWORD _msgQMask;
548    void (*_msgPump)(void);
549#endif
550    uint64_t _timerSoftDeadline; /* TSR */
551    uint64_t _timerHardDeadline; /* TSR */
552};
553
554CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
555    pthread_mutex_lock(&(rlm->_lock));
556    //CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm);
557}
558
559CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
560    //CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm);
561    pthread_mutex_unlock(&(rlm->_lock));
562}
563
564static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
565    CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
566    CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
567    return CFEqual(rlm1->_name, rlm2->_name);
568}
569
570static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
571    CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
572    return CFHash(rlm->_name);
573}
574
575static 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");
584#endif
585#if USE_MK_TIMER_TOO
586    CFStringAppendFormat(result, NULL, CFSTR("timer port = 0x%x, "), rlm->_timerPort);
587#endif
588#if DEPLOYMENT_TARGET_WINDOWS
589    CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p, "), rlm->_msgQMask);
590#endif
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);
592    return result;
593}
594
595static 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);
608    }
609    if (rlm->_queue) {
610        dispatch_release(rlm->_queue);
611    }
612#endif
613#if USE_MK_TIMER_TOO
614    if (MACH_PORT_NULL != rlm->_timerPort) mk_timer_destroy(rlm->_timerPort);
615#endif
616    pthread_mutex_destroy(&rlm->_lock);
617    memset((char *)cf + sizeof(CFRuntimeBase), 0x7C, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase));
618}
619
620#pragma mark -
621#pragma mark Run Loops
622
623struct _block_item {
624    struct _block_item *_next;
625    CFTypeRef _mode;	// CFString or CFSet
626    void (^_block)(void);
627};
628
629typedef struct _per_run_data {
630    uint32_t a;
631    uint32_t b;
632    uint32_t stopped;
633    uint32_t ignoreWakeUps;
634} _per_run_data;
635
636struct __CFRunLoop {
637    CFRuntimeBase _base;
638    pthread_mutex_t _lock;			/* locked for accessing mode list */
639    __CFPort _wakeUpPort;			// used for CFRunLoopWakeUp
640    Boolean _unused;
641    volatile _per_run_data *_perRunData;              // reset for runs of the run loop
642    pthread_t _pthread;
643    uint32_t _winthread;
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;
651};
652
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 */
656
657CF_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;
664    return previous;
665}
666
667CF_INLINE void __CFRunLoopPopPerRunData(CFRunLoopRef rl, volatile _per_run_data *previous) {
668    if (rl->_perRunData) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (void *)rl->_perRunData);
669    rl->_perRunData = previous;
670}
671
672CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
673    return (rl->_perRunData->stopped) ? true : false;
674}
675
676CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
677    rl->_perRunData->stopped = 0x53544F50;	// 'STOP'
678}
679
680CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
681    rl->_perRunData->stopped = 0x0;
682}
683
684CF_INLINE Boolean __CFRunLoopIsIgnoringWakeUps(CFRunLoopRef rl) {
685    return (rl->_perRunData->ignoreWakeUps) ? true : false;
686}
687
688CF_INLINE void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl) {
689    rl->_perRunData->ignoreWakeUps = 0x57414B45; // 'WAKE'
690}
691
692CF_INLINE void __CFRunLoopUnsetIgnoreWakeUps(CFRunLoopRef rl) {
693    rl->_perRunData->ignoreWakeUps = 0x0;
694}
695
696CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
697    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1);
698}
699
700CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
701    __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
702}
703
704CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
705    __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
706}
707
708CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
709    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2);
710}
711
712CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
713    __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
714}
715
716CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
717    pthread_mutex_lock(&(((CFRunLoopRef)rl)->_lock));
718    //    CFLog(6, CFSTR("__CFRunLoopLock locked %p"), rl);
719}
720
721CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
722    //    CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl);
723    pthread_mutex_unlock(&(((CFRunLoopRef)rl)->_lock));
724}
725
726static 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)"));
732#else
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)"));
734#endif
735    CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
736    return result;
737}
738
739CF_PRIVATE void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
740    CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
741}
742
743CF_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);
749    if (0 != mret) {
750    }
751}
752
753/* call with rl locked, returns mode locked */
754static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
755    CHECK_FOR_FORK();
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);
762    if (NULL != rlm) {
763	__CFRunLoopModeLock(rlm);
764	return rlm;
765    }
766    if (!create) {
767	return NULL;
768    }
769    rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
770    if (NULL == rlm) {
771	return NULL;
772    }
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;
780    rlm->_timers = NULL;
781    rlm->_observerMask = 0;
782    rlm->_portSet = __CFPortSetAllocate();
783    rlm->_timerSoftDeadline = UINT64_MAX;
784    rlm->_timerHardDeadline = UINT64_MAX;
785
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);
793
794    __block Boolean *timerFiredPointer = &(rlm->_timerFired);
795    dispatch_source_set_event_handler(rlm->_timerSource, ^{
796        *timerFiredPointer = true;
797    });
798
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);
802
803    ret = __CFPortSetInsert(queuePort, rlm->_portSet);
804    if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
805
806#endif
807#if USE_MK_TIMER_TOO
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);
811#endif
812
813    ret = __CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet);
814    if (KERN_SUCCESS != ret) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret);
815
816#if DEPLOYMENT_TARGET_WINDOWS
817    rlm->_msgQMask = 0;
818    rlm->_msgPump = NULL;
819#endif
820    CFSetAddValue(rl->_modes, rlm);
821    CFRelease(rlm);
822    __CFRunLoopModeLock(rlm);	/* return mode locked */
823    return rlm;
824}
825
826
827// expects rl and rlm locked
828static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
829    CHECK_FOR_FORK();
830    if (NULL == rlm) return true;
831#if DEPLOYMENT_TARGET_WINDOWS
832    if (0 != rlm->_msgQMask) return false;
833#endif
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;
840    while (item) {
841        struct _block_item *curr = item;
842        item = item->_next;
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));
846        } else {
847            doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
848        }
849        if (doit) return false;
850    }
851    return true;
852}
853
854#if DEPLOYMENT_TARGET_WINDOWS
855
856uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) {
857    if (modeName == kCFRunLoopCommonModes) {
858	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
859	HALT;
860    }
861    DWORD result = 0;
862    __CFRunLoopLock(rl);
863    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
864    if (rlm) {
865	result = rlm->_msgQMask;
866	__CFRunLoopModeUnlock(rlm);
867    }
868    __CFRunLoopUnlock(rl);
869    return (uint32_t)result;
870}
871
872void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t mask, CFStringRef modeName) {
873    if (modeName == kCFRunLoopCommonModes) {
874	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
875	HALT;
876    }
877    __CFRunLoopLock(rl);
878    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
879    rlm->_msgQMask = (DWORD)mask;
880    __CFRunLoopModeUnlock(rlm);
881    __CFRunLoopUnlock(rl);
882}
883
884uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl) {
885    return rl->_winthread;
886}
887
888CFWindowsMessageQueueHandler _CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName) {
889    if (modeName == kCFRunLoopCommonModes) {
890	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
891	HALT;
892    }
893    if (rl != CFRunLoopGetCurrent()) {
894	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
895	HALT;
896    }
897    void (*result)(void) = NULL;
898    __CFRunLoopLock(rl);
899    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
900    if (rlm) {
901	result = rlm->_msgPump;
902	__CFRunLoopModeUnlock(rlm);
903    }
904    __CFRunLoopUnlock(rl);
905    return result;
906}
907
908void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName, CFWindowsMessageQueueHandler func) {
909    if (modeName == kCFRunLoopCommonModes) {
910	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
911	HALT;
912    }
913    if (rl != CFRunLoopGetCurrent()) {
914	CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
915	HALT;
916    }
917    __CFRunLoopLock(rl);
918    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
919    rlm->_msgPump = func;
920    __CFRunLoopModeUnlock(rlm);
921    __CFRunLoopUnlock(rl);
922}
923
924#endif
925
926#pragma mark -
927#pragma mark Sources
928
929/* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
930
931CF_INLINE Boolean __CFIsValid(const void *cf) {
932    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3);
933}
934
935CF_INLINE void __CFSetValid(void *cf) {
936    __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
937}
938
939CF_INLINE void __CFUnsetValid(void *cf) {
940    __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
941}
942
943struct __CFRunLoopSource {
944    CFRuntimeBase _base;
945    uint32_t _bits;
946    pthread_mutex_t _lock;
947    CFIndex _order;			/* immutable */
948    CFMutableBagRef _runLoops;
949    union {
950	CFRunLoopSourceContext version0;	/* immutable, except invalidation */
951        CFRunLoopSourceContext1 version1;	/* immutable, except invalidation */
952    } _context;
953};
954
955/* Bit 1 of the base reserved bits is used for signalled state */
956
957CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
958    return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
959}
960
961CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
962    __CFBitfieldSetValue(rls->_bits, 1, 1, 1);
963}
964
965CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
966    __CFBitfieldSetValue(rls->_bits, 1, 1, 0);
967}
968
969CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) {
970    pthread_mutex_lock(&(rls->_lock));
971//    CFLog(6, CFSTR("__CFRunLoopSourceLock locked %p"), rls);
972}
973
974CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
975//    CFLog(6, CFSTR("__CFRunLoopSourceLock unlocking %p"), rls);
976    pthread_mutex_unlock(&(rls->_lock));
977}
978
979#pragma mark Observers
980
981struct __CFRunLoopObserver {
982    CFRuntimeBase _base;
983    pthread_mutex_t _lock;
984    CFRunLoopRef _runLoop;
985    CFIndex _rlCount;
986    CFOptionFlags _activities;		/* immutable */
987    CFIndex _order;			/* immutable */
988    CFRunLoopObserverCallBack _callout;	/* immutable */
989    CFRunLoopObserverContext _context;	/* immutable, except invalidation */
990};
991
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 */
994
995CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
996    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0);
997}
998
999CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
1000    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
1001}
1002
1003CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
1004    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
1005}
1006
1007CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
1008    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1);
1009}
1010
1011CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
1012    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
1013}
1014
1015CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
1016    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
1017}
1018
1019CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
1020    pthread_mutex_lock(&(rlo->_lock));
1021//    CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo);
1022}
1023
1024CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
1025//    CFLog(6, CFSTR("__CFRunLoopObserverLock unlocking %p"), rlo);
1026    pthread_mutex_unlock(&(rlo->_lock));
1027}
1028
1029static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
1030    __CFRunLoopObserverLock(rlo);
1031    if (0 == rlo->_rlCount) {
1032	rlo->_runLoop = rl;
1033    }
1034    rlo->_rlCount++;
1035    __CFRunLoopObserverUnlock(rlo);
1036}
1037
1038static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
1039    __CFRunLoopObserverLock(rlo);
1040    rlo->_rlCount--;
1041    if (0 == rlo->_rlCount) {
1042	rlo->_runLoop = NULL;
1043    }
1044    __CFRunLoopObserverUnlock(rlo);
1045}
1046
1047#pragma mark Timers
1048
1049struct __CFRunLoopTimer {
1050    CFRuntimeBase _base;
1051    uint16_t _bits;
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 */
1062};
1063
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 */
1067
1068CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
1069    return (Boolean)__CFBitfieldGetValue(rlt->_bits, 0, 0);
1070}
1071
1072CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
1073    __CFBitfieldSetValue(rlt->_bits, 0, 0, 1);
1074}
1075
1076CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
1077    __CFBitfieldSetValue(rlt->_bits, 0, 0, 0);
1078}
1079
1080CF_INLINE Boolean __CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt) {
1081    return (Boolean)__CFBitfieldGetValue(rlt->_bits, 2, 2);
1082}
1083
1084CF_INLINE void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt) {
1085    __CFBitfieldSetValue(rlt->_bits, 2, 2, 1);
1086}
1087
1088CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
1089    pthread_mutex_lock(&(rlt->_lock));
1090//    CFLog(6, CFSTR("__CFRunLoopTimerLock locked %p"), rlt);
1091}
1092
1093CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
1094//    CFLog(6, CFSTR("__CFRunLoopTimerLock unlocking %p"), rlt);
1095    pthread_mutex_unlock(&(rlt->_lock));
1096}
1097
1098static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit;
1099
1100CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
1101    __CFSpinLock(&__CFRLTFireTSRLock);
1102}
1103
1104CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
1105    __CFSpinUnlock(&__CFRLTFireTSRLock);
1106}
1107
1108#pragma mark -
1109
1110/* CFRunLoop */
1111
1112CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
1113CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
1114
1115// call with rl and rlm locked
1116static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) {	/* DOES CALLOUT */
1117    CHECK_FOR_FORK();
1118    CFRunLoopSourceRef found = rlm->_portToV1SourceMap ? (CFRunLoopSourceRef)CFDictionaryGetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)port) : NULL;
1119    return found;
1120}
1121
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.
1128static void __CFRunLoopCleanseSources(const void *value, void *context) {
1129    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1130    CFRunLoopRef rl = (CFRunLoopRef)context;
1131    CFIndex idx, cnt;
1132    const void **list, *buffer[256];
1133    if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;
1134
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);
1144	}
1145	__CFRunLoopSourceUnlock(rls);
1146    }
1147    if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1148}
1149
1150static void __CFRunLoopDeallocateSources(const void *value, void *context) {
1151    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1152    CFRunLoopRef rl = (CFRunLoopRef)context;
1153    CFIndex idx, cnt;
1154    const void **list, *buffer[256];
1155    if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;
1156
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]);
1163    }
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);
1171        }
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 */
1176            }
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);
1181            }
1182        }
1183	CFRelease(rls);
1184    }
1185    if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1186}
1187
1188static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
1189    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1190    CFRunLoopRef rl = (CFRunLoopRef)context;
1191    CFIndex idx, cnt;
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]);
1199    }
1200    CFArrayRemoveAllValues(rlm->_observers);
1201    for (idx = 0; idx < cnt; idx++) {
1202	__CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm);
1203	CFRelease(list[idx]);
1204    }
1205    if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1206}
1207
1208static 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) {
1212        CFIndex idx, cnt;
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]);
1219        }
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]);
1231        }
1232        if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1233    };
1234
1235    if (rlm->_timers && CFArrayGetCount(rlm->_timers)) deallocateTimers(rlm->_timers);
1236}
1237
1238CF_EXPORT CFRunLoopRef _CFRunLoopGet0b(pthread_t t);
1239
1240static void __CFRunLoopDeallocate(CFTypeRef cf) {
1241    CFRunLoopRef rl = (CFRunLoopRef)cf;
1242
1243    if (_CFRunLoopGet0b(pthread_main_thread_np()) == cf) HALT;
1244
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
1252       three lines. */
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);
1259    }
1260    __CFRunLoopLock(rl);
1261    struct _block_item *item = rl->_blocks_head;
1262    while (item) {
1263	struct _block_item *curr = item;
1264	item = item->_next;
1265	CFRelease(curr->_mode);
1266	Block_release(curr->_block);
1267	free(curr);
1268    }
1269    if (NULL != rl->_commonModeItems) {
1270	CFRelease(rl->_commonModeItems);
1271    }
1272    if (NULL != rl->_commonModes) {
1273	CFRelease(rl->_commonModes);
1274    }
1275    if (NULL != rl->_modes) {
1276	CFRelease(rl->_modes);
1277    }
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));
1284}
1285
1286static const CFRuntimeClass __CFRunLoopModeClass = {
1287    0,
1288    "CFRunLoopMode",
1289    NULL,      // init
1290    NULL,      // copy
1291    __CFRunLoopModeDeallocate,
1292    __CFRunLoopModeEqual,
1293    __CFRunLoopModeHash,
1294    NULL,      //
1295    __CFRunLoopModeCopyDescription
1296};
1297
1298static const CFRuntimeClass __CFRunLoopClass = {
1299    0,
1300    "CFRunLoop",
1301    NULL,      // init
1302    NULL,      // copy
1303    __CFRunLoopDeallocate,
1304    NULL,
1305    NULL,
1306    NULL,      //
1307    __CFRunLoopCopyDescription
1308};
1309
1310CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data);
1311
1312CF_PRIVATE void __CFRunLoopInitialize(void) {
1313    __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);
1314    __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass);
1315}
1316
1317CFTypeID CFRunLoopGetTypeID(void) {
1318    return __kCFRunLoopTypeID;
1319}
1320
1321static 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);
1326    if (NULL == loop) {
1327	return NULL;
1328    }
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;
1342    loop->_pthread = t;
1343#if DEPLOYMENT_TARGET_WINDOWS
1344    loop->_winthread = GetCurrentThreadId();
1345#else
1346    loop->_winthread = 0;
1347#endif
1348    rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
1349    if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
1350    return loop;
1351}
1352
1353static CFMutableDictionaryRef __CFRunLoops = NULL;
1354static CFSpinLock_t loopsLock = CFSpinLockInit;
1355
1356// should only be called by Foundation
1357// t==0 is a synonym for "main thread" that always works
1358CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
1359    if (pthread_equal(t, kNilPthreadT)) {
1360	t = pthread_main_thread_np();
1361    }
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)) {
1369	    CFRelease(dict);
1370	}
1371	CFRelease(mainLoop);
1372        __CFSpinLock(&loopsLock);
1373    }
1374    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1375    __CFSpinUnlock(&loopsLock);
1376    if (!loop) {
1377	CFRunLoopRef newLoop = __CFRunLoopCreate(t);
1378        __CFSpinLock(&loopsLock);
1379	loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1380	if (!loop) {
1381	    CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
1382	    loop = newLoop;
1383	}
1384        // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
1385        __CFSpinUnlock(&loopsLock);
1386	CFRelease(newLoop);
1387    }
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);
1392        }
1393    }
1394    return loop;
1395}
1396
1397// should only be called by Foundation
1398CFRunLoopRef _CFRunLoopGet0b(pthread_t t) {
1399    if (pthread_equal(t, kNilPthreadT)) {
1400	t = pthread_main_thread_np();
1401    }
1402    __CFSpinLock(&loopsLock);
1403    CFRunLoopRef loop = NULL;
1404    if (__CFRunLoops) {
1405        loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1406    }
1407    __CFSpinUnlock(&loopsLock);
1408    return loop;
1409}
1410
1411static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName);
1412
1413// Called for each thread as it exits
1414CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data) {
1415    CFRunLoopRef rl = NULL;
1416    if (data <= 1) {
1417	__CFSpinLock(&loopsLock);
1418	if (__CFRunLoops) {
1419	    rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
1420	    if (rl) CFRetain(rl);
1421	    CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
1422	}
1423	__CFSpinUnlock(&loopsLock);
1424    } else {
1425        _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(data - 1), (void (*)(void *))__CFFinalizeRunLoop);
1426    }
1427    if (rl && CFRunLoopGetMain() != rl) { // protect against cooperative threads
1428        if (NULL != rl->_counterpart) {
1429            CFRelease(rl->_counterpart);
1430	    rl->_counterpart = NULL;
1431        }
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);
1437        }
1438        __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
1439        CFRelease(array);
1440    }
1441    if (rl) CFRelease(rl);
1442}
1443
1444pthread_t _CFRunLoopGet1(CFRunLoopRef rl) {
1445    return rl->_pthread;
1446}
1447
1448// should only be called by Foundation
1449CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl) {
1450    CFTypeRef ret = NULL;
1451    __CFSpinLock(&loopsLock);
1452    ret = rl->_counterpart;
1453    __CFSpinUnlock(&loopsLock);
1454    return ret;
1455}
1456
1457// should only be called by Foundation
1458CF_EXPORT CFTypeRef _CFRunLoopGet2b(CFRunLoopRef rl) {
1459    return rl->_counterpart;
1460}
1461
1462#if DEPLOYMENT_TARGET_MACOSX
1463void _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);
1469	if (rl) {
1470	    CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl);
1471	} else {
1472	    CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
1473	}
1474        __CFSpinUnlock(&loopsLock);
1475	CFRelease(currentLoop);
1476        _CFSetTSD(__CFTSDKeyRunLoop, NULL, NULL);
1477        _CFSetTSD(__CFTSDKeyRunLoopCntr, 0, (void (*)(void *))__CFFinalizeRunLoop);
1478    }
1479}
1480#endif
1481
1482CFRunLoopRef CFRunLoopGetMain(void) {
1483    CHECK_FOR_FORK();
1484    static CFRunLoopRef __main = NULL; // no retain needed
1485    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
1486    return __main;
1487}
1488
1489CFRunLoopRef CFRunLoopGetCurrent(void) {
1490    CHECK_FOR_FORK();
1491    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
1492    if (rl) return rl;
1493    return _CFRunLoopGet0(pthread_self());
1494}
1495
1496CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
1497    CHECK_FOR_FORK();
1498    CFStringRef result = NULL;
1499    __CFRunLoopLock(rl);
1500    if (NULL != rl->_currentMode) {
1501	result = (CFStringRef)CFRetain(rl->_currentMode->_name);
1502    }
1503    __CFRunLoopUnlock(rl);
1504    return result;
1505}
1506
1507static void __CFRunLoopGetModeName(const void *value, void *context) {
1508    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1509    CFMutableArrayRef array = (CFMutableArrayRef)context;
1510    CFArrayAppendValue(array, rlm->_name);
1511}
1512
1513CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) {
1514    CHECK_FOR_FORK();
1515    CFMutableArrayRef array;
1516    __CFRunLoopLock(rl);
1517    array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks);
1518    CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array);
1519    __CFRunLoopUnlock(rl);
1520    return array;
1521}
1522
1523static 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);
1533    }
1534}
1535
1536static 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);
1546    }
1547}
1548
1549static 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);
1559    }
1560}
1561
1562CF_EXPORT Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) {
1563    __CFRunLoopLock(rl);
1564    Boolean present = CFSetContainsValue(rl->_commonModes, modeName);
1565    __CFRunLoopUnlock(rl);
1566    return present;
1567}
1568
1569void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
1570    CHECK_FOR_FORK();
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);
1576	if (NULL != set) {
1577	    CFTypeRef context[2] = {rl, modeName};
1578	    /* add all common-modes items to new mode */
1579	    CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
1580	    CFRelease(set);
1581	}
1582    } else {
1583    }
1584    __CFRunLoopUnlock(rl);
1585}
1586
1587
1588static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() __attribute__((noinline));
1589static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(void *msg) {
1590    _dispatch_main_queue_callback_4CF(msg);
1591    getpid(); // thwart tail-call optimization
1592}
1593
1594static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline));
1595static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
1596    if (func) {
1597        func(observer, activity, info);
1598    }
1599    getpid(); // thwart tail-call optimization
1600}
1601
1602static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline));
1603static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func, CFRunLoopTimerRef timer, void *info) {
1604    if (func) {
1605        func(timer, info);
1606    }
1607    getpid(); // thwart tail-call optimization
1608}
1609
1610static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline));
1611static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block)(void)) {
1612    if (block) {
1613        block();
1614    }
1615    getpid(); // thwart tail-call optimization
1616}
1617
1618static 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;
1632    while (item) {
1633        struct _block_item *curr = item;
1634        item = item->_next;
1635	Boolean doit = false;
1636	if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
1637	    doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
1638        } else {
1639	    doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
1640	}
1641	if (!doit) prev = curr;
1642	if (doit) {
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);
1648            free(curr);
1649	    if (doit) {
1650                __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
1651	        did = true;
1652	    }
1653            Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1654	}
1655    }
1656    __CFRunLoopLock(rl);
1657    __CFRunLoopModeLock(rlm);
1658    if (head) {
1659	tail->_next = rl->_blocks_head;
1660	rl->_blocks_head = head;
1661        if (!rl->_blocks_tail) rl->_blocks_tail = tail;
1662    }
1663    return did;
1664}
1665
1666/* rl is locked, rlm is locked on entrance and exit */
1667static void __CFRunLoopDoObservers() __attribute__((noinline));
1668static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) {	/* DOES CALLOUT */
1669    CHECK_FOR_FORK();
1670
1671    CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
1672    if (cnt < 1) return;
1673
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);
1682        }
1683    }
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);
1694            if (doInvalidate) {
1695                CFRunLoopObserverInvalidate(rlo);
1696            }
1697            __CFRunLoopObserverUnsetFiring(rlo);
1698        } else {
1699            __CFRunLoopObserverUnlock(rlo);
1700        }
1701        CFRelease(rlo);
1702    }
1703    __CFRunLoopLock(rl);
1704    __CFRunLoopModeLock(rlm);
1705
1706    if (collectedObservers != buffer) free(collectedObservers);
1707}
1708
1709static 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;
1715}
1716
1717static 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);
1728	    CFRelease(oldrls);
1729	} else {
1730	    CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1731	}
1732    }
1733}
1734
1735static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline));
1736static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info) {
1737    if (perform) {
1738        perform(info);
1739    }
1740    getpid(); // thwart tail-call optimization
1741}
1742
1743static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline));
1744static 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,
1748#else
1749        void (*perform)(void *),
1750#endif
1751        void *info) {
1752    if (perform) {
1753#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1754        *reply = perform(msg, size, kCFAllocatorSystemDefault, info);
1755#else
1756        perform(info);
1757#endif
1758    }
1759    getpid(); // thwart tail-call optimization
1760}
1761
1762/* rl is locked, rlm is locked on entrance and exit */
1763static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) __attribute__((noinline));
1764static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) {	/* DOES CALLOUT */
1765    CHECK_FOR_FORK();
1766    CFTypeRef sources = NULL;
1767    Boolean sourceHandled = false;
1768
1769    /* Fire the version 0 sources */
1770    if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) {
1771	CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources);
1772    }
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);
1785	            CHECK_FOR_FORK();
1786	            sourceHandled = true;
1787	        } else {
1788	            __CFRunLoopSourceUnlock(rls);
1789	        }
1790            } else {
1791                __CFRunLoopSourceUnlock(rls);
1792            }
1793	} else {
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);
1804		        CHECK_FOR_FORK();
1805		        sourceHandled = true;
1806		    } else {
1807		        __CFRunLoopSourceUnlock(rls);
1808		    }
1809                } else {
1810                    __CFRunLoopSourceUnlock(rls);
1811                }
1812		if (stopAfterHandle && sourceHandled) {
1813		    break;
1814		}
1815	    }
1816	}
1817	CFRelease(sources);
1818	__CFRunLoopLock(rl);
1819	__CFRunLoopModeLock(rlm);
1820    }
1821    return sourceHandled;
1822}
1823
1824CF_INLINE void __CFRunLoopDebugInfoForRunLoopSource(CFRunLoopSourceRef rls) {
1825}
1826
1827// msg, size and reply are unused on Windows
1828static Boolean __CFRunLoopDoSource1() __attribute__((noinline));
1829static 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
1832#endif
1833                                    ) {	/* DOES CALLOUT */
1834    CHECK_FOR_FORK();
1835    Boolean sourceHandled = false;
1836
1837    /* Fire a version 1 source */
1838    CFRetain(rls);
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
1848            msg, size, reply,
1849#endif
1850            rls->_context.version1.info);
1851	CHECK_FOR_FORK();
1852	sourceHandled = true;
1853    } else {
1854        if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
1855	__CFRunLoopSourceUnlock(rls);
1856    }
1857    CFRelease(rls);
1858    __CFRunLoopLock(rl);
1859    __CFRunLoopModeLock(rlm);
1860    return sourceHandled;
1861}
1862
1863static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) __attribute__((noinline));
1864static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) {
1865    CFIndex cnt = CFArrayGetCount(array);
1866    if (cnt <= 0) {
1867        return 0;
1868    }
1869    if (256 < cnt) {
1870        CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, cnt - 1);
1871        if (item->_fireTSR <= rlt->_fireTSR) {
1872            return cnt;
1873        }
1874        item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, 0);
1875        if (rlt->_fireTSR < item->_fireTSR) {
1876            return 0;
1877        }
1878    }
1879
1880    CFIndex add = (1 << flsl(cnt)) * 2;
1881    CFIndex idx = 0;
1882    Boolean lastTestLEQ;
1883    do {
1884        add = add / 2;
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) {
1890                idx = testIdx;
1891		lastTestLEQ = true;
1892            }
1893        }
1894    } while (0 < add);
1895
1896    return lastTestLEQ ? idx + 1 : idx;
1897}
1898
1899static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm, CFRunLoopRef rl) {
1900    uint64_t nextHardDeadline = UINT64_MAX;
1901    uint64_t nextSoftDeadline = UINT64_MAX;
1902
1903    if (rlm->_timers) {
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;
1911
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;
1916
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) {
1919                break;
1920            }
1921
1922            if (oneTimerSoftDeadline < nextSoftDeadline) {
1923                nextSoftDeadline = oneTimerSoftDeadline;
1924            }
1925
1926            if (oneTimerHardDeadline < nextHardDeadline) {
1927                nextHardDeadline = oneTimerHardDeadline;
1928            }
1929        }
1930
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()));
1934            }
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
1940            if (leeway > 0) {
1941                // Only use the dispatch timer if we have any leeway
1942                // <rdar://problem/14447675>
1943
1944                // Cancel the mk timer
1945                if (rlm->_mkTimerArmed && rlm->_timerPort) {
1946                    AbsoluteTime dummy;
1947                    mk_timer_cancel(rlm->_timerPort, &dummy);
1948                    rlm->_mkTimerArmed = false;
1949                }
1950
1951                // Arm the dispatch timer
1952                _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
1953                rlm->_dispatchTimerArmed = true;
1954            } else {
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;
1960                }
1961
1962                // Arm the mk timer
1963                if (rlm->_timerPort) {
1964                    mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
1965                    rlm->_mkTimerArmed = true;
1966                }
1967            }
1968#else
1969            _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
1970#endif
1971#else
1972            if (rlm->_timerPort) {
1973                mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
1974            }
1975#endif
1976        } else if (nextSoftDeadline == UINT64_MAX) {
1977            // Disarm the timers - there is no timer scheduled
1978
1979            if (rlm->_mkTimerArmed && rlm->_timerPort) {
1980                AbsoluteTime dummy;
1981                mk_timer_cancel(rlm->_timerPort, &dummy);
1982                rlm->_mkTimerArmed = false;
1983            }
1984
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;
1989            }
1990#endif
1991        }
1992    }
1993    rlm->_timerHardDeadline = nextHardDeadline;
1994    rlm->_timerSoftDeadline = nextSoftDeadline;
1995}
1996
1997// call with rlm and its run loop locked, and the TSRLock locked; rlt not locked; returns with same state
1998static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) __attribute__((noinline));
1999static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) {
2000    if (!rlt) return;
2001
2002    CFMutableArrayRef timerArray = rlm->_timers;
2003    if (!timerArray) return;
2004    Boolean found = false;
2005
2006    // If we know in advance that the timer is not in the array (just being added now) then we can skip this search
2007    if (isInArray) {
2008        CFIndex idx = CFArrayGetFirstIndexOfValue(timerArray, CFRangeMake(0, CFArrayGetCount(timerArray)), rlt);
2009        if (kCFNotFound != idx) {
2010            CFRetain(rlt);
2011            CFArrayRemoveValueAtIndex(timerArray, idx);
2012            found = true;
2013        }
2014    }
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);
2020}
2021
2022
2023// mode and rl are locked on entry and exit
2024static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) {	/* DOES CALLOUT */
2025    Boolean timerHandled = false;
2026    uint64_t oldFireTSR = 0;
2027
2028    /* Fire a timer */
2029    CFRetain(rlt);
2030    __CFRunLoopTimerLock(rlt);
2031
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;
2038        } else {
2039            context_info = rlt->_context.info;
2040        }
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();
2050
2051        __CFArmNextTimerInMode(rlm, rl);
2052
2053	__CFRunLoopModeUnlock(rlm);
2054	__CFRunLoopUnlock(rl);
2055	__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt->_callout, rlt, context_info);
2056	CHECK_FOR_FORK();
2057        if (doInvalidate) {
2058            CFRunLoopTimerInvalidate(rlt);      /* DOES CALLOUT */
2059        }
2060        if (context_release) {
2061            context_release(context_info);
2062        }
2063	__CFRunLoopLock(rl);
2064	__CFRunLoopModeLock(rlm);
2065        __CFRunLoopTimerLock(rlt);
2066	timerHandled = true;
2067	__CFRunLoopTimerUnsetFiring(rlt);
2068    }
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);
2084        } else {
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);
2090            } else {
2091        	intervalTSR = __CFTimeIntervalToTSR(rlt->_interval);
2092            }
2093            if (LLONG_MAX - intervalTSR <= oldFireTSR) {
2094                nextFireTSR = LLONG_MAX;
2095            } else {
2096                uint64_t currentTSR = mach_absolute_time();
2097                nextFireTSR = oldFireTSR;
2098                while (nextFireTSR <= currentTSR) {
2099                    nextFireTSR += intervalTSR;
2100                }
2101            }
2102            CFRunLoopRef rlt_rl = rlt->_runLoop;
2103            if (rlt_rl) {
2104                CFRetain(rlt_rl);
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]);
2114		}
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);
2119		    CFRelease(name);
2120		}
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];
2126		    if (rlm) {
2127                        __CFRepositionTimerInMode(rlm, rlt, true);
2128		    }
2129		}
2130		__CFRunLoopTimerFireTSRUnlock();
2131		for (CFIndex idx = 0; idx < cnt; idx++) {
2132		    __CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]);
2133		}
2134		CFRelease(rlt_rl);
2135	    } else {
2136		__CFRunLoopTimerUnlock(rlt);
2137		__CFRunLoopTimerFireTSRLock();
2138		rlt->_fireTSR = nextFireTSR;
2139                rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
2140		__CFRunLoopTimerFireTSRUnlock();
2141            }
2142        }
2143    } else {
2144        __CFRunLoopTimerUnlock(rlt);
2145    }
2146    CFRelease(rlt);
2147    return timerHandled;
2148}
2149
2150
2151// rl and rlm are locked on entry and exit
2152static 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);
2157
2158        if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
2159            if (rlt->_fireTSR <= limitTSR) {
2160                if (!timers) timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
2161                CFArrayAppendValue(timers, rlt);
2162            }
2163        }
2164    }
2165
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;
2170    }
2171    if (timers) CFRelease(timers);
2172    return timerHandled;
2173}
2174
2175
2176CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
2177    CHECK_FOR_FORK();
2178    CFRunLoopModeRef rlm;
2179    Boolean result = false;
2180    __CFRunLoopLock(rl);
2181    rlm = __CFRunLoopFindMode(rl, modeName, false);
2182    if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm, NULL)) {
2183	result = true;
2184    }
2185    if (rlm) __CFRunLoopModeUnlock(rlm);
2186    __CFRunLoopUnlock(rl);
2187    return result;
2188}
2189
2190static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) __attribute__((noinline));
2191
2192#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2193
2194#define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0)
2195
2196static 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;
2201        msg->msgh_bits = 0;
2202        msg->msgh_local_port = port;
2203        msg->msgh_remote_port = MACH_PORT_NULL;
2204        msg->msgh_size = buffer_size;
2205        msg->msgh_id = 0;
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;
2211            return true;
2212        }
2213        if (MACH_RCV_TIMED_OUT == ret) {
2214            if (!originalBuffer) free(msg);
2215            *buffer = NULL;
2216            *livePort = MACH_PORT_NULL;
2217            return false;
2218        }
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);
2224    }
2225    HALT;
2226    return false;
2227}
2228
2229#elif DEPLOYMENT_TARGET_WINDOWS
2230
2231#define TIMEOUT_INFINITY INFINITE
2232
2233// pass in either a portSet or onePort
2234static 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;
2241
2242    if (portSet) {
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);
2246    } else {
2247	handles = onePort;
2248	handleCount = 1;
2249	freeHandles = FALSE;
2250    }
2251
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);
2254
2255    CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError());
2256
2257    if (waitResult == WAIT_TIMEOUT) {
2258	// do nothing, just return to caller
2259	result = false;
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];
2263	result = true;
2264    } else if (waitResult == WAIT_OBJECT_0+handleCount) {
2265	// windows message received
2266        if (msgReceived) *msgReceived = true;
2267	result = 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];
2271	result = true;
2272    } else {
2273	CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult);
2274	result = false;
2275    }
2276
2277    if (freeHandles) {
2278	CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
2279    }
2280
2281    return result;
2282}
2283
2284#endif
2285
2286struct __timeout_context {
2287    dispatch_source_t ds;
2288    CFRunLoopRef rl;
2289    uint64_t termTSR;
2290};
2291
2292static void __CFRunLoopTimeoutCancel(void *arg) {
2293    struct __timeout_context *context = (struct __timeout_context *)arg;
2294    CFRelease(context->rl);
2295    dispatch_release(context->ds);
2296    free(context);
2297}
2298
2299static 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
2305}
2306
2307/* rl, rlm are locked on entrance and exit */
2308static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
2309    uint64_t startTSR = mach_absolute_time();
2310
2311    if (__CFRunLoopIsStopped(rl)) {
2312        __CFRunLoopUnsetStopped(rl);
2313	return kCFRunLoopRunStopped;
2314    } else if (rlm->_stopped) {
2315	rlm->_stopped = false;
2316	return kCFRunLoopRunStopped;
2317    }
2318
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();
2322
2323#if USE_DISPATCH_SOURCE_FOR_TIMERS
2324    mach_port_name_t modeQueuePort = MACH_PORT_NULL;
2325    if (rlm->_queue) {
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);
2329        }
2330    }
2331#endif
2332
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
2336        seconds = 0.0;
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;
2354    }
2355
2356    Boolean didDispatchPortLastTime = true;
2357    int32_t retVal = 0;
2358    do {
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;
2366#endif
2367	__CFPortSet waitSet = rlm->_portSet;
2368
2369        __CFRunLoopUnsetIgnoreWakeUps(rl);
2370
2371        if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
2372        if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
2373
2374	__CFRunLoopDoBlocks(rl, rlm);
2375
2376        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
2377        if (sourceHandledThisLoop) {
2378            __CFRunLoopDoBlocks(rl, rlm);
2379	}
2380
2381        Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
2382
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)) {
2387                goto handle_msg;
2388            }
2389#elif DEPLOYMENT_TARGET_WINDOWS
2390            if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) {
2391                goto handle_msg;
2392            }
2393#endif
2394        }
2395
2396        didDispatchPortLastTime = false;
2397
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)
2401
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.
2405
2406        __CFPortSetInsert(dispatchPort, waitSet);
2407
2408	__CFRunLoopModeUnlock(rlm);
2409	__CFRunLoopUnlock(rl);
2410
2411#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2412#if USE_DISPATCH_SOURCE_FOR_TIMERS
2413        do {
2414            if (kCFUseCollectableAllocator) {
2415                objc_clear_stack(0);
2416                memset(msg_buffer, 0, sizeof(msg_buffer));
2417            }
2418            msg = (mach_msg_header_t *)msg_buffer;
2419            __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY);
2420
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;
2427                    break;
2428                } else {
2429                    if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
2430                }
2431            } else {
2432                // Go ahead and leave the inner loop.
2433                break;
2434            }
2435        } while (1);
2436#else
2437        if (kCFUseCollectableAllocator) {
2438            objc_clear_stack(0);
2439            memset(msg_buffer, 0, sizeof(msg_buffer));
2440        }
2441        msg = (mach_msg_header_t *)msg_buffer;
2442        __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY);
2443#endif
2444
2445
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);
2449#endif
2450
2451        __CFRunLoopLock(rl);
2452        __CFRunLoopModeLock(rlm);
2453
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.
2458
2459        __CFPortSetRemove(dispatchPort, waitSet);
2460
2461        __CFRunLoopSetIgnoreWakeUps(rl);
2462
2463        // user callouts now OK again
2464	__CFRunLoopUnsetSleeping(rl);
2465	if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
2466
2467        handle_msg:;
2468        __CFRunLoopSetIgnoreWakeUps(rl);
2469
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);
2475
2476            if (rlm->_msgPump) {
2477                rlm->_msgPump();
2478            } else {
2479                MSG msg;
2480                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
2481                    TranslateMessage(&msg);
2482                    DispatchMessage(&msg);
2483                }
2484            }
2485
2486            __CFRunLoopLock(rl);
2487	    __CFRunLoopModeLock(rlm);
2488 	    sourceHandledThisLoop = true;
2489
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);
2496
2497            __CFRunLoopWaitForMultipleObjects(waitSet, NULL, 0, 0, &livePort, NULL);
2498
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
2503        }
2504
2505
2506#endif
2507        if (MACH_PORT_NULL == livePort) {
2508            CFRUNLOOP_WAKEUP_FOR_NOTHING();
2509            // handle 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);
2516#endif
2517        }
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);
2524            }
2525        }
2526#endif
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);
2535            }
2536        }
2537#endif
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
2544            void *msg = 0;
2545#endif
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;
2552        } else {
2553            CFRUNLOOP_WAKEUP_FOR_SOURCE();
2554            // Despite the name, this works for windows handles as well
2555            CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);
2556            if (rls) {
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);
2563		}
2564#elif DEPLOYMENT_TARGET_WINDOWS
2565                sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop;
2566#endif
2567	    }
2568        }
2569#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2570        if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
2571#endif
2572
2573	__CFRunLoopDoBlocks(rl, rlm);
2574
2575
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;
2588	}
2589    } while (0 == retVal);
2590
2591    if (timeout_timer) {
2592        dispatch_source_cancel(timeout_timer);
2593        dispatch_release(timeout_timer);
2594    } else {
2595        free(timeout_context);
2596    }
2597
2598    return retVal;
2599}
2600
2601SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */
2602    CHECK_FOR_FORK();
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;
2611    }
2612    volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
2613    CFRunLoopModeRef previousMode = rl->_currentMode;
2614    rl->_currentMode = currentMode;
2615    int32_t result = kCFRunLoopRunFinished;
2616
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);
2620
2621        __CFRunLoopModeUnlock(currentMode);
2622        __CFRunLoopPopPerRunData(rl, previousPerRun);
2623	rl->_currentMode = previousMode;
2624    __CFRunLoopUnlock(rl);
2625    return result;
2626}
2627
2628void CFRunLoopRun(void) {	/* DOES CALLOUT */
2629    int32_t result;
2630    do {
2631        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
2632        CHECK_FOR_FORK();
2633    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
2634}
2635
2636SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */
2637    CHECK_FOR_FORK();
2638    return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
2639}
2640
2641CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
2642    CHECK_FOR_FORK();
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;
2647    if (nextTimer) {
2648        at = CFRunLoopTimerGetNextFireDate(nextTimer);
2649    }
2650    if (rlm) __CFRunLoopModeUnlock(rlm);
2651    __CFRunLoopUnlock(rl);
2652    return at;
2653}
2654
2655Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
2656    CHECK_FOR_FORK();
2657    return __CFRunLoopIsSleeping(rl);
2658}
2659
2660void CFRunLoopWakeUp(CFRunLoopRef rl) {
2661    CHECK_FOR_FORK();
2662    // This lock is crucial to ignorable wakeups, do not remove it.
2663    __CFRunLoopLock(rl);
2664    if (__CFRunLoopIsIgnoringWakeUps(rl)) {
2665        __CFRunLoopUnlock(rl);
2666        return;
2667    }
2668#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2669    kern_return_t ret;
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);
2677#endif
2678    __CFRunLoopUnlock(rl);
2679}
2680
2681void CFRunLoopStop(CFRunLoopRef rl) {
2682    Boolean doWake = false;
2683    CHECK_FOR_FORK();
2684    __CFRunLoopLock(rl);
2685    if (rl->_currentMode) {
2686        __CFRunLoopSetStopped(rl);
2687        doWake = true;
2688    }
2689    __CFRunLoopUnlock(rl);
2690    if (doWake) {
2691        CFRunLoopWakeUp(rl);
2692    }
2693}
2694
2695CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
2696    CHECK_FOR_FORK();
2697    CFRunLoopModeRef rlm;
2698    __CFRunLoopLock(rl);
2699    rlm = __CFRunLoopFindMode(rl, modeName, true);
2700    if (NULL != rlm) {
2701	rlm->_stopped = true;
2702	__CFRunLoopModeUnlock(rlm);
2703    }
2704    __CFRunLoopUnlock(rl);
2705    CFRunLoopWakeUp(rl);
2706}
2707
2708CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
2709    CHECK_FOR_FORK();
2710    return false;
2711}
2712
2713void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) {
2714    CHECK_FOR_FORK();
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);
2732	}
2733        __CFRunLoopUnlock(rl);
2734	free(values);
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);
2745	}
2746        __CFRunLoopUnlock(rl);
2747	free(values);
2748    } else {
2749	mode = NULL;
2750    }
2751    block = Block_copy(block);
2752    if (!mode || !block) {
2753	if (mode) CFRelease(mode);
2754	if (block) Block_release(block);
2755	return;
2756    }
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;
2764    } else {
2765	rl->_blocks_tail->_next = new_item;
2766    }
2767    rl->_blocks_tail = new_item;
2768    __CFRunLoopUnlock(rl);
2769}
2770
2771Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
2772    CHECK_FOR_FORK();
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);
2779	}
2780    } else {
2781	rlm = __CFRunLoopFindMode(rl, modeName, false);
2782	if (NULL != rlm) {
2783	    hasValue = (rlm->_sources0 ? CFSetContainsValue(rlm->_sources0, rls) : false) || (rlm->_sources1 ? CFSetContainsValue(rlm->_sources1, rls) : false);
2784	    __CFRunLoopModeUnlock(rlm);
2785	}
2786    }
2787    __CFRunLoopUnlock(rl);
2788    return hasValue;
2789}
2790
2791void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {	/* DOES CALLOUT */
2792    CHECK_FOR_FORK();
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);
2801	}
2802	CFSetAddValue(rl->_commonModeItems, rls);
2803	if (NULL != set) {
2804	    CFTypeRef context[2] = {rl, rls};
2805	    /* add new item to all common-modes */
2806	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2807	    CFRelease(set);
2808	}
2809    } else {
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);
2815	}
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);
2825	        }
2826	    }
2827	    __CFRunLoopSourceLock(rls);
2828	    if (NULL == rls->_runLoops) {
2829	        rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops!
2830	    }
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;
2836	        }
2837	    }
2838	}
2839        if (NULL != rlm) {
2840	    __CFRunLoopModeUnlock(rlm);
2841	}
2842    }
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 */
2850    }
2851}
2852
2853void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {	/* DOES CALLOUT */
2854    CHECK_FOR_FORK();
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);
2861	    if (NULL != set) {
2862		CFTypeRef context[2] = {rl, rls};
2863		/* remove new item from all common-modes */
2864		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2865		CFRelease(set);
2866	    }
2867	} else {
2868	}
2869    } else {
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)))) {
2872	    CFRetain(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);
2878                }
2879	    }
2880	    CFSetRemoveValue(rlm->_sources0, rls);
2881	    CFSetRemoveValue(rlm->_sources1, rls);
2882            __CFRunLoopSourceLock(rls);
2883            if (NULL != rls->_runLoops) {
2884                CFBagRemoveValue(rls->_runLoops, rl);
2885            }
2886            __CFRunLoopSourceUnlock(rls);
2887	    if (0 == rls->_context.version0.version) {
2888	        if (NULL != rls->_context.version0.cancel) {
2889	            doVer0Callout = true;
2890	        }
2891	    }
2892	    doRLSRelease = true;
2893	}
2894        if (NULL != rlm) {
2895	    __CFRunLoopModeUnlock(rlm);
2896	}
2897    }
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 */
2905    }
2906    if (doRLSRelease) CFRelease(rls);
2907}
2908
2909static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
2910    CFStringRef modeName = (CFStringRef)value;
2911    CFRunLoopRef rl = (CFRunLoopRef)ctx;
2912    __CFRunLoopRemoveAllSources(rl, modeName);
2913}
2914
2915static 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);
2920}
2921
2922static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
2923    CHECK_FOR_FORK();
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;
2929	    if (NULL != set) {
2930                CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
2931		CFRelease(set);
2932	    }
2933	} else {
2934	}
2935    } else {
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);
2941	    CFRelease(set);
2942	}
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);
2947	    CFRelease(set);
2948	}
2949        if (NULL != rlm) {
2950	    __CFRunLoopModeUnlock(rlm);
2951	}
2952    }
2953    __CFRunLoopUnlock(rl);
2954}
2955
2956Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2957    CHECK_FOR_FORK();
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);
2964	}
2965    } else {
2966	rlm = __CFRunLoopFindMode(rl, modeName, false);
2967	if (NULL != rlm && NULL != rlm->_observers) {
2968	    hasValue = CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo);
2969	}
2970        if (NULL != rlm) {
2971	    __CFRunLoopModeUnlock(rlm);
2972	}
2973    }
2974    __CFRunLoopUnlock(rl);
2975    return hasValue;
2976}
2977
2978void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2979    CHECK_FOR_FORK();
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);
2988	}
2989	CFSetAddValue(rl->_commonModeItems, rlo);
2990	if (NULL != set) {
2991	    CFTypeRef context[2] = {rl, rlo};
2992	    /* add new item to all common-modes */
2993	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2994	    CFRelease(set);
2995	}
2996    } else {
2997	rlm = __CFRunLoopFindMode(rl, modeName, true);
2998	if (NULL != rlm && NULL == rlm->_observers) {
2999	    rlm->_observers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
3000	}
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);
3007                    inserted = true;
3008                    break;
3009                }
3010            }
3011            if (!inserted) {
3012	        CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo);
3013            }
3014	    rlm->_observerMask |= rlo->_activities;
3015	    __CFRunLoopObserverSchedule(rlo, rl, rlm);
3016	}
3017        if (NULL != rlm) {
3018	    __CFRunLoopModeUnlock(rlm);
3019	}
3020    }
3021    __CFRunLoopUnlock(rl);
3022}
3023
3024void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
3025    CHECK_FOR_FORK();
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);
3032	    if (NULL != set) {
3033		CFTypeRef context[2] = {rl, rlo};
3034		/* remove new item from all common-modes */
3035		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
3036		CFRelease(set);
3037	    }
3038	} else {
3039	}
3040    } else {
3041	rlm = __CFRunLoopFindMode(rl, modeName, false);
3042	if (NULL != rlm && NULL != rlm->_observers) {
3043	    CFRetain(rlo);
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);
3048            }
3049	    CFRelease(rlo);
3050	}
3051        if (NULL != rlm) {
3052	    __CFRunLoopModeUnlock(rlm);
3053	}
3054    }
3055    __CFRunLoopUnlock(rl);
3056}
3057
3058Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
3059    CHECK_FOR_FORK();
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);
3066	}
3067    } else {
3068	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
3069	if (NULL != rlm) {
3070            if (NULL != rlm->_timers) {
3071                CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), rlt);
3072                hasValue = (kCFNotFound != idx);
3073            }
3074	    __CFRunLoopModeUnlock(rlm);
3075	}
3076    }
3077    __CFRunLoopUnlock(rl);
3078    return hasValue;
3079}
3080
3081void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
3082    CHECK_FOR_FORK();
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);
3090	}
3091	CFSetAddValue(rl->_commonModeItems, rlt);
3092	if (NULL != set) {
3093	    CFTypeRef context[2] = {rl, rlt};
3094	    /* add new item to all common-modes */
3095	    CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
3096	    CFRelease(set);
3097	}
3098    } else {
3099	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
3100	if (NULL != rlm) {
3101            if (NULL == rlm->_timers) {
3102                CFArrayCallBacks cb = kCFTypeArrayCallBacks;
3103                cb.equal = NULL;
3104                rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
3105            }
3106	}
3107	if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
3108            __CFRunLoopTimerLock(rlt);
3109            if (NULL == rlt->_runLoop) {
3110		rlt->_runLoop = rl;
3111  	    } else if (rl != rlt->_runLoop) {
3112                __CFRunLoopTimerUnlock(rlt);
3113	        __CFRunLoopModeUnlock(rlm);
3114                __CFRunLoopUnlock(rl);
3115		return;
3116	    }
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);
3126            }
3127	}
3128        if (NULL != rlm) {
3129	    __CFRunLoopModeUnlock(rlm);
3130	}
3131    }
3132    __CFRunLoopUnlock(rl);
3133}
3134
3135void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
3136    CHECK_FOR_FORK();
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);
3142	    if (NULL != set) {
3143		CFTypeRef context[2] = {rl, rlt};
3144		/* remove new item from all common-modes */
3145		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
3146		CFRelease(set);
3147	    }
3148	} else {
3149	}
3150    } else {
3151	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
3152        CFIndex idx = kCFNotFound;
3153        CFMutableArrayRef timerList = NULL;
3154        if (NULL != rlm) {
3155            timerList = rlm->_timers;
3156            if (NULL != timerList) {
3157                idx = CFArrayGetFirstIndexOfValue(timerList, CFRangeMake(0, CFArrayGetCount(timerList)), rlt);
3158            }
3159        }
3160        if (kCFNotFound != idx) {
3161            __CFRunLoopTimerLock(rlt);
3162            CFSetRemoveValue(rlt->_rlModes, rlm->_name);
3163            if (0 == CFSetGetCount(rlt->_rlModes)) {
3164                rlt->_runLoop = NULL;
3165            }
3166            __CFRunLoopTimerUnlock(rlt);
3167	    CFArrayRemoveValueAtIndex(timerList, idx);
3168            __CFArmNextTimerInMode(rlm, rl);
3169        }
3170        if (NULL != rlm) {
3171	    __CFRunLoopModeUnlock(rlm);
3172	}
3173    }
3174    __CFRunLoopUnlock(rl);
3175}
3176
3177/* CFRunLoopSource */
3178
3179static 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);
3193}
3194
3195static 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;
3200}
3201
3202static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) {	/* DOES CALLOUT */
3203    CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
3204    CFStringRef result;
3205    CFStringRef contextDesc = NULL;
3206    if (NULL != rls->_context.version0.copyDescription) {
3207	contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info);
3208    }
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
3214	Dl_info info;
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);
3217#endif
3218    }
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);
3221#else
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);
3223#endif
3224    CFRelease(contextDesc);
3225    return result;
3226}
3227
3228static 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);
3233    }
3234    pthread_mutex_destroy(&rls->_lock);
3235    memset((char *)cf + sizeof(CFRuntimeBase), 0, sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase));
3236}
3237
3238static const CFRuntimeClass __CFRunLoopSourceClass = {
3239    _kCFRuntimeScannedObject,
3240    "CFRunLoopSource",
3241    NULL,      // init
3242    NULL,      // copy
3243    __CFRunLoopSourceDeallocate,
3244    __CFRunLoopSourceEqual,
3245    __CFRunLoopSourceHash,
3246    NULL,      //
3247    __CFRunLoopSourceCopyDescription
3248};
3249
3250CF_PRIVATE void __CFRunLoopSourceInitialize(void) {
3251    __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass);
3252}
3253
3254CFTypeID CFRunLoopSourceGetTypeID(void) {
3255    return __kCFRunLoopSourceTypeID;
3256}
3257
3258CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
3259    CHECK_FOR_FORK();
3260    CFRunLoopSourceRef memory;
3261    uint32_t size;
3262    if (NULL == context) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
3263
3264    size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
3265    memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL);
3266    if (NULL == memory) {
3267	return NULL;
3268    }
3269    __CFSetValid(memory);
3270    __CFRunLoopSourceUnsetSignaled(memory);
3271    __CFRunLoopLockInit(&memory->_lock);
3272    memory->_bits = 0;
3273    memory->_order = order;
3274    memory->_runLoops = NULL;
3275    size = 0;
3276    switch (context->version) {
3277    case 0:
3278	size = sizeof(CFRunLoopSourceContext);
3279	break;
3280    case 1:
3281	size = sizeof(CFRunLoopSourceContext1);
3282	break;
3283    }
3284    objc_memmove_collectable(&memory->_context, context, size);
3285    if (context->retain) {
3286	memory->_context.version0.info = (void *)context->retain(context->info);
3287    }
3288    return memory;
3289}
3290
3291CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
3292    CHECK_FOR_FORK();
3293    __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3294    return rls->_order;
3295}
3296
3297static void __CFRunLoopSourceWakeUpLoop(const void *value, void *context) {
3298    CFRunLoopWakeUp((CFRunLoopRef)value);
3299}
3300
3301static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
3302    CFRunLoopRef rl = (CFRunLoopRef)value;
3303    CFTypeRef *params = (CFTypeRef *)context;
3304    CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
3305    CFIndex idx;
3306    if (rl == params[1]) return;
3307
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);
3316    }
3317    CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
3318    __CFRunLoopUnlock(rl);
3319    CFRelease(array);
3320    params[1] = rl;
3321}
3322
3323void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
3324    CHECK_FOR_FORK();
3325    __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3326    __CFRunLoopSourceLock(rls);
3327    CFRetain(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
3336            // invalidation.
3337            rls->_runLoops = NULL; // transfer ownership to local stack
3338            __CFRunLoopSourceUnlock(rls);
3339            CFTypeRef params[2] = {rls, NULL};
3340            CFBagApplyFunction(rloops, (__CFRunLoopSourceRemoveFromRunLoop), params);
3341            CFRelease(rloops);
3342            __CFRunLoopSourceLock(rls);
3343        }
3344        /* for hashing- and equality-use purposes, can't actually release the context here */
3345    }
3346    __CFRunLoopSourceUnlock(rls);
3347    CFRelease(rls);
3348}
3349
3350Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
3351    CHECK_FOR_FORK();
3352    __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3353    return __CFIsValid(rls);
3354}
3355
3356void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
3357    CHECK_FOR_FORK();
3358    __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3359    CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__);
3360    CFIndex size = 0;
3361    switch (context->version) {
3362    case 0:
3363	size = sizeof(CFRunLoopSourceContext);
3364	break;
3365    case 1:
3366	size = sizeof(CFRunLoopSourceContext1);
3367	break;
3368    }
3369    memmove(context, &rls->_context, size);
3370}
3371
3372void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
3373    CHECK_FOR_FORK();
3374    __CFRunLoopSourceLock(rls);
3375    if (__CFIsValid(rls)) {
3376	__CFRunLoopSourceSetSignaled(rls);
3377    }
3378    __CFRunLoopSourceUnlock(rls);
3379}
3380
3381Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) {
3382    CHECK_FOR_FORK();
3383    __CFRunLoopSourceLock(rls);
3384    Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false;
3385    __CFRunLoopSourceUnlock(rls);
3386    return ret;
3387}
3388
3389CF_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);
3394    }
3395    __CFRunLoopSourceUnlock(rls);
3396    if (loops) {
3397	CFBagApplyFunction(loops, __CFRunLoopSourceWakeUpLoop, NULL);
3398        CFRelease(loops);
3399    }
3400}
3401
3402/* CFRunLoopObserver */
3403
3404static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) {	/* DOES CALLOUT */
3405    CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
3406    CFStringRef result;
3407    CFStringRef contextDesc = NULL;
3408    if (NULL != rlo->_context.copyDescription) {
3409	contextDesc = rlo->_context.copyDescription(rlo->_context.info);
3410    }
3411    if (!contextDesc) {
3412	contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
3413    }
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;
3418    Dl_info info;
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);
3421#endif
3422    CFRelease(contextDesc);
3423    return result;
3424}
3425
3426static void __CFRunLoopObserverDeallocate(CFTypeRef cf) {	/* DOES CALLOUT */
3427    CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
3428    CFRunLoopObserverInvalidate(rlo);
3429    pthread_mutex_destroy(&rlo->_lock);
3430}
3431
3432static const CFRuntimeClass __CFRunLoopObserverClass = {
3433    0,
3434    "CFRunLoopObserver",
3435    NULL,      // init
3436    NULL,      // copy
3437    __CFRunLoopObserverDeallocate,
3438    NULL,
3439    NULL,
3440    NULL,      //
3441    __CFRunLoopObserverCopyDescription
3442};
3443
3444CF_PRIVATE void __CFRunLoopObserverInitialize(void) {
3445    __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass);
3446}
3447
3448CFTypeID CFRunLoopObserverGetTypeID(void) {
3449    return __kCFRunLoopObserverTypeID;
3450}
3451
3452CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
3453    CHECK_FOR_FORK();
3454    CFRunLoopObserverRef memory;
3455    UInt32 size;
3456    size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
3457    memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL);
3458    if (NULL == memory) {
3459	return NULL;
3460    }
3461    __CFSetValid(memory);
3462    __CFRunLoopObserverUnsetFiring(memory);
3463    if (repeats) {
3464	__CFRunLoopObserverSetRepeats(memory);
3465    } else {
3466	__CFRunLoopObserverUnsetRepeats(memory);
3467    }
3468    __CFRunLoopLockInit(&memory->_lock);
3469    memory->_runLoop = NULL;
3470    memory->_rlCount = 0;
3471    memory->_activities = activities;
3472    memory->_order = order;
3473    memory->_callout = callout;
3474    if (context) {
3475	if (context->retain) {
3476	    memory->_context.info = (void *)context->retain(context->info);
3477	} else {
3478	    memory->_context.info = context->info;
3479	}
3480	memory->_context.retain = context->retain;
3481	memory->_context.release = context->release;
3482	memory->_context.copyDescription = context->copyDescription;
3483    } else {
3484	memory->_context.info = 0;
3485	memory->_context.retain = 0;
3486	memory->_context.release = 0;
3487	memory->_context.copyDescription = 0;
3488    }
3489    return memory;
3490}
3491
3492static 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);
3496}
3497
3498CFRunLoopObserverRef 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);
3507}
3508
3509CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
3510    CHECK_FOR_FORK();
3511    __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3512    return rlo->_activities;
3513}
3514
3515CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
3516    CHECK_FOR_FORK();
3517    __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3518    return rlo->_order;
3519}
3520
3521Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
3522    CHECK_FOR_FORK();
3523    __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3524    return __CFRunLoopObserverRepeats(rlo);
3525}
3526
3527void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) {    /* DOES CALLOUT */
3528    CHECK_FOR_FORK();
3529    __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3530    __CFRunLoopObserverLock(rlo);
3531    CFRetain(rlo);
3532    if (__CFIsValid(rlo)) {
3533        CFRunLoopRef rl = rlo->_runLoop;
3534        void *info = rlo->_context.info;
3535        rlo->_context.info = NULL;
3536        __CFUnsetValid(rlo);
3537        if (NULL != rl) {
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
3541            // invalidation.
3542            CFRetain(rl);
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);
3552            }
3553            CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
3554            __CFRunLoopUnlock(rl);
3555            CFRelease(array);
3556            CFRelease(rl);
3557            __CFRunLoopObserverLock(rlo);
3558        }
3559        if (NULL != rlo->_context.release) {
3560            rlo->_context.release(info);        /* CALLOUT */
3561        }
3562    }
3563    __CFRunLoopObserverUnlock(rlo);
3564    CFRelease(rlo);
3565}
3566
3567Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
3568    CHECK_FOR_FORK();
3569    return __CFIsValid(rlo);
3570}
3571
3572void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
3573    CHECK_FOR_FORK();
3574    __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3575    CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
3576    *context = rlo->_context;
3577}
3578
3579#pragma mark -
3580#pragma mark CFRunLoopTimer
3581
3582static 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);
3587    }
3588    if (NULL == contextDesc) {
3589	contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
3590    }
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 = %@}"),
3599              cf,
3600              CFGetAllocator(rlt),
3601              __CFIsValid(rlt) ? "Yes" : "No",
3602              __CFRunLoopTimerIsFiring(rlt) ? "Yes" : "No",
3603              rlt->_interval,
3604              rlt->_tolerance,
3605              rlt->_nextFireDate,
3606              rlt->_nextFireDate - CFAbsoluteTimeGetCurrent(),
3607              rlt->_fireTSR,
3608              functionName,
3609              addr,
3610              functionPtr,
3611              libraryName,
3612              contextDesc);
3613    CFRelease(contextDesc);
3614    return result;
3615}
3616
3617static 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);
3625}
3626
3627static const CFRuntimeClass __CFRunLoopTimerClass = {
3628    0,
3629    "CFRunLoopTimer",
3630    NULL,      // init
3631    NULL,      // copy
3632    __CFRunLoopTimerDeallocate,
3633    NULL,	// equal
3634    NULL,
3635    NULL,      //
3636    __CFRunLoopTimerCopyDescription
3637};
3638
3639CF_PRIVATE void __CFRunLoopTimerInitialize(void) {
3640    __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass);
3641}
3642
3643CFTypeID CFRunLoopTimerGetTypeID(void) {
3644    return __kCFRunLoopTimerTypeID;
3645}
3646
3647CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
3648    CHECK_FOR_FORK();
3649    CFRunLoopTimerRef memory;
3650    UInt32 size;
3651    size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
3652    memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL);
3653    if (NULL == memory) {
3654	return NULL;
3655    }
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);
3674    } else {
3675	memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
3676    }
3677    memory->_callout = callout;
3678    if (NULL != context) {
3679	if (context->retain) {
3680	    memory->_context.info = (void *)context->retain(context->info);
3681	} else {
3682	    memory->_context.info = context->info;
3683	}
3684	memory->_context.retain = context->retain;
3685	memory->_context.release = context->release;
3686	memory->_context.copyDescription = context->copyDescription;
3687    } else {
3688	memory->_context.info = 0;
3689	memory->_context.retain = 0;
3690	memory->_context.release = 0;
3691	memory->_context.copyDescription = 0;
3692    }
3693    return memory;
3694}
3695
3696static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer, void *opaqueBlock) {
3697    typedef void (^timer_block_t) (CFRunLoopTimerRef timer);
3698    timer_block_t block = (timer_block_t)opaqueBlock;
3699    block(timer);
3700}
3701
3702CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order,
3703						void (^block) (CFRunLoopTimerRef timer)) {
3704
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);
3712}
3713
3714CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
3715    CHECK_FOR_FORK();
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;
3723    }
3724    __CFRunLoopTimerFireTSRUnlock();
3725    __CFRunLoopTimerUnlock(rlt);
3726    return at;
3727}
3728
3729void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
3730    CHECK_FOR_FORK();
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) {
3737	nextFireTSR = now2;
3738    } else if (TIMER_INTERVAL_LIMIT < fireDate - now1) {
3739	nextFireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
3740    } else {
3741	nextFireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
3742    }
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]);
3754        }
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);
3761	    CFRelease(name);
3762        }
3763        __CFRunLoopTimerFireTSRLock();
3764	rlt->_fireTSR = nextFireTSR;
3765        rlt->_nextFireDate = fireDate;
3766        for (CFIndex idx = 0; idx < cnt; idx++) {
3767	    CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx];
3768            if (rlm) {
3769                __CFRepositionTimerInMode(rlm, rlt, true);
3770            }
3771        }
3772        __CFRunLoopTimerFireTSRUnlock();
3773        for (CFIndex idx = 0; idx < cnt; idx++) {
3774            __CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]);
3775        }
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);
3783        CFRelease(rl);
3784     } else {
3785        __CFRunLoopTimerFireTSRLock();
3786	rlt->_fireTSR = nextFireTSR;
3787        rlt->_nextFireDate = fireDate;
3788        __CFRunLoopTimerFireTSRUnlock();
3789         __CFRunLoopTimerUnlock(rlt);
3790     }
3791}
3792
3793CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
3794    CHECK_FOR_FORK();
3795    CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID, CFTimeInterval, (NSTimer *)rlt, timeInterval);
3796    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3797    return rlt->_interval;
3798}
3799
3800Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
3801    CHECK_FOR_FORK();
3802    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3803    return (0.0 < rlt->_interval);
3804}
3805
3806CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
3807    CHECK_FOR_FORK();
3808    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3809    return rlt->_order;
3810}
3811
3812void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) {	/* DOES CALLOUT */
3813    CHECK_FOR_FORK();
3814    CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID, void, (NSTimer *)rlt, invalidate);
3815    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3816    __CFRunLoopTimerLock(rlt);
3817    if (!__CFRunLoopTimerIsDeallocating(rlt)) {
3818        CFRetain(rlt);
3819    }
3820    if (__CFIsValid(rlt)) {
3821	CFRunLoopRef rl = rlt->_runLoop;
3822	void *info = rlt->_context.info;
3823	rlt->_context.info = NULL;
3824	__CFUnsetValid(rlt);
3825	if (NULL != rl) {
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]);
3835            }
3836            CFRetain(rl);
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]);
3844	    }
3845	    CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
3846            __CFRunLoopUnlock(rl);
3847            for (CFIndex idx = 0; idx < cnt; idx++) {
3848                CFRelease(modes[idx]);
3849            }
3850            CFRelease(rl);
3851            __CFRunLoopTimerLock(rlt);
3852	}
3853	if (NULL != rlt->_context.release) {
3854	    rlt->_context.release(info);	/* CALLOUT */
3855	}
3856    }
3857    __CFRunLoopTimerUnlock(rlt);
3858    if (!__CFRunLoopTimerIsDeallocating(rlt)) {
3859        CFRelease(rlt);
3860    }
3861}
3862
3863Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
3864    CHECK_FOR_FORK();
3865    CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID, Boolean, (NSTimer *)rlt, isValid);
3866    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3867    return __CFIsValid(rlt);
3868}
3869
3870void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
3871    CHECK_FOR_FORK();
3872    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3873    CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
3874    *context = rlt->_context;
3875}
3876
3877CFTimeInterval CFRunLoopTimerGetTolerance(CFRunLoopTimerRef rlt) {
3878#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3879    CHECK_FOR_FORK();
3880    CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID, CFTimeInterval, (NSTimer *)rlt, tolerance);
3881    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3882    return rlt->_tolerance;
3883#else
3884    return 0.0;
3885#endif
3886}
3887
3888void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef rlt, CFTimeInterval tolerance) {
3889#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3890    CHECK_FOR_FORK();
3891    CF_OBJC_FUNCDISPATCHV(__kCFRunLoopTimerTypeID, void, (NSTimer *)rlt, setTolerance:tolerance);
3892    __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3893    /*
3894     * dispatch rules:
3895     *
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).
3899     */
3900    if (rlt->_interval > 0) {
3901        rlt->_tolerance = MIN(tolerance, rlt->_interval / 2);
3902    } else {
3903        // Tolerance must be a positive value or zero
3904        if (tolerance < 0) tolerance = 0.0;
3905        rlt->_tolerance = tolerance;
3906    }
3907#endif
3908}
3909
3910