]> git.saurik.com Git - apple/cf.git/blob - CFRunLoop.c
CF-476.13.tar.gz
[apple/cf.git] / CFRunLoop.c
1 /*
2 * Copyright (c) 2008 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 /* CFRunLoop.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__WIN32__)
29
30 #include <CoreFoundation/CFRunLoop.h>
31 #include <CoreFoundation/CFSet.h>
32 #include <CoreFoundation/CFBag.h>
33 #include "CFInternal.h"
34 #include <math.h>
35 #include <stdio.h>
36 #include <limits.h>
37 #if DEPLOYMENT_TARGET_MACOSX
38 #include <mach/mach.h>
39 #include <mach/clock_types.h>
40 #include <mach/clock.h>
41 #include <unistd.h>
42 #include <dlfcn.h>
43 #else
44 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
45 // With the MS headers, turning off Standard-C gets you macros for stat vs _stat.
46 // Strictly speaking, this is supposed to control traditional vs ANSI C features.
47 #undef __STDC__
48 #endif
49 #include <windows.h>
50 #include <pthread.h>
51 #include <process.h>
52 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
53 #define __STDC__
54 #endif
55 #endif
56
57 static int _LogCFRunLoop = 0;
58
59 #if 0 || 0
60 static pthread_t kNilPthreadT = { nil, nil };
61 #define pthreadPointer(a) a.p
62 #define lockCount(a) a.LockCount
63 #else
64 static pthread_t kNilPthreadT = (pthread_t)0;
65 #define pthreadPointer(a) a
66 #define lockCount(a) a
67 #endif
68
69
70 #if DEPLOYMENT_TARGET_MACOSX
71 #include <sys/types.h>
72 #include <sys/event.h>
73
74 typedef struct {
75 CFIndex version;
76 void * info;
77 const void *(*retain)(const void *info);
78 void (*release)(const void *info);
79 CFStringRef (*copyDescription)(const void *info);
80 Boolean (*equal)(const void *info1, const void *info2);
81 CFHashCode (*hash)(const void *info);
82 void (*perform)(const struct kevent *kev, void *info);
83 struct kevent event;
84 } CFRunLoopSourceContext2;
85
86 // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR.
87 // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop.
88 // There is no way to EV_ENABLE or EV_DISABLE a kevent.
89 // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet.
90 // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet.
91 // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos).
92 #endif
93
94 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey);
95
96 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
97 // simple abstraction layer spanning Mach ports and Windows HANDLES
98 #if DEPLOYMENT_TARGET_MACOSX
99
100 typedef mach_port_t __CFPort;
101 #define CFPORT_NULL MACH_PORT_NULL
102 typedef mach_port_t __CFPortSet;
103
104 static __CFPort __CFPortAllocate(void) {
105 __CFPort result;
106 kern_return_t ret;
107 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result);
108 if (KERN_SUCCESS == ret) {
109 ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND);
110 }
111 if (KERN_SUCCESS == ret) {
112 mach_port_limits_t limits;
113 limits.mpl_qlimit = 1;
114 ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT);
115 }
116 return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
117 }
118
119 CF_INLINE void __CFPortFree(__CFPort port) {
120 mach_port_destroy(mach_task_self(), port);
121 }
122
123 CF_INLINE __CFPortSet __CFPortSetAllocate(void) {
124 __CFPortSet result;
125 kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result);
126 return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
127 }
128
129 CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
130 kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet);
131 return (KERN_SUCCESS == ret);
132 }
133
134 CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
135 kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet);
136 return (KERN_SUCCESS == ret);
137 }
138
139 CF_INLINE void __CFPortSetFree(__CFPortSet portSet) {
140 kern_return_t ret;
141 mach_port_name_array_t array;
142 mach_msg_type_number_t idx, number;
143
144 ret = mach_port_get_set_status(mach_task_self(), portSet, &array, &number);
145 if (KERN_SUCCESS == ret) {
146 for (idx = 0; idx < number; idx++) {
147 mach_port_extract_member(mach_task_self(), array[idx], portSet);
148 }
149 vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t));
150 }
151 mach_port_destroy(mach_task_self(), portSet);
152 }
153
154 #elif defined(__WIN32__)
155
156 typedef HANDLE __CFPort;
157 #define CFPORT_NULL NULL
158
159 // A simple dynamic array of HANDLEs, which grows to a high-water mark
160 typedef struct ___CFPortSet {
161 uint16_t used;
162 uint16_t size;
163 HANDLE *handles;
164 CFSpinLock_t lock; // insert and remove must be thread safe, like the Mach calls
165 } *__CFPortSet;
166
167 CF_INLINE __CFPort __CFPortAllocate(void) {
168 return CreateEvent(NULL, true, false, NULL);
169 }
170
171 CF_INLINE void __CFPortFree(__CFPort port) {
172 CloseHandle(port);
173 }
174
175 static __CFPortSet __CFPortSetAllocate(void) {
176 __CFPortSet result = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0);
177 result->used = 0;
178 result->size = 4;
179 result->handles = CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0);
180 CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock);
181 return result;
182 }
183
184 static void __CFPortSetFree(__CFPortSet portSet) {
185 CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles);
186 CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet);
187 }
188
189 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
190 static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uint32_t bufSize, uint32_t *portsUsed) {
191 __CFSpinLock(&(portSet->lock));
192 __CFPort *result = portBuf;
193 if (bufSize > portSet->used)
194 result = CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0);
195 memmove(result, portSet->handles, portSet->used * sizeof(HANDLE));
196 *portsUsed = portSet->used;
197 __CFSpinUnlock(&(portSet->lock));
198 return result;
199 }
200
201 static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
202 __CFSpinLock(&(portSet->lock));
203 if (portSet->used >= portSet->size) {
204 portSet->size += 4;
205 portSet->handles = CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0);
206 }
207 if (portSet->used >= MAXIMUM_WAIT_OBJECTS)
208 CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS);
209 portSet->handles[portSet->used++] = port;
210 __CFSpinUnlock(&(portSet->lock));
211 return true;
212 }
213
214 static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
215 int i, j;
216 __CFSpinLock(&(portSet->lock));
217 for (i = 0; i < portSet->used; i++) {
218 if (portSet->handles[i] == port) {
219 for (j = i+1; j < portSet->used; j++) {
220 portSet->handles[j-1] = portSet->handles[j];
221 }
222 portSet->used--;
223 __CFSpinUnlock(&(portSet->lock));
224 return true;
225 }
226 }
227 __CFSpinUnlock(&(portSet->lock));
228 return false;
229 }
230
231 #endif
232
233 #if DEPLOYMENT_TARGET_MACOSX
234 extern mach_port_name_t mk_timer_create(void);
235 extern kern_return_t mk_timer_destroy(mach_port_name_t name);
236 extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time);
237 extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time);
238
239 CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(int64_t x) {
240 AbsoluteTime a;
241 a.hi = x >> 32;
242 a.lo = x & (int64_t)0xFFFFFFFF;
243 return a;
244 }
245
246 static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) {
247 kern_return_t result;
248 mach_msg_header_t header;
249 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
250 header.msgh_size = sizeof(mach_msg_header_t);
251 header.msgh_remote_port = port;
252 header.msgh_local_port = MACH_PORT_NULL;
253 header.msgh_id = msg_id;
254 result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
255 if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header);
256 return result;
257 }
258 #endif
259
260 /* unlock a run loop and modes before doing callouts/sleeping */
261 /* never try to take the run loop lock with a mode locked */
262 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
263 /* run loop mode structures should never be deallocated, even if they become empty */
264
265 static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID;
266 static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID;
267 static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID;
268 static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID;
269 static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID;
270
271 typedef struct __CFRunLoopMode *CFRunLoopModeRef;
272
273 struct __CFRunLoopMode {
274 CFRuntimeBase _base;
275 CFSpinLock_t _lock; /* must have the run loop locked before locking this */
276 CFStringRef _name;
277 Boolean _stopped;
278 char _padding[3];
279 CFMutableSetRef _sources;
280 CFMutableSetRef _observers;
281 CFMutableSetRef _timers;
282 CFMutableArrayRef _submodes; // names of the submodes
283 __CFPortSet _portSet;
284 #if DEPLOYMENT_TARGET_MACOSX
285 int _kq;
286 #endif
287 };
288
289 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm);
290
291 CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
292 __CFSpinLock(&(rlm->_lock));
293 }
294
295 CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
296 __CFSpinUnlock(&(rlm->_lock));
297 }
298
299 static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
300 CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
301 CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
302 return CFEqual(rlm1->_name, rlm2->_name);
303 }
304
305 static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
306 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
307 return CFHash(rlm->_name);
308 }
309
310 static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) {
311 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
312 CFMutableStringRef result;
313 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
314 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false");
315 CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet);
316 CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers);
317 return result;
318 }
319
320 static void __CFRunLoopModeDeallocate(CFTypeRef cf) {
321 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
322 if (NULL != rlm->_sources) CFRelease(rlm->_sources);
323 if (NULL != rlm->_observers) CFRelease(rlm->_observers);
324 if (NULL != rlm->_timers) CFRelease(rlm->_timers);
325 if (NULL != rlm->_submodes) CFRelease(rlm->_submodes);
326 CFRelease(rlm->_name);
327 __CFPortSetFree(rlm->_portSet);
328 #if DEPLOYMENT_TARGET_MACOSX
329 if (-1 != rlm->_kq) close(rlm->_kq);
330 #endif
331 }
332
333 struct __CFRunLoop {
334 CFRuntimeBase _base;
335 CFSpinLock_t _lock; /* locked for accessing mode list */
336 __CFPort _wakeUpPort; // used for CFRunLoopWakeUp
337 volatile uint32_t *_stopped;
338 CFMutableSetRef _commonModes;
339 CFMutableSetRef _commonModeItems;
340 CFRunLoopModeRef _currentMode;
341 CFMutableSetRef _modes;
342 void *_counterpart;
343 };
344
345 /* Bit 0 of the base reserved bits is used for stopped state */
346 /* Bit 1 of the base reserved bits is used for sleeping state */
347 /* Bit 2 of the base reserved bits is used for deallocating state */
348
349 CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
350 return (rl->_stopped && rl->_stopped[2]) ? true : false;
351 }
352
353 CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
354 if (rl->_stopped) rl->_stopped[2] = 0x53544F50; // 'STOP'
355 }
356
357 CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
358 if (rl->_stopped) rl->_stopped[2] = 0x0;
359 }
360
361 CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
362 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1);
363 }
364
365 CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
366 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
367 }
368
369 CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
370 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
371 }
372
373 CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
374 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2);
375 }
376
377 CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
378 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
379 }
380
381 CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
382 __CFSpinLock(&(((CFRunLoopRef)rl)->_lock));
383 }
384
385 CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
386 __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock));
387 }
388
389 static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) {
390 CFRunLoopRef rl = (CFRunLoopRef)cf;
391 CFMutableStringRef result;
392 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
393 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), lockCount(rl->_lock) ? "true" : "false", rl->_wakeUpPort, (rl->_stopped && (rl->_stopped[2] == 0x53544F50)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)"));
394 CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
395 return result;
396 }
397
398 /* call with rl locked */
399 static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
400 CHECK_FOR_FORK();
401 CFRunLoopModeRef rlm;
402 struct __CFRunLoopMode srlm;
403 srlm._base._cfisa = __CFISAForTypeID(__kCFRunLoopModeTypeID);
404 srlm._base._cfinfo[CF_INFO_BITS] = 0;
405 _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID);
406 srlm._name = modeName;
407 rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
408 if (NULL != rlm) {
409 __CFRunLoopModeLock(rlm);
410 return rlm;
411 }
412 if (!create) {
413 return NULL;
414 }
415 rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(CFGetAllocator(rl), __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
416 if (NULL == rlm) {
417 return NULL;
418 }
419 CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock);
420 rlm->_name = CFStringCreateCopy(CFGetAllocator(rlm), modeName);
421 rlm->_stopped = false;
422 rlm->_sources = NULL;
423 rlm->_observers = NULL;
424 rlm->_timers = NULL;
425 rlm->_submodes = NULL;
426 rlm->_portSet = __CFPortSetAllocate();
427 if (CFPORT_NULL == rlm->_portSet) HALT;
428 if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT;
429 #if DEPLOYMENT_TARGET_MACOSX
430 rlm->_kq = -1;
431 #endif
432 CFSetAddValue(rl->_modes, rlm);
433 CFRelease(rlm);
434 __CFRunLoopModeLock(rlm); /* return mode locked */
435 return rlm;
436 }
437
438
439 // expects rl and rlm locked
440 static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
441 CHECK_FOR_FORK();
442 if (NULL == rlm) return true;
443 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false;
444 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false;
445 if (NULL != rlm->_submodes) {
446 CFIndex idx, cnt;
447 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
448 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
449 CFRunLoopModeRef subrlm;
450 Boolean subIsEmpty;
451 subrlm = __CFRunLoopFindMode(rl, modeName, false);
452 subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm) : true;
453 if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm);
454 if (!subIsEmpty) return false;
455 }
456 }
457 return true;
458 }
459
460 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
461
462 CF_INLINE Boolean __CFIsValid(const void *cf) {
463 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3);
464 }
465
466 CF_INLINE void __CFSetValid(void *cf) {
467 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
468 }
469
470 CF_INLINE void __CFUnsetValid(void *cf) {
471 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
472 }
473
474 struct __CFRunLoopSource {
475 CFRuntimeBase _base;
476 uint32_t _bits;
477 CFSpinLock_t _lock;
478 CFIndex _order; /* immutable */
479 CFMutableBagRef _runLoops;
480 union {
481 CFRunLoopSourceContext version0; /* immutable, except invalidation */
482 CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
483 } _context;
484 };
485
486 /* Bit 1 of the base reserved bits is used for signalled state */
487
488 CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
489 return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
490 }
491
492 CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
493 __CFBitfieldSetValue(rls->_bits, 1, 1, 1);
494 }
495
496 CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
497 __CFBitfieldSetValue(rls->_bits, 1, 1, 0);
498 }
499
500 CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) {
501 __CFSpinLock(&(rls->_lock));
502 }
503
504 CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
505 __CFSpinUnlock(&(rls->_lock));
506 }
507
508 /* rlm is not locked */
509 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
510 __CFRunLoopSourceLock(rls);
511 if (NULL == rls->_runLoops) {
512 rls->_runLoops = CFBagCreateMutable(CFGetAllocator(rls), 0, NULL);
513 }
514 CFBagAddValue(rls->_runLoops, rl);
515 __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety
516 if (0 == rls->_context.version0.version) {
517 if (NULL != rls->_context.version0.schedule) {
518 rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name);
519 }
520 } else if (1 == rls->_context.version0.version) {
521 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
522 if (CFPORT_NULL != port) {
523 __CFPortSetInsert(port, rlm->_portSet);
524 }
525 }
526 }
527
528 /* rlm is not locked */
529 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
530 if (0 == rls->_context.version0.version) {
531 if (NULL != rls->_context.version0.cancel) {
532 rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */
533 }
534 } else if (1 == rls->_context.version0.version) {
535 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
536 if (CFPORT_NULL != port) {
537 __CFPortSetRemove(port, rlm->_portSet);
538 }
539 }
540 __CFRunLoopSourceLock(rls);
541 if (NULL != rls->_runLoops) {
542 CFBagRemoveValue(rls->_runLoops, rl);
543 }
544 __CFRunLoopSourceUnlock(rls);
545 }
546
547 struct __CFRunLoopObserver {
548 CFRuntimeBase _base;
549 CFSpinLock_t _lock;
550 CFRunLoopRef _runLoop;
551 CFIndex _rlCount;
552 CFOptionFlags _activities; /* immutable */
553 CFIndex _order; /* immutable */
554 CFRunLoopObserverCallBack _callout; /* immutable */
555 CFRunLoopObserverContext _context; /* immutable, except invalidation */
556 };
557
558 /* Bit 0 of the base reserved bits is used for firing state */
559 /* Bit 1 of the base reserved bits is used for repeats state */
560
561 CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
562 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0);
563 }
564
565 CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
566 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
567 }
568
569 CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
570 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
571 }
572
573 CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
574 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1);
575 }
576
577 CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
578 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
579 }
580
581 CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
582 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
583 }
584
585 CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
586 __CFSpinLock(&(rlo->_lock));
587 }
588
589 CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
590 __CFSpinUnlock(&(rlo->_lock));
591 }
592
593 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
594 __CFRunLoopObserverLock(rlo);
595 if (0 == rlo->_rlCount) {
596 rlo->_runLoop = rl;
597 }
598 rlo->_rlCount++;
599 __CFRunLoopObserverUnlock(rlo);
600 }
601
602 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
603 __CFRunLoopObserverLock(rlo);
604 rlo->_rlCount--;
605 if (0 == rlo->_rlCount) {
606 rlo->_runLoop = NULL;
607 }
608 __CFRunLoopObserverUnlock(rlo);
609 }
610
611 struct __CFRunLoopTimer {
612 CFRuntimeBase _base;
613 CFSpinLock_t _lock;
614 CFRunLoopRef _runLoop;
615 CFIndex _rlCount;
616 #if DEPLOYMENT_TARGET_MACOSX
617 mach_port_name_t _port;
618 #endif
619 CFIndex _order; /* immutable */
620 int64_t _fireTSR; /* TSR units */
621 int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */
622 CFRunLoopTimerCallBack _callout; /* immutable */
623 CFRunLoopTimerContext _context; /* immutable, except invalidation */
624 };
625
626 /* Bit 0 of the base reserved bits is used for firing state */
627 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
628
629 CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
630 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0);
631 }
632
633 CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
634 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
635 }
636
637 CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
638 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
639 }
640
641 CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) {
642 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1);
643 }
644
645 CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) {
646 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
647 }
648
649 CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) {
650 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
651 }
652
653 CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
654 __CFSpinLock(&(rlt->_lock));
655 }
656
657 CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
658 __CFSpinUnlock(&(rlt->_lock));
659 }
660
661 static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit;
662
663 CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
664 __CFSpinLock(&__CFRLTFireTSRLock);
665 }
666
667 CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
668 __CFSpinUnlock(&__CFRLTFireTSRLock);
669 }
670
671 #if DEPLOYMENT_TARGET_MACOSX
672 static CFMutableDictionaryRef __CFRLTPortMap = NULL;
673 static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit;
674
675 CF_INLINE void __CFRunLoopTimerPortMapLock(void) {
676 __CFSpinLock(&__CFRLTPortMapLock);
677 }
678
679 CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) {
680 __CFSpinUnlock(&__CFRLTPortMapLock);
681 }
682 #endif
683
684 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
685 #if DEPLOYMENT_TARGET_MACOSX
686 __CFRunLoopTimerLock(rlt);
687 if (0 == rlt->_rlCount) {
688 rlt->_runLoop = rl;
689 if (MACH_PORT_NULL == rlt->_port) {
690 rlt->_port = mk_timer_create();
691 }
692 __CFRunLoopTimerPortMapLock();
693 if (NULL == __CFRLTPortMap) {
694 __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
695 }
696 CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt);
697 __CFRunLoopTimerPortMapUnlock();
698 }
699 rlt->_rlCount++;
700 mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet);
701 mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
702 __CFRunLoopTimerUnlock(rlt);
703 #endif
704 }
705
706 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
707 #if DEPLOYMENT_TARGET_MACOSX
708 __CFRunLoopTimerLock(rlt);
709 __CFPortSetRemove(rlt->_port, rlm->_portSet);
710 rlt->_rlCount--;
711 if (0 == rlt->_rlCount) {
712 __CFRunLoopTimerPortMapLock();
713 if (NULL != __CFRLTPortMap) {
714 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port);
715 }
716 __CFRunLoopTimerPortMapUnlock();
717 rlt->_runLoop = NULL;
718 mk_timer_cancel(rlt->_port, NULL);
719 }
720 __CFRunLoopTimerUnlock(rlt);
721 #endif
722 }
723
724 // Caller must hold the Timer lock for safety
725 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt, CFRunLoopRef rl) {
726 #if DEPLOYMENT_TARGET_MACOSX
727 mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
728 #endif
729 }
730
731 /* CFRunLoop */
732
733 CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
734 CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
735
736 struct _findsource {
737 __CFPort port;
738 CFRunLoopSourceRef result;
739 };
740
741 static void __CFRunLoopFindSource(const void *value, void *ctx) {
742 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
743 struct _findsource *context = (struct _findsource *)ctx;
744 __CFPort port;
745 if (NULL != context->result) return;
746 if (1 != rls->_context.version0.version) return;
747 __CFRunLoopSourceLock(rls);
748 port = rls->_context.version1.getPort(rls->_context.version1.info);
749 if (port == context->port) {
750 context->result = rls;
751 }
752 __CFRunLoopSourceUnlock(rls);
753 }
754
755 // call with rl and rlm locked
756 static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */
757 CHECK_FOR_FORK();
758 struct _findsource context = {port, NULL};
759 if (NULL != rlm->_sources) {
760 CFSetApplyFunction(rlm->_sources, (__CFRunLoopFindSource), &context);
761 }
762 if (NULL == context.result && NULL != rlm->_submodes) {
763 CFIndex idx, cnt;
764 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
765 CFRunLoopSourceRef source = NULL;
766 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
767 CFRunLoopModeRef subrlm;
768 subrlm = __CFRunLoopFindMode(rl, modeName, false);
769 if (NULL != subrlm) {
770 source = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port);
771 __CFRunLoopModeUnlock(subrlm);
772 }
773 if (NULL != source) {
774 context.result = source;
775 break;
776 }
777 }
778 }
779 return context.result;
780 }
781
782 #if DEPLOYMENT_TARGET_MACOSX
783 // call with rl and rlm locked
784 static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) {
785 CHECK_FOR_FORK();
786 CFRunLoopTimerRef result = NULL;
787 __CFRunLoopTimerPortMapLock();
788 if (NULL != __CFRLTPortMap) {
789 result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port);
790 }
791 __CFRunLoopTimerPortMapUnlock();
792 return result;
793 }
794 #endif
795
796 static void __CFRunLoopDeallocateSources(const void *value, void *context) {
797 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
798 CFRunLoopRef rl = (CFRunLoopRef)context;
799 CFIndex idx, cnt;
800 const void **list, *buffer[256];
801 if (NULL == rlm->_sources) return;
802 cnt = CFSetGetCount(rlm->_sources);
803 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
804 CFSetGetValues(rlm->_sources, list);
805 for (idx = 0; idx < cnt; idx++) {
806 CFRetain(list[idx]);
807 }
808 CFSetRemoveAllValues(rlm->_sources);
809 for (idx = 0; idx < cnt; idx++) {
810 __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm);
811 CFRelease(list[idx]);
812 }
813 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
814 }
815
816 static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
817 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
818 CFRunLoopRef rl = (CFRunLoopRef)context;
819 CFIndex idx, cnt;
820 const void **list, *buffer[256];
821 if (NULL == rlm->_observers) return;
822 cnt = CFSetGetCount(rlm->_observers);
823 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
824 CFSetGetValues(rlm->_observers, list);
825 for (idx = 0; idx < cnt; idx++) {
826 CFRetain(list[idx]);
827 }
828 CFSetRemoveAllValues(rlm->_observers);
829 for (idx = 0; idx < cnt; idx++) {
830 __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm);
831 CFRelease(list[idx]);
832 }
833 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
834 }
835
836 static void __CFRunLoopDeallocateTimers(const void *value, void *context) {
837 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
838 CFRunLoopRef rl = (CFRunLoopRef)context;
839 CFIndex idx, cnt;
840 const void **list, *buffer[256];
841 if (NULL == rlm->_timers) return;
842 cnt = CFSetGetCount(rlm->_timers);
843 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
844 CFSetGetValues(rlm->_timers, list);
845 for (idx = 0; idx < cnt; idx++) {
846 CFRetain(list[idx]);
847 }
848 CFSetRemoveAllValues(rlm->_timers);
849 for (idx = 0; idx < cnt; idx++) {
850 __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm);
851 CFRelease(list[idx]);
852 }
853 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
854 }
855
856 static void __CFRunLoopDeallocate(CFTypeRef cf) {
857 CFRunLoopRef rl = (CFRunLoopRef)cf;
858 /* We try to keep the run loop in a valid state as long as possible,
859 since sources may have non-retained references to the run loop.
860 Another reason is that we don't want to lock the run loop for
861 callback reasons, if we can get away without that. We start by
862 eliminating the sources, since they are the most likely to call
863 back into the run loop during their "cancellation". Common mode
864 items will be removed from the mode indirectly by the following
865 three lines. */
866 __CFRunLoopSetDeallocating(rl);
867 if (NULL != rl->_modes) {
868 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
869 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
870 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
871 }
872 __CFRunLoopLock(rl);
873 if (NULL != rl->_commonModeItems) {
874 CFRelease(rl->_commonModeItems);
875 }
876 if (NULL != rl->_commonModes) {
877 CFRelease(rl->_commonModes);
878 }
879 if (NULL != rl->_modes) {
880 CFRelease(rl->_modes);
881 }
882 __CFPortFree(rl->_wakeUpPort);
883 rl->_wakeUpPort = CFPORT_NULL;
884 __CFRunLoopUnlock(rl);
885 }
886
887 static const CFRuntimeClass __CFRunLoopModeClass = {
888 0,
889 "CFRunLoopMode",
890 NULL, // init
891 NULL, // copy
892 __CFRunLoopModeDeallocate,
893 __CFRunLoopModeEqual,
894 __CFRunLoopModeHash,
895 NULL, //
896 __CFRunLoopModeCopyDescription
897 };
898
899 static const CFRuntimeClass __CFRunLoopClass = {
900 0,
901 "CFRunLoop",
902 NULL, // init
903 NULL, // copy
904 __CFRunLoopDeallocate,
905 NULL,
906 NULL,
907 NULL, //
908 __CFRunLoopCopyDescription
909 };
910
911 __private_extern__ void __CFRunLoopInitialize(void) {
912 __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);
913 __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass);
914 }
915
916 CFTypeID CFRunLoopGetTypeID(void) {
917 return __kCFRunLoopTypeID;
918 }
919
920 static CFRunLoopRef __CFRunLoopCreate(void) {
921 CFRunLoopRef loop = NULL;
922 CFRunLoopModeRef rlm;
923 uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
924 loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL);
925 if (NULL == loop) {
926 return NULL;
927 }
928 loop->_stopped = NULL;
929 CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock);
930 loop->_wakeUpPort = __CFPortAllocate();
931 if (CFPORT_NULL == loop->_wakeUpPort) HALT;
932 loop->_commonModes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
933 CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
934 loop->_commonModeItems = NULL;
935 loop->_currentMode = NULL;
936 loop->_modes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
937 _CFSetSetCapacity(loop->_modes, 10);
938 loop->_counterpart = NULL;
939 rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
940 if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
941 return loop;
942 }
943
944 static CFMutableDictionaryRef runLoops = NULL;
945 static char setMainLoop = 0;
946 static CFSpinLock_t loopsLock = CFSpinLockInit;
947
948 // If this is called on a non-main thread, and the main thread pthread_t is passed in,
949 // and this has not yet beed called on the main thread (since the last fork(), this will
950 // produce a different run loop that will probably be tossed away eventually, than the
951 // main thread run loop. There's nothing much we can do about that, without a call to
952 // fetch the main thread's pthread_t from the pthreads subsystem.
953
954 // t==0 is a synonym for "main thread" that always works
955 __private_extern__ CFRunLoopRef _CFRunLoop0(pthread_t t) {
956 CFRunLoopRef loop = NULL;
957 __CFSpinLock(&loopsLock);
958 if (!runLoops) {
959 __CFSpinUnlock(&loopsLock);
960 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
961 CFRunLoopRef mainLoop = __CFRunLoopCreate();
962 CFDictionarySetValue(dict, 0, mainLoop);
963 if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&runLoops)) {
964 CFRelease(dict);
965 CFRelease(mainLoop);
966 }
967 __CFSpinLock(&loopsLock);
968 }
969 if (pthread_main_np() && pthread_equal(t, pthread_self())) {
970 t = kNilPthreadT;
971 }
972 loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
973 if (!loop) {
974 __CFSpinUnlock(&loopsLock);
975 CFRunLoopRef newLoop = __CFRunLoopCreate();
976 __CFGetThreadSpecificData(); // just cause the thread finalizer to be called as a side effect
977 __CFSpinLock(&loopsLock);
978 loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
979 if (loop) {
980 CFRelease(newLoop);
981 } else {
982 CFDictionarySetValue(runLoops, pthreadPointer(t), newLoop);
983 loop = newLoop;
984 }
985 }
986 if (!setMainLoop && pthread_main_np()) {
987 if (pthread_equal(t, kNilPthreadT)) {
988 CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), loop);
989 } else {
990 CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
991 CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), mainLoop);
992 }
993 setMainLoop = 1;
994 }
995 __CFSpinUnlock(&loopsLock);
996 return loop;
997 }
998
999 __private_extern__ void _CFRunLoop1(void) {
1000 __CFSpinLock(&loopsLock);
1001 if (runLoops) {
1002 pthread_t t = pthread_self();
1003 CFRunLoopRef currentLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t));
1004 CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT));
1005 if (currentLoop && mainLoop != currentLoop) {
1006 CFDictionaryRemoveValue(runLoops, pthreadPointer(t));
1007 CFRelease(currentLoop);
1008 }
1009 }
1010 __CFSpinUnlock(&loopsLock);
1011 }
1012
1013 CFRunLoopRef CFRunLoopGetMain(void) {
1014 CHECK_FOR_FORK();
1015 return _CFRunLoop0(kNilPthreadT);
1016 }
1017
1018 CFRunLoopRef CFRunLoopGetCurrent(void) {
1019 CHECK_FOR_FORK();
1020 return _CFRunLoop0(pthread_self());
1021 }
1022
1023 void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
1024 __CFSpinLock(&loopsLock);
1025 CFRunLoopRef currentLoop = runLoops ? (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(pthread_self())) : NULL;
1026 if (rl != currentLoop) {
1027 // intentionally leak currentLoop so we don't kill any ports in the child
1028 // if (currentLoop) CFRelease(currentLoop);
1029 if (rl) {
1030 if (!runLoops) {
1031 runLoops = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
1032 CFRunLoopRef mainLoop = __CFRunLoopCreate();
1033 CFDictionarySetValue(runLoops, pthreadPointer(kNilPthreadT), mainLoop);
1034 }
1035 CFRetain(rl);
1036 CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), rl);
1037 } else {
1038 CFDictionaryRemoveValue(runLoops, pthreadPointer(pthread_self()));
1039 }
1040 }
1041 __CFSpinUnlock(&loopsLock);
1042 }
1043
1044 CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
1045 CHECK_FOR_FORK();
1046 CFStringRef result = NULL;
1047 __CFRunLoopLock(rl);
1048 if (NULL != rl->_currentMode) {
1049 result = CFRetain(rl->_currentMode->_name);
1050 }
1051 __CFRunLoopUnlock(rl);
1052 return result;
1053 }
1054
1055 static void __CFRunLoopGetModeName(const void *value, void *context) {
1056 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1057 CFMutableArrayRef array = (CFMutableArrayRef)context;
1058 CFArrayAppendValue(array, rlm->_name);
1059 }
1060
1061 CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) {
1062 CHECK_FOR_FORK();
1063 CFMutableArrayRef array;
1064 __CFRunLoopLock(rl);
1065 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks);
1066 CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array);
1067 __CFRunLoopUnlock(rl);
1068 return array;
1069 }
1070
1071 static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
1072 CFTypeRef item = (CFTypeRef)value;
1073 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1074 CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
1075 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1076 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
1077 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1078 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
1079 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1080 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
1081 }
1082 }
1083
1084 static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
1085 CFStringRef modeName = (CFStringRef)value;
1086 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1087 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
1088 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1089 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
1090 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1091 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
1092 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1093 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
1094 }
1095 }
1096
1097 static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
1098 CFStringRef modeName = (CFStringRef)value;
1099 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1100 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
1101 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1102 CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
1103 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1104 CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
1105 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1106 CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
1107 }
1108 }
1109
1110 Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) {
1111 __CFRunLoopLock(rl);
1112 Boolean present = CFSetContainsValue(rl->_commonModes, modeName);
1113 __CFRunLoopUnlock(rl);
1114 return present;
1115 }
1116
1117 void *_CFRunLoop02(CFRunLoopRef rl) {
1118 return rl->_counterpart;
1119 }
1120
1121 void _CFRunLoop03(CFRunLoopRef rl, void *ns) {
1122 rl->_counterpart = ns;
1123 }
1124
1125 void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
1126 CHECK_FOR_FORK();
1127 if (__CFRunLoopIsDeallocating(rl)) return;
1128 __CFRunLoopLock(rl);
1129 if (!CFSetContainsValue(rl->_commonModes, modeName)) {
1130 CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
1131 CFSetAddValue(rl->_commonModes, modeName);
1132 __CFRunLoopUnlock(rl);
1133 if (NULL != set) {
1134 CFTypeRef context[2] = {rl, modeName};
1135 /* add all common-modes items to new mode */
1136 CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
1137 CFRelease(set);
1138 }
1139 } else {
1140 __CFRunLoopUnlock(rl);
1141 }
1142 }
1143
1144 static CFComparisonResult __CFRunLoopObserverQSortComparator(const void *val1, const void *val2, void *context) {
1145 CFRunLoopObserverRef o1 = *((CFRunLoopObserverRef *)val1);
1146 CFRunLoopObserverRef o2 = *((CFRunLoopObserverRef *)val2);
1147 if (!o1) {
1148 return (!o2) ? kCFCompareEqualTo : kCFCompareLessThan;
1149 }
1150 if (!o2) {
1151 return kCFCompareGreaterThan;
1152 }
1153 if (o1->_order < o2->_order) return kCFCompareLessThan;
1154 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
1155 return kCFCompareEqualTo;
1156 }
1157
1158
1159 /* rl is unlocked, rlm is locked on entrance and exit */
1160 /* ALERT: this should collect all the candidate observers from the top level
1161 * and all submodes, recursively, THEN start calling them, in order to obey
1162 * the ordering parameter. */
1163 static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
1164 CHECK_FOR_FORK();
1165 CFIndex idx, cnt;
1166 CFArrayRef submodes;
1167
1168 /* Fire the observers */
1169 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
1170 if (NULL != rlm->_observers) {
1171 cnt = CFSetGetCount(rlm->_observers);
1172 if (0 < cnt) {
1173 CFRunLoopObserverRef buffer[(cnt <= 1024) ? cnt : 1];
1174 CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0);
1175 CFSetGetValues(rlm->_observers, (const void **)collectedObservers);
1176 for (idx = 0; idx < cnt; idx++) {
1177 CFRunLoopObserverRef rlo = collectedObservers[idx];
1178 if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
1179 CFRetain(rlo);
1180 } else {
1181 /* We're not interested in this one - set it to NULL so we don't process it later */
1182 collectedObservers[idx] = NULL;
1183 }
1184 }
1185 __CFRunLoopModeUnlock(rlm);
1186 CFQSortArray(collectedObservers, cnt, sizeof(CFRunLoopObserverRef), __CFRunLoopObserverQSortComparator, NULL);
1187 for (idx = 0; idx < cnt; idx++) {
1188 CFRunLoopObserverRef rlo = collectedObservers[idx];
1189 if (rlo) {
1190 __CFRunLoopObserverLock(rlo);
1191 if (__CFIsValid(rlo)) {
1192 __CFRunLoopObserverUnlock(rlo);
1193 __CFRunLoopObserverSetFiring(rlo);
1194 rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */
1195 __CFRunLoopObserverUnsetFiring(rlo);
1196 if (!__CFRunLoopObserverRepeats(rlo)) {
1197 CFRunLoopObserverInvalidate(rlo);
1198 }
1199 } else {
1200 __CFRunLoopObserverUnlock(rlo);
1201 }
1202 CFRelease(rlo);
1203 }
1204 }
1205 __CFRunLoopModeLock(rlm);
1206 if (collectedObservers != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, collectedObservers);
1207 }
1208 }
1209 if (NULL != submodes) {
1210 __CFRunLoopModeUnlock(rlm);
1211 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
1212 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
1213 CFRunLoopModeRef subrlm;
1214 __CFRunLoopLock(rl);
1215 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1216 __CFRunLoopUnlock(rl);
1217 if (NULL != subrlm) {
1218 __CFRunLoopDoObservers(rl, subrlm, activity);
1219 __CFRunLoopModeUnlock(subrlm);
1220 }
1221 }
1222 CFRelease(submodes);
1223 __CFRunLoopModeLock(rlm);
1224 }
1225 }
1226
1227 static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) {
1228 CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1;
1229 CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2;
1230 if (o1->_order < o2->_order) return kCFCompareLessThan;
1231 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
1232 return kCFCompareEqualTo;
1233 }
1234
1235 static void __CFRunLoopCollectSources0(const void *value, void *context) {
1236 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
1237 CFTypeRef *sources = (CFTypeRef *)context;
1238 if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) {
1239 if (NULL == *sources) {
1240 *sources = CFRetain(rls);
1241 } else if (CFGetTypeID(*sources) == __kCFRunLoopSourceTypeID) {
1242 CFTypeRef oldrls = *sources;
1243 *sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1244 CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls);
1245 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1246 CFRelease(oldrls);
1247 } else {
1248 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1249 }
1250 }
1251 }
1252
1253 /* rl is unlocked, rlm is locked on entrance and exit */
1254 static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */
1255 CHECK_FOR_FORK();
1256 CFTypeRef sources = NULL;
1257 Boolean sourceHandled = false;
1258 CFIndex idx, cnt;
1259
1260 __CFRunLoopModeUnlock(rlm); // locks have to be taken in order
1261 __CFRunLoopLock(rl);
1262 __CFRunLoopModeLock(rlm);
1263 /* Fire the version 0 sources */
1264 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) {
1265 CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources);
1266 }
1267 for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1268 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1269 CFRunLoopModeRef subrlm;
1270 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1271 if (NULL != subrlm) {
1272 if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) {
1273 CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources);
1274 }
1275 __CFRunLoopModeUnlock(subrlm);
1276 }
1277 }
1278 __CFRunLoopUnlock(rl);
1279 if (NULL != sources) {
1280 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1281 __CFRunLoopModeUnlock(rlm);
1282 if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) {
1283 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
1284 __CFRunLoopSourceLock(rls);
1285 __CFRunLoopSourceUnsetSignaled(rls);
1286 if (__CFIsValid(rls)) {
1287 __CFRunLoopSourceUnlock(rls);
1288 if (NULL != rls->_context.version0.perform) {
1289 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1290 CHECK_FOR_FORK();
1291 }
1292 sourceHandled = true;
1293 } else {
1294 __CFRunLoopSourceUnlock(rls);
1295 }
1296 } else {
1297 cnt = CFArrayGetCount(sources);
1298 CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
1299 for (idx = 0; idx < cnt; idx++) {
1300 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, idx);
1301 __CFRunLoopSourceLock(rls);
1302 __CFRunLoopSourceUnsetSignaled(rls);
1303 if (__CFIsValid(rls)) {
1304 __CFRunLoopSourceUnlock(rls);
1305 if (NULL != rls->_context.version0.perform) {
1306 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1307 CHECK_FOR_FORK();
1308 }
1309 sourceHandled = true;
1310 } else {
1311 __CFRunLoopSourceUnlock(rls);
1312 }
1313 if (stopAfterHandle && sourceHandled) {
1314 break;
1315 }
1316 }
1317 }
1318 CFRelease(sources);
1319 __CFRunLoopModeLock(rlm);
1320 }
1321 return sourceHandled;
1322 }
1323
1324 // msg, size and reply are unused on Windows
1325 static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls
1326 #if DEPLOYMENT_TARGET_MACOSX
1327 , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply
1328 #endif
1329 ) { /* DOES CALLOUT */
1330 CHECK_FOR_FORK();
1331 Boolean sourceHandled = false;
1332
1333 /* Fire a version 1 source */
1334 CFRetain(rls);
1335 __CFRunLoopModeUnlock(rlm);
1336 __CFRunLoopSourceLock(rls);
1337 if (__CFIsValid(rls)) {
1338 __CFRunLoopSourceUnsetSignaled(rls);
1339 __CFRunLoopSourceUnlock(rls);
1340 if (NULL != rls->_context.version1.perform) {
1341 #if DEPLOYMENT_TARGET_MACOSX
1342 *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */
1343 CHECK_FOR_FORK();
1344 #else
1345 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
1346 rls->_context.version1.perform(rls->_context.version1.info); /* CALLOUT */
1347 CHECK_FOR_FORK();
1348 #endif
1349 } else {
1350 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); }
1351 }
1352 sourceHandled = true;
1353 } else {
1354 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
1355 __CFRunLoopSourceUnlock(rls);
1356 }
1357 CFRelease(rls);
1358 __CFRunLoopModeLock(rlm);
1359 return sourceHandled;
1360 }
1361
1362 static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
1363 Boolean timerHandled = false;
1364 int64_t oldFireTSR = 0;
1365
1366 /* Fire a timer */
1367 CFRetain(rlt);
1368 __CFRunLoopModeUnlock(rlm);
1369 __CFRunLoopTimerLock(rlt);
1370 if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
1371 __CFRunLoopTimerUnsetDidFire(rlt);
1372 __CFRunLoopTimerSetFiring(rlt);
1373 __CFRunLoopTimerUnlock(rlt);
1374 __CFRunLoopTimerFireTSRLock();
1375 oldFireTSR = rlt->_fireTSR;
1376 __CFRunLoopTimerFireTSRUnlock();
1377 rlt->_callout(rlt, rlt->_context.info); /* CALLOUT */
1378 CHECK_FOR_FORK();
1379 __CFRunLoopTimerUnsetFiring(rlt);
1380 timerHandled = true;
1381 } else {
1382 // If the timer fires while it is firing in a higher activiation,
1383 // it is not allowed to fire, but we have to remember that fact.
1384 // Later, if the timer's fire date is being handled manually, we
1385 // need to re-arm the kernel timer, since it has possibly already
1386 // fired (this firing which is being skipped, say) and the timer
1387 // will permanently stop if we completely drop this firing.
1388 if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt);
1389 __CFRunLoopTimerUnlock(rlt);
1390 }
1391 if (__CFIsValid(rlt) && timerHandled) {
1392 if (0 == rlt->_intervalTSR) {
1393 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
1394 } else {
1395 /* This is just a little bit tricky: we want to support calling
1396 * CFRunLoopTimerSetNextFireDate() from within the callout and
1397 * honor that new time here if it is a later date, otherwise
1398 * it is completely ignored. */
1399 int64_t currentFireTSR;
1400 __CFRunLoopTimerFireTSRLock();
1401 currentFireTSR = rlt->_fireTSR;
1402 if (oldFireTSR < currentFireTSR) {
1403 /* Next fire TSR was set, and set to a date after the previous
1404 * fire date, so we honor it. */
1405 if (__CFRunLoopTimerDidFire(rlt)) {
1406 __CFRunLoopTimerRescheduleWithAllModes(rlt, rl);
1407 __CFRunLoopTimerUnsetDidFire(rlt);
1408 }
1409 } else {
1410 if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) {
1411 currentFireTSR = LLONG_MAX;
1412 } else {
1413 int64_t currentTSR = (int64_t)__CFReadTSR();
1414 currentFireTSR = oldFireTSR;
1415 while (currentFireTSR <= currentTSR) {
1416 currentFireTSR += rlt->_intervalTSR;
1417 }
1418 }
1419 rlt->_fireTSR = currentFireTSR;
1420 __CFRunLoopTimerRescheduleWithAllModes(rlt, rl);
1421 }
1422 __CFRunLoopTimerFireTSRUnlock();
1423 }
1424 }
1425 CFRelease(rlt);
1426 __CFRunLoopModeLock(rlm);
1427 return timerHandled;
1428 }
1429
1430 CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
1431 CHECK_FOR_FORK();
1432 CFRunLoopModeRef rlm;
1433 Boolean result = false;
1434 __CFRunLoopLock(rl);
1435 rlm = __CFRunLoopFindMode(rl, modeName, false);
1436 if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm)) {
1437 result = true;
1438 }
1439 __CFRunLoopUnlock(rl);
1440 if (rlm) __CFRunLoopModeUnlock(rlm);
1441 return result;
1442 }
1443
1444 // rl is locked, rlm is locked on entry and exit
1445 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) {
1446 CFIndex idx, cnt;
1447 const void **list, *buffer[256];
1448
1449 // Timers and version 1 sources go into the portSet currently
1450 if (NULL != rlm->_sources) {
1451 cnt = CFSetGetCount(rlm->_sources);
1452 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
1453 CFSetGetValues(rlm->_sources, list);
1454 for (idx = 0; idx < cnt; idx++) {
1455 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
1456 if (1 == rls->_context.version0.version) {
1457 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
1458 if (CFPORT_NULL != port) {
1459 __CFPortSetInsert(port, portSet);
1460 }
1461 }
1462 }
1463 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1464 }
1465 #if DEPLOYMENT_TARGET_MACOSX
1466 if (NULL != rlm->_timers) {
1467 cnt = CFSetGetCount(rlm->_timers);
1468 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
1469 CFSetGetValues(rlm->_timers, list);
1470 for (idx = 0; idx < cnt; idx++) {
1471 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx];
1472 if (MACH_PORT_NULL != rlt->_port) {
1473 mach_port_insert_member(mach_task_self(), rlt->_port, portSet);
1474 }
1475 }
1476 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1477 }
1478 #endif
1479 // iterate over submodes
1480 for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1481 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1482 CFRunLoopModeRef subrlm;
1483 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1484 if (NULL != subrlm) {
1485 __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet);
1486 __CFRunLoopModeUnlock(subrlm);
1487 }
1488 }
1489 }
1490
1491 static __CFPortSet _LastMainWaitSet = 0;
1492
1493 // return NO if we're the main runloop and there are no messages waiting on the port set
1494 int _CFRunLoopInputsReady(void) {
1495 CHECK_FOR_FORK();
1496 // XXX_PCB: the following 2 lines aren't safe to call during GC, because another
1497 // thread may have entered CFRunLoopGetMain(), which grabs a spink lock, and then
1498 // is suspended by the GC. We can check for the main thread more directly
1499 // by calling pthread_main_np().
1500 // CFRunLoopRef current = CFRunLoopGetMain()
1501 // if (current != CFRunLoopGetMain()) return true;
1502 #if DEPLOYMENT_TARGET_MACOSX
1503 if (!pthread_main_np()) return true;
1504
1505 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1506 if (_LastMainWaitSet == MACH_PORT_NULL) return false;
1507
1508 // prepare a message header with no space for any data, nor a trailer
1509 mach_msg_header_t msg;
1510 msg.msgh_size = sizeof(msg); // just the header, ma'am
1511 // need the waitset, actually XXX
1512 msg.msgh_local_port = _LastMainWaitSet;
1513 msg.msgh_remote_port = MACH_PORT_NULL;
1514 msg.msgh_id = 0;
1515
1516 kern_return_t ret = mach_msg(&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, 0, msg.msgh_size, _LastMainWaitSet, 0, MACH_PORT_NULL);
1517
1518 return (MACH_RCV_TOO_LARGE == ret);
1519 #endif
1520 return true;
1521 }
1522
1523 #if 0
1524 static void print_msg_scan_header(void) {
1525 printf("======== ======== ======== ========\n");
1526 printf("description\tport\tport type\t\treferences\n");
1527 }
1528
1529 static void print_one_port_info(const char *desc, mach_port_t port, mach_msg_type_name_t type) {
1530 mach_port_urefs_t refs;
1531 kern_return_t ret = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs);
1532 if (ret != KERN_SUCCESS) refs = 0;
1533 const char *type_name = "???";
1534 switch (type) {
1535 case MACH_MSG_TYPE_MOVE_SEND: type_name = "MACH_MSG_TYPE_MOVE_SEND"; break;
1536 case MACH_MSG_TYPE_MOVE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break;
1537 case MACH_MSG_TYPE_MOVE_RECEIVE: type_name = "MACH_MSG_TYPE_MOVE_RECEIVE"; break;
1538 case MACH_MSG_TYPE_MAKE_SEND: type_name = "MACH_MSG_TYPE_MAKE_SEND"; break;
1539 case MACH_MSG_TYPE_MAKE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break;
1540 }
1541 printf("%s\t%p\t%-20s\t%u\n", desc, port, type_name, refs);
1542 }
1543
1544 static void mach_msg_scan(mach_msg_header_t *msg, int clean) {
1545 Boolean printed_header = false;
1546 /*
1547 * The msgh_local_port field doesn't hold a port right.
1548 * The receive operation consumes the destination port right.
1549 */
1550 if (MACH_PORT_NULL != msg->msgh_remote_port) {
1551 if (! printed_header) print_msg_scan_header();
1552 printed_header = true;
1553 print_one_port_info("msg->msgh_remote_port", msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(msg->msgh_bits));
1554 }
1555 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1556 mach_msg_body_t *body = (mach_msg_body_t *) (msg + 1);
1557 mach_msg_descriptor_t *saddr = (mach_msg_descriptor_t *) ((mach_msg_base_t *) msg + 1);
1558 mach_msg_descriptor_t *eaddr = saddr + body->msgh_descriptor_count;
1559 for ( ; saddr < eaddr; saddr++) {
1560 switch (saddr->type.type) {
1561 case MACH_MSG_PORT_DESCRIPTOR:;
1562 mach_msg_port_descriptor_t *dsc = &saddr->port;
1563 if (! printed_header) print_msg_scan_header();
1564 printed_header = true;
1565 print_one_port_info("port in body", dsc->name, dsc->disposition);
1566 // if (clean) mach_port_deallocate(mach_task_self(), dsc->name);
1567 break;
1568 case MACH_MSG_OOL_PORTS_DESCRIPTOR:;
1569 mach_msg_ool_ports_descriptor_t *dsc2 = &saddr->ool_ports;
1570 mach_port_t *ports = (mach_port_t *) dsc2->address;
1571 for (mach_msg_type_number_t j = 0; j < dsc2->count; j++, ports++) {
1572 if (! printed_header) print_msg_scan_header();
1573 printed_header = true;
1574 print_one_port_info("port in OOL ports", *ports, dsc2->disposition);
1575 }
1576 break;
1577 }
1578 }
1579 }
1580 }
1581 #endif
1582
1583 /* rl is unlocked, rlm locked on entrance and exit */
1584 static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, Boolean waitIfEmpty) { /* DOES CALLOUT */
1585 int64_t termTSR;
1586 #if DEPLOYMENT_TARGET_MACOSX
1587 mach_port_name_t timeoutPort = MACH_PORT_NULL;
1588 Boolean timeoutPortAdded = false;
1589 #endif
1590 Boolean poll = false;
1591 Boolean firstPass = true;
1592
1593 if (__CFRunLoopIsStopped(rl)) {
1594 return kCFRunLoopRunStopped;
1595 } else if (rlm->_stopped) {
1596 rlm->_stopped = false;
1597 return kCFRunLoopRunStopped;
1598 }
1599 if (seconds <= 0.0) {
1600 termTSR = 0;
1601 } else if (3.1556952e+9 < seconds) {
1602 termTSR = LLONG_MAX;
1603 } else {
1604 termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds);
1605 #if DEPLOYMENT_TARGET_MACOSX
1606 timeoutPort = mk_timer_create();
1607 mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR));
1608 #endif
1609 }
1610 if (seconds <= 0.0) {
1611 poll = true;
1612 }
1613 if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = CFPORT_NULL;
1614 for (;;) {
1615 __CFPortSet waitSet = CFPORT_NULL;
1616 waitSet = CFPORT_NULL;
1617 Boolean destroyWaitSet = false;
1618 CFRunLoopSourceRef rls;
1619 #if DEPLOYMENT_TARGET_MACOSX
1620 mach_msg_header_t *msg;
1621 kern_return_t ret;
1622 uint8_t buffer[1024 + 80] = {0}; // large enough for 1k of inline payload; must be zeroed for GC
1623 #else
1624 CFArrayRef timersToCall = NULL;
1625 #endif
1626 int32_t returnValue = 0;
1627 Boolean sourceHandledThisLoop = false;
1628
1629 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
1630 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
1631
1632 sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
1633
1634 if (sourceHandledThisLoop) {
1635 poll = true;
1636 }
1637
1638 if (!poll) {
1639 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
1640 __CFRunLoopSetSleeping(rl);
1641 }
1642 if (NULL != rlm->_submodes) {
1643 // !!! what do we do if this doesn't succeed?
1644 waitSet = __CFPortSetAllocate();
1645 if (CFPORT_NULL == waitSet) HALT;
1646 __CFRunLoopModeUnlock(rlm);
1647 __CFRunLoopLock(rl);
1648 __CFRunLoopModeLock(rlm);
1649 __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet);
1650 __CFRunLoopUnlock(rl);
1651 #if DEPLOYMENT_TARGET_MACOSX
1652 if (CFPORT_NULL != timeoutPort) {
1653 __CFPortSetInsert(timeoutPort, waitSet);
1654 }
1655 #endif
1656 destroyWaitSet = true;
1657 } else {
1658 waitSet = rlm->_portSet;
1659 #if DEPLOYMENT_TARGET_MACOSX
1660 if (!timeoutPortAdded && CFPORT_NULL != timeoutPort) {
1661 __CFPortSetInsert(timeoutPort, waitSet);
1662 timeoutPortAdded = true;
1663 }
1664 #endif
1665 }
1666 if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = waitSet;
1667 __CFRunLoopModeUnlock(rlm);
1668
1669 #if DEPLOYMENT_TARGET_MACOSX
1670 msg = (mach_msg_header_t *)buffer;
1671 msg->msgh_size = sizeof(buffer);
1672
1673 /* In that sleep of death what nightmares may come ... */
1674 try_receive:
1675 msg->msgh_bits = 0;
1676 msg->msgh_local_port = waitSet;
1677 msg->msgh_remote_port = MACH_PORT_NULL;
1678 msg->msgh_id = 0;
1679 ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|(poll ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL);
1680 if (MACH_RCV_TOO_LARGE == ret) {
1681 uint32_t newSize = round_msg(msg->msgh_size) + sizeof(mach_msg_audit_trailer_t);
1682 if (msg == (mach_msg_header_t *)buffer) msg = NULL;
1683 msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0);
1684 msg->msgh_size = newSize;
1685 goto try_receive;
1686 } else if (MACH_RCV_TIMED_OUT == ret) {
1687 // timeout, for poll
1688 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
1689 msg = NULL;
1690 } else if (MACH_MSG_SUCCESS != ret) {
1691 HALT;
1692 }
1693 #elif defined(__WIN32__)
1694 DWORD waitResult = WAIT_TIMEOUT;
1695 HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS];
1696 HANDLE *handles;
1697 uint32_t handleCount;
1698 Boolean freeHandles;
1699 if (destroyWaitSet) {
1700 // wait set is a local, no one else could modify it, no need to copy handles
1701 handles = waitSet->handles;
1702 handleCount = waitSet->used;
1703 freeHandles = FALSE;
1704 } else {
1705 // copy out the handles to be safe from other threads at work
1706 handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount);
1707 freeHandles = (handles != handleBuf);
1708 }
1709 // should msgQMask be an OR'ing of this and all submodes' masks?
1710 if (0 == GetQueueStatus(rlm->_msgQMask)) {
1711 DWORD timeout;
1712 if (poll)
1713 timeout = 0;
1714 else {
1715 __CFRunLoopModeLock(rlm);
1716 int64_t nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm);
1717 if (nextStop <= 0)
1718 nextStop = termTSR;
1719 else if (nextStop > termTSR)
1720 nextStop = termTSR;
1721 // else the next stop is dictated by the next timer
1722 int64_t timeoutTSR = nextStop - __CFReadTSR();
1723 if (timeoutTSR < 0)
1724 timeout = 0;
1725 else {
1726 CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000;
1727 if (timeoutCF > MAXDWORD)
1728 timeout = INFINITE;
1729 else
1730 timeout = timeoutCF;
1731 }
1732 }
1733 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- about to wait for %d objects, wakeupport is %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), handleCount, rl->_wakeUpPort); }
1734 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("All RLM sources = %@"), rlm->_sources); }
1735 waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout, rlm->_msgQMask);
1736 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- waitResult was %d"), CFRunLoopGetCurrent(), *_CFGetProgname(), waitResult); }
1737 }
1738 ResetEvent(rl->_wakeUpPort);
1739 #endif
1740 if (destroyWaitSet) {
1741 __CFPortSetFree(waitSet);
1742 if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = 0;
1743 }
1744 __CFRunLoopLock(rl);
1745 __CFRunLoopModeLock(rlm);
1746 __CFRunLoopUnlock(rl);
1747 if (!poll) {
1748 __CFRunLoopUnsetSleeping(rl);
1749 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
1750 }
1751 poll = false;
1752 __CFRunLoopModeUnlock(rlm);
1753 __CFRunLoopLock(rl);
1754 __CFRunLoopModeLock(rlm);
1755
1756 __CFPort livePort = CFPORT_NULL;
1757 #if DEPLOYMENT_TARGET_MACOSX
1758 if (NULL != msg) {
1759 livePort = msg->msgh_local_port;
1760 }
1761 #elif defined(__WIN32__)
1762 CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError());
1763 if (waitResult == WAIT_TIMEOUT) {
1764 // do nothing, just return to caller
1765 } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) {
1766 // a handle was signalled
1767 livePort = handles[waitResult-WAIT_OBJECT_0];
1768 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- Resetting event %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), livePort); }
1769 } else if (waitResult == WAIT_OBJECT_0+handleCount) {
1770 // windows message received - the CFWindowsMessageQueue will pick this up when
1771 // the v0 RunLoopSources get their chance
1772 } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) {
1773 // an "abandoned mutex object"
1774 livePort = handles[waitResult-WAIT_ABANDONED_0];
1775 } else {
1776 CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult);
1777 }
1778 if (freeHandles)
1779 CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
1780 timersToCall = __CFRunLoopTimersToFire(rl, rlm);
1781 #endif
1782
1783 if (CFPORT_NULL == livePort) {
1784 __CFRunLoopUnlock(rl);
1785 } else if (livePort == rl->_wakeUpPort) {
1786 // wakeup
1787 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); }
1788 __CFRunLoopUnlock(rl);
1789 }
1790 #if DEPLOYMENT_TARGET_MACOSX
1791 else if (livePort == timeoutPort) {
1792 returnValue = kCFRunLoopRunTimedOut;
1793 __CFRunLoopUnlock(rl);
1794 } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
1795 mach_msg_header_t *reply = NULL;
1796 __CFRunLoopUnlock(rl);
1797 // mach_msg_scan(msg, 0);
1798 if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) {
1799 sourceHandledThisLoop = true;
1800 }
1801 // mach_msg_scan(msg, 1);
1802 if (NULL != reply) {
1803 ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
1804 //#warning CF: what should be done with the return value?
1805 CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
1806 }
1807 } else {
1808 CFRunLoopTimerRef rlt;
1809 rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort);
1810 __CFRunLoopUnlock(rl);
1811 if (NULL != rlt) {
1812 __CFRunLoopDoTimer(rl, rlm, rlt);
1813 }
1814 }
1815 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
1816 #else
1817 else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
1818 __CFRunLoopUnlock(rl);
1819 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("Source %@ was signalled"), rls); }
1820 if (__CFRunLoopDoSource1(rl, rlm, rls)) {
1821 sourceHandledThisLoop = true;
1822 }
1823 }
1824 #endif
1825
1826 __CFRunLoopModeUnlock(rlm); // locks must be taken in order
1827 __CFRunLoopLock(rl);
1828 __CFRunLoopModeLock(rlm);
1829 if (sourceHandledThisLoop && stopAfterHandle) {
1830 returnValue = kCFRunLoopRunHandledSource;
1831 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
1832 // internal wakeup signal on the first look at the portset, we'll go around the loop one
1833 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
1834 } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) {
1835 returnValue = kCFRunLoopRunTimedOut;
1836 } else if (__CFRunLoopIsStopped(rl)) {
1837 returnValue = kCFRunLoopRunStopped;
1838 } else if (rlm->_stopped) {
1839 rlm->_stopped = false;
1840 returnValue = kCFRunLoopRunStopped;
1841 } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm)) {
1842 returnValue = kCFRunLoopRunFinished;
1843 }
1844 __CFRunLoopUnlock(rl);
1845 if (0 != returnValue) {
1846 #if DEPLOYMENT_TARGET_MACOSX
1847 if (MACH_PORT_NULL != timeoutPort) {
1848 if (!destroyWaitSet) __CFPortSetRemove(timeoutPort, waitSet);
1849 mk_timer_destroy(timeoutPort);
1850 }
1851 #endif
1852 return returnValue;
1853 }
1854 firstPass = false;
1855 }
1856 }
1857
1858 SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
1859 CHECK_FOR_FORK();
1860 if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
1861 __CFRunLoopLock(rl);
1862 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
1863 if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode)) {
1864 if (currentMode) __CFRunLoopModeUnlock(currentMode);
1865 __CFRunLoopUnlock(rl);
1866 return kCFRunLoopRunFinished;
1867 }
1868 uint32_t *previousStopped = (uint32_t *)rl->_stopped;
1869 rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 4 * sizeof(uint32_t), 0);
1870 rl->_stopped[0] = 0x4346524C;
1871 rl->_stopped[1] = 0x4346524C; // 'CFRL'
1872 rl->_stopped[2] = 0x00000000; // here the value is stored
1873 rl->_stopped[3] = 0x4346524C;
1874 CFRunLoopModeRef previousMode = rl->_currentMode;
1875 rl->_currentMode = currentMode;
1876 __CFRunLoopUnlock(rl);
1877 int32_t result;
1878 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
1879 result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, false);
1880 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
1881 __CFRunLoopModeUnlock(currentMode);
1882 __CFRunLoopLock(rl);
1883 CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped);
1884 rl->_stopped = previousStopped;
1885 rl->_currentMode = previousMode;
1886 __CFRunLoopUnlock(rl);
1887 return result;
1888 }
1889
1890 void CFRunLoopRun(void) { /* DOES CALLOUT */
1891 int32_t result;
1892 do {
1893 result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
1894 CHECK_FOR_FORK();
1895 } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
1896 }
1897
1898 SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
1899 CHECK_FOR_FORK();
1900 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
1901 }
1902
1903 static void __CFRunLoopFindMinTimer(const void *value, void *ctx) {
1904 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
1905 if (__CFIsValid(rlt)) {
1906 CFRunLoopTimerRef *result = ctx;
1907 if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) {
1908 *result = rlt;
1909 }
1910 }
1911 }
1912
1913 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
1914 CFRunLoopTimerRef result = NULL;
1915 int64_t fireTime = 0;
1916 if (rlm) {
1917 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
1918 __CFRunLoopTimerFireTSRLock();
1919 CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result);
1920 if (result)
1921 fireTime = result->_fireTSR;
1922 __CFRunLoopTimerFireTSRUnlock();
1923 }
1924 if (NULL != rlm->_submodes) {
1925 CFIndex idx, cnt;
1926 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
1927 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1928 CFRunLoopModeRef subrlm;
1929 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1930 if (NULL != subrlm) {
1931 int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm);
1932 __CFRunLoopModeUnlock(subrlm);
1933 if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime))
1934 fireTime = newFireTime;
1935 }
1936 }
1937 }
1938 __CFRunLoopModeUnlock(rlm);
1939 }
1940 return fireTime;
1941 }
1942
1943 CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
1944 CHECK_FOR_FORK();
1945 CFRunLoopModeRef rlm;
1946 int64_t fireTSR;
1947 __CFRunLoopLock(rl);
1948 rlm = __CFRunLoopFindMode(rl, modeName, false);
1949 __CFRunLoopUnlock(rl);
1950 fireTSR = __CFRunLoopGetNextTimerFireTSR(rl, rlm);
1951 int64_t now2 = (int64_t)mach_absolute_time();
1952 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
1953 return (0 == fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(fireTSR - now2));
1954 }
1955
1956 Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
1957 CHECK_FOR_FORK();
1958 return __CFRunLoopIsSleeping(rl);
1959 }
1960
1961 void CFRunLoopWakeUp(CFRunLoopRef rl) {
1962 CHECK_FOR_FORK();
1963 #if DEPLOYMENT_TARGET_MACOSX
1964 kern_return_t ret;
1965 /* We unconditionally try to send the message, since we don't want
1966 * to lose a wakeup, but the send may fail if there is already a
1967 * wakeup pending, since the queue length is 1. */
1968 ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0);
1969 if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) {
1970 HALT;
1971 }
1972 #else
1973 SetEvent(rl->_wakeUpPort);
1974 #endif
1975 }
1976
1977 void CFRunLoopStop(CFRunLoopRef rl) {
1978 CHECK_FOR_FORK();
1979 __CFRunLoopLock(rl);
1980 __CFRunLoopSetStopped(rl);
1981 __CFRunLoopUnlock(rl);
1982 CFRunLoopWakeUp(rl);
1983 }
1984
1985 CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
1986 CHECK_FOR_FORK();
1987 CFRunLoopModeRef rlm;
1988 __CFRunLoopLock(rl);
1989 rlm = __CFRunLoopFindMode(rl, modeName, true);
1990 __CFRunLoopUnlock(rl);
1991 if (NULL != rlm) {
1992 rlm->_stopped = true;
1993 __CFRunLoopModeUnlock(rlm);
1994 }
1995 CFRunLoopWakeUp(rl);
1996 }
1997
1998 CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
1999 CHECK_FOR_FORK();
2000 CFRunLoopModeRef rlm;
2001 if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) {
2002 return false;
2003 } else if (CFEqual(modeName, candidateContainedName)) {
2004 return true;
2005 }
2006 __CFRunLoopLock(rl);
2007 rlm = __CFRunLoopFindMode(rl, modeName, true);
2008 __CFRunLoopUnlock(rl);
2009 if (NULL != rlm) {
2010 CFArrayRef submodes;
2011 if (NULL == rlm->_submodes) {
2012 __CFRunLoopModeUnlock(rlm);
2013 return false;
2014 }
2015 if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) {
2016 __CFRunLoopModeUnlock(rlm);
2017 return true;
2018 }
2019 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
2020 __CFRunLoopModeUnlock(rlm);
2021 if (NULL != submodes) {
2022 CFIndex idx, cnt;
2023 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
2024 CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
2025 if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) {
2026 CFRelease(submodes);
2027 return true;
2028 }
2029 }
2030 CFRelease(submodes);
2031 }
2032 }
2033 return false;
2034 }
2035
2036 CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) {
2037 CHECK_FOR_FORK();
2038 CFRunLoopModeRef rlm;
2039 if (__CFRunLoopIsDeallocating(rl)) return;
2040 // should really do a recursive check here, to make sure that a cycle isn't
2041 // introduced; of course, if that happens, you aren't going to get very far.
2042 if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) {
2043 return;
2044 } else {
2045 __CFRunLoopLock(rl);
2046 rlm = __CFRunLoopFindMode(rl, toModeName, true);
2047 __CFRunLoopUnlock(rl);
2048 if (NULL != rlm) {
2049 if (NULL == rlm->_submodes) {
2050 rlm->_submodes = CFArrayCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeArrayCallBacks);
2051 }
2052 if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) {
2053 CFArrayAppendValue(rlm->_submodes, modeName);
2054 }
2055 __CFRunLoopModeUnlock(rlm);
2056 }
2057 }
2058 }
2059
2060 CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) {
2061 CHECK_FOR_FORK();
2062 CFRunLoopModeRef rlm;
2063 // should really do a recursive check here, to make sure that a cycle isn't
2064 // introduced; of course, if that happens, you aren't going to get very far.
2065 if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) {
2066 return;
2067 } else {
2068 __CFRunLoopLock(rl);
2069 rlm = __CFRunLoopFindMode(rl, fromModeName, true);
2070 __CFRunLoopUnlock(rl);
2071 if (NULL != rlm) {
2072 if (NULL != rlm->_submodes) {
2073 CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes);
2074 idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName);
2075 if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx);
2076 }
2077 __CFRunLoopModeUnlock(rlm);
2078 }
2079 }
2080 }
2081
2082 Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
2083 CHECK_FOR_FORK();
2084 CFRunLoopModeRef rlm;
2085 Boolean hasValue = false;
2086 __CFRunLoopLock(rl);
2087 if (modeName == kCFRunLoopCommonModes) {
2088 if (NULL != rl->_commonModeItems) {
2089 hasValue = CFSetContainsValue(rl->_commonModeItems, rls);
2090 }
2091 __CFRunLoopUnlock(rl);
2092 } else {
2093 rlm = __CFRunLoopFindMode(rl, modeName, false);
2094 __CFRunLoopUnlock(rl);
2095 if (NULL != rlm && NULL != rlm->_sources) {
2096 hasValue = CFSetContainsValue(rlm->_sources, rls);
2097 __CFRunLoopModeUnlock(rlm);
2098 } else if (NULL != rlm) {
2099 __CFRunLoopModeUnlock(rlm);
2100 }
2101 }
2102 return hasValue;
2103 }
2104
2105 void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
2106 CHECK_FOR_FORK();
2107 CFRunLoopModeRef rlm;
2108 if (__CFRunLoopIsDeallocating(rl)) return;
2109 if (!__CFIsValid(rls)) return;
2110 __CFRunLoopLock(rl);
2111 if (modeName == kCFRunLoopCommonModes) {
2112 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2113 if (NULL == rl->_commonModeItems) {
2114 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
2115 _CFSetSetCapacity(rl->_commonModeItems, 20);
2116 }
2117 CFSetAddValue(rl->_commonModeItems, rls);
2118 __CFRunLoopUnlock(rl);
2119 if (NULL != set) {
2120 CFTypeRef context[2] = {rl, rls};
2121 /* add new item to all common-modes */
2122 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2123 CFRelease(set);
2124 }
2125 } else {
2126 rlm = __CFRunLoopFindMode(rl, modeName, true);
2127 __CFRunLoopUnlock(rl);
2128 if (NULL != rlm && NULL == rlm->_sources) {
2129 rlm->_sources = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
2130 _CFSetSetCapacity(rlm->_sources, 10);
2131 }
2132 if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) {
2133 CFSetAddValue(rlm->_sources, rls);
2134 __CFRunLoopModeUnlock(rlm);
2135 __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */
2136 } else if (NULL != rlm) {
2137 __CFRunLoopModeUnlock(rlm);
2138 }
2139 }
2140 }
2141
2142 void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
2143 CHECK_FOR_FORK();
2144 CFRunLoopModeRef rlm;
2145 __CFRunLoopLock(rl);
2146 if (modeName == kCFRunLoopCommonModes) {
2147 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
2148 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2149 CFSetRemoveValue(rl->_commonModeItems, rls);
2150 __CFRunLoopUnlock(rl);
2151 if (NULL != set) {
2152 CFTypeRef context[2] = {rl, rls};
2153 /* remove new item from all common-modes */
2154 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2155 CFRelease(set);
2156 }
2157 } else {
2158 __CFRunLoopUnlock(rl);
2159 }
2160 } else {
2161 rlm = __CFRunLoopFindMode(rl, modeName, false);
2162 __CFRunLoopUnlock(rl);
2163 if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) {
2164 CFRetain(rls);
2165 CFSetRemoveValue(rlm->_sources, rls);
2166 __CFRunLoopModeUnlock(rlm);
2167 __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */
2168 CFRelease(rls);
2169 } else if (NULL != rlm) {
2170 __CFRunLoopModeUnlock(rlm);
2171 }
2172 }
2173 }
2174
2175 Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2176 CHECK_FOR_FORK();
2177 CFRunLoopModeRef rlm;
2178 Boolean hasValue = false;
2179 __CFRunLoopLock(rl);
2180 if (modeName == kCFRunLoopCommonModes) {
2181 if (NULL != rl->_commonModeItems) {
2182 hasValue = CFSetContainsValue(rl->_commonModeItems, rlo);
2183 }
2184 __CFRunLoopUnlock(rl);
2185 } else {
2186 rlm = __CFRunLoopFindMode(rl, modeName, false);
2187 __CFRunLoopUnlock(rl);
2188 if (NULL != rlm && NULL != rlm->_observers) {
2189 hasValue = CFSetContainsValue(rlm->_observers, rlo);
2190 __CFRunLoopModeUnlock(rlm);
2191 } else if (NULL != rlm) {
2192 __CFRunLoopModeUnlock(rlm);
2193 }
2194 }
2195 return hasValue;
2196 }
2197
2198 void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2199 CHECK_FOR_FORK();
2200 CFRunLoopModeRef rlm;
2201 if (__CFRunLoopIsDeallocating(rl)) return;
2202 if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
2203 __CFRunLoopLock(rl);
2204 if (modeName == kCFRunLoopCommonModes) {
2205 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2206 if (NULL == rl->_commonModeItems) {
2207 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
2208 }
2209 CFSetAddValue(rl->_commonModeItems, rlo);
2210 __CFRunLoopUnlock(rl);
2211 if (NULL != set) {
2212 CFTypeRef context[2] = {rl, rlo};
2213 /* add new item to all common-modes */
2214 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2215 CFRelease(set);
2216 }
2217 } else {
2218 rlm = __CFRunLoopFindMode(rl, modeName, true);
2219 __CFRunLoopUnlock(rl);
2220 if (NULL != rlm && NULL == rlm->_observers) {
2221 rlm->_observers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
2222 }
2223 if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) {
2224 CFSetAddValue(rlm->_observers, rlo);
2225 __CFRunLoopModeUnlock(rlm);
2226 __CFRunLoopObserverSchedule(rlo, rl, rlm);
2227 } else if (NULL != rlm) {
2228 __CFRunLoopModeUnlock(rlm);
2229 }
2230 }
2231 }
2232
2233 void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2234 CHECK_FOR_FORK();
2235 CFRunLoopModeRef rlm;
2236 __CFRunLoopLock(rl);
2237 if (modeName == kCFRunLoopCommonModes) {
2238 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) {
2239 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2240 CFSetRemoveValue(rl->_commonModeItems, rlo);
2241 __CFRunLoopUnlock(rl);
2242 if (NULL != set) {
2243 CFTypeRef context[2] = {rl, rlo};
2244 /* remove new item from all common-modes */
2245 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2246 CFRelease(set);
2247 }
2248 } else {
2249 __CFRunLoopUnlock(rl);
2250 }
2251 } else {
2252 rlm = __CFRunLoopFindMode(rl, modeName, false);
2253 __CFRunLoopUnlock(rl);
2254 if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) {
2255 CFRetain(rlo);
2256 CFSetRemoveValue(rlm->_observers, rlo);
2257 __CFRunLoopModeUnlock(rlm);
2258 __CFRunLoopObserverCancel(rlo, rl, rlm);
2259 CFRelease(rlo);
2260 } else if (NULL != rlm) {
2261 __CFRunLoopModeUnlock(rlm);
2262 }
2263 }
2264 }
2265
2266 Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2267 CHECK_FOR_FORK();
2268 CFRunLoopModeRef rlm;
2269 Boolean hasValue = false;
2270 __CFRunLoopLock(rl);
2271 if (modeName == kCFRunLoopCommonModes) {
2272 if (NULL != rl->_commonModeItems) {
2273 hasValue = CFSetContainsValue(rl->_commonModeItems, rlt);
2274 }
2275 __CFRunLoopUnlock(rl);
2276 } else {
2277 rlm = __CFRunLoopFindMode(rl, modeName, false);
2278 __CFRunLoopUnlock(rl);
2279 if (NULL != rlm && NULL != rlm->_timers) {
2280 hasValue = CFSetContainsValue(rlm->_timers, rlt);
2281 __CFRunLoopModeUnlock(rlm);
2282 } else if (NULL != rlm) {
2283 __CFRunLoopModeUnlock(rlm);
2284 }
2285 }
2286 return hasValue;
2287 }
2288
2289 void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2290 CHECK_FOR_FORK();
2291 CFRunLoopModeRef rlm;
2292 if (__CFRunLoopIsDeallocating(rl)) return;
2293 if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
2294 __CFRunLoopLock(rl);
2295 if (modeName == kCFRunLoopCommonModes) {
2296 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2297 if (NULL == rl->_commonModeItems) {
2298 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
2299 }
2300 CFSetAddValue(rl->_commonModeItems, rlt);
2301 __CFRunLoopUnlock(rl);
2302 if (NULL != set) {
2303 CFTypeRef context[2] = {rl, rlt};
2304 /* add new item to all common-modes */
2305 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2306 CFRelease(set);
2307 }
2308 } else {
2309 rlm = __CFRunLoopFindMode(rl, modeName, true);
2310 __CFRunLoopUnlock(rl);
2311 if (NULL != rlm && NULL == rlm->_timers) {
2312 rlm->_timers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
2313 }
2314 if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) {
2315 CFSetAddValue(rlm->_timers, rlt);
2316 __CFRunLoopModeUnlock(rlm);
2317 __CFRunLoopTimerSchedule(rlt, rl, rlm);
2318 } else if (NULL != rlm) {
2319 __CFRunLoopModeUnlock(rlm);
2320 }
2321 }
2322 }
2323
2324 void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2325 CHECK_FOR_FORK();
2326 CFRunLoopModeRef rlm;
2327 __CFRunLoopLock(rl);
2328 if (modeName == kCFRunLoopCommonModes) {
2329 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) {
2330 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2331 CFSetRemoveValue(rl->_commonModeItems, rlt);
2332 __CFRunLoopUnlock(rl);
2333 if (NULL != set) {
2334 CFTypeRef context[2] = {rl, rlt};
2335 /* remove new item from all common-modes */
2336 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2337 CFRelease(set);
2338 }
2339 } else {
2340 __CFRunLoopUnlock(rl);
2341 }
2342 } else {
2343 rlm = __CFRunLoopFindMode(rl, modeName, false);
2344 __CFRunLoopUnlock(rl);
2345 if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) {
2346 CFRetain(rlt);
2347 CFSetRemoveValue(rlm->_timers, rlt);
2348 __CFRunLoopModeUnlock(rlm);
2349 __CFRunLoopTimerCancel(rlt, rl, rlm);
2350 CFRelease(rlt);
2351 } else if (NULL != rlm) {
2352 __CFRunLoopModeUnlock(rlm);
2353 }
2354 }
2355 }
2356
2357
2358 /* CFRunLoopSource */
2359
2360 static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */
2361 CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1;
2362 CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2;
2363 if (rls1 == rls2) return true;
2364 if (rls1->_order != rls2->_order) return false;
2365 if (rls1->_context.version0.version != rls2->_context.version0.version) return false;
2366 if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false;
2367 if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false;
2368 if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false;
2369 if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false;
2370 if (rls1->_context.version0.equal)
2371 return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info);
2372 return (rls1->_context.version0.info == rls2->_context.version0.info);
2373 }
2374
2375 static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) { /* DOES CALLOUT */
2376 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
2377 if (rls->_context.version0.hash)
2378 return rls->_context.version0.hash(rls->_context.version0.info);
2379 return (CFHashCode)rls->_context.version0.info;
2380 }
2381
2382 static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
2383 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
2384 CFStringRef result;
2385 CFStringRef contextDesc = NULL;
2386 if (NULL != rls->_context.version0.copyDescription) {
2387 contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info);
2388 }
2389 if (NULL == contextDesc) {
2390 void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL);
2391 #if DEPLOYMENT_TARGET_MACOSX
2392 Dl_info info;
2393 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
2394 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr);
2395 #else
2396 #error Unknown or unspecified DEPLOYMENT_TARGET
2397 #endif
2398 }
2399 result = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), lockCount(rls->_lock) ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc);
2400 CFRelease(contextDesc);
2401 return result;
2402 }
2403
2404 static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2405 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
2406 CFRunLoopSourceInvalidate(rls);
2407 if (rls->_context.version0.release) {
2408 rls->_context.version0.release(rls->_context.version0.info);
2409 }
2410 }
2411
2412 static const CFRuntimeClass __CFRunLoopSourceClass = {
2413 _kCFRuntimeScannedObject,
2414 "CFRunLoopSource",
2415 NULL, // init
2416 NULL, // copy
2417 __CFRunLoopSourceDeallocate,
2418 __CFRunLoopSourceEqual,
2419 __CFRunLoopSourceHash,
2420 NULL, //
2421 __CFRunLoopSourceCopyDescription
2422 };
2423
2424 __private_extern__ void __CFRunLoopSourceInitialize(void) {
2425 __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass);
2426 }
2427
2428 CFTypeID CFRunLoopSourceGetTypeID(void) {
2429 return __kCFRunLoopSourceTypeID;
2430 }
2431
2432 CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
2433 CHECK_FOR_FORK();
2434 CFRunLoopSourceRef memory;
2435 uint32_t size;
2436 if (NULL == context) HALT;
2437 size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
2438 memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL);
2439 if (NULL == memory) {
2440 return NULL;
2441 }
2442 __CFSetValid(memory);
2443 __CFRunLoopSourceUnsetSignaled(memory);
2444 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
2445 memory->_bits = 0;
2446 memory->_order = order;
2447 memory->_runLoops = NULL;
2448 size = 0;
2449 switch (context->version) {
2450 case 0:
2451 size = sizeof(CFRunLoopSourceContext);
2452 break;
2453 case 1:
2454 size = sizeof(CFRunLoopSourceContext1);
2455 break;
2456 #if DEPLOYMENT_TARGET_MACOSX
2457 case 2:
2458 size = sizeof(CFRunLoopSourceContext2);
2459 break;
2460 #endif
2461 }
2462 CF_WRITE_BARRIER_MEMMOVE(&memory->_context, context, size);
2463 if (context->retain) {
2464 memory->_context.version0.info = (void *)context->retain(context->info);
2465 }
2466 return memory;
2467 }
2468
2469 CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
2470 CHECK_FOR_FORK();
2471 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2472 return rls->_order;
2473 }
2474
2475 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
2476 CFRunLoopRef rl = (CFRunLoopRef)value;
2477 CFTypeRef *params = context;
2478 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
2479 CFArrayRef array;
2480 CFIndex idx;
2481 if (rl == params[1]) return;
2482 array = CFRunLoopCopyAllModes(rl);
2483 for (idx = CFArrayGetCount(array); idx--;) {
2484 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2485 CFRunLoopRemoveSource(rl, rls, modeName);
2486 }
2487 CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
2488 CFRelease(array);
2489 params[1] = rl;
2490 }
2491
2492 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
2493 CHECK_FOR_FORK();
2494 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2495 CFRetain(rls);
2496 __CFRunLoopSourceLock(rls);
2497 if (__CFIsValid(rls)) {
2498 __CFUnsetValid(rls);
2499 __CFRunLoopSourceUnsetSignaled(rls);
2500 if (NULL != rls->_runLoops) {
2501 CFTypeRef params[2] = {rls, NULL};
2502 CFBagRef bag = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops);
2503 CFRelease(rls->_runLoops);
2504 rls->_runLoops = NULL;
2505 __CFRunLoopSourceUnlock(rls);
2506 CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params);
2507 CFRelease(bag);
2508 } else {
2509 __CFRunLoopSourceUnlock(rls);
2510 }
2511 /* for hashing- and equality-use purposes, can't actually release the context here */
2512 } else {
2513 __CFRunLoopSourceUnlock(rls);
2514 }
2515 CFRelease(rls);
2516 }
2517
2518 Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
2519 CHECK_FOR_FORK();
2520 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2521 return __CFIsValid(rls);
2522 }
2523
2524 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
2525 CHECK_FOR_FORK();
2526 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2527 CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__);
2528 CFIndex size = 0;
2529 switch (context->version) {
2530 case 0:
2531 size = sizeof(CFRunLoopSourceContext);
2532 break;
2533 case 1:
2534 size = sizeof(CFRunLoopSourceContext1);
2535 break;
2536 #if DEPLOYMENT_TARGET_MACOSX
2537 case 2:
2538 size = sizeof(CFRunLoopSourceContext2);
2539 break;
2540 #endif
2541 }
2542 memmove(context, &rls->_context, size);
2543 }
2544
2545 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
2546 CHECK_FOR_FORK();
2547 __CFRunLoopSourceLock(rls);
2548 if (__CFIsValid(rls)) {
2549 __CFRunLoopSourceSetSignaled(rls);
2550 }
2551 __CFRunLoopSourceUnlock(rls);
2552 }
2553
2554 Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) {
2555 CHECK_FOR_FORK();
2556 __CFRunLoopSourceLock(rls);
2557 Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false;
2558 __CFRunLoopSourceUnlock(rls);
2559 return ret;
2560 }
2561
2562 /* CFRunLoopObserver */
2563
2564 static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
2565 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
2566 CFStringRef result;
2567 CFStringRef contextDesc = NULL;
2568 if (NULL != rlo->_context.copyDescription) {
2569 contextDesc = rlo->_context.copyDescription(rlo->_context.info);
2570 }
2571 if (!contextDesc) {
2572 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
2573 }
2574 #if DEPLOYMENT_TARGET_MACOSX
2575 void *addr = rlo->_callout;
2576 Dl_info info;
2577 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
2578 result = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlo), lockCount(rlo->_lock) ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, name, addr, contextDesc);
2579 #else
2580 #error Unknown or unspecified DEPLOYMENT_TARGET
2581 #endif
2582 CFRelease(contextDesc);
2583 return result;
2584 }
2585
2586 static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2587 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
2588 CFRunLoopObserverInvalidate(rlo);
2589 }
2590
2591 static const CFRuntimeClass __CFRunLoopObserverClass = {
2592 0,
2593 "CFRunLoopObserver",
2594 NULL, // init
2595 NULL, // copy
2596 __CFRunLoopObserverDeallocate,
2597 NULL,
2598 NULL,
2599 NULL, //
2600 __CFRunLoopObserverCopyDescription
2601 };
2602
2603 __private_extern__ void __CFRunLoopObserverInitialize(void) {
2604 __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass);
2605 }
2606
2607 CFTypeID CFRunLoopObserverGetTypeID(void) {
2608 return __kCFRunLoopObserverTypeID;
2609 }
2610
2611 CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
2612 CHECK_FOR_FORK();
2613 CFRunLoopObserverRef memory;
2614 UInt32 size;
2615 size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
2616 memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL);
2617 if (NULL == memory) {
2618 return NULL;
2619 }
2620 __CFSetValid(memory);
2621 __CFRunLoopObserverUnsetFiring(memory);
2622 if (repeats) {
2623 __CFRunLoopObserverSetRepeats(memory);
2624 } else {
2625 __CFRunLoopObserverUnsetRepeats(memory);
2626 }
2627 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
2628 memory->_runLoop = NULL;
2629 memory->_rlCount = 0;
2630 memory->_activities = activities;
2631 memory->_order = order;
2632 memory->_callout = callout;
2633 if (context) {
2634 if (context->retain) {
2635 memory->_context.info = (void *)context->retain(context->info);
2636 } else {
2637 memory->_context.info = context->info;
2638 }
2639 memory->_context.retain = context->retain;
2640 memory->_context.release = context->release;
2641 memory->_context.copyDescription = context->copyDescription;
2642 } else {
2643 memory->_context.info = 0;
2644 memory->_context.retain = 0;
2645 memory->_context.release = 0;
2646 memory->_context.copyDescription = 0;
2647 }
2648 return memory;
2649 }
2650
2651 CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
2652 CHECK_FOR_FORK();
2653 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2654 return rlo->_activities;
2655 }
2656
2657 CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
2658 CHECK_FOR_FORK();
2659 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2660 return rlo->_order;
2661 }
2662
2663 Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
2664 CHECK_FOR_FORK();
2665 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2666 return __CFRunLoopObserverRepeats(rlo);
2667 }
2668
2669 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */
2670 CHECK_FOR_FORK();
2671 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2672 CFRetain(rlo);
2673 __CFRunLoopObserverLock(rlo);
2674 if (__CFIsValid(rlo)) {
2675 CFRunLoopRef rl = rlo->_runLoop;
2676 __CFUnsetValid(rlo);
2677 __CFRunLoopObserverUnlock(rlo);
2678 if (NULL != rl) {
2679 CFArrayRef array;
2680 CFIndex idx;
2681 array = CFRunLoopCopyAllModes(rl);
2682 for (idx = CFArrayGetCount(array); idx--;) {
2683 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2684 CFRunLoopRemoveObserver(rl, rlo, modeName);
2685 }
2686 CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
2687 CFRelease(array);
2688 }
2689 if (rlo->_context.release)
2690 rlo->_context.release(rlo->_context.info); /* CALLOUT */
2691 rlo->_context.info = NULL;
2692 } else {
2693 __CFRunLoopObserverUnlock(rlo);
2694 }
2695 CFRelease(rlo);
2696 }
2697
2698 Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
2699 CHECK_FOR_FORK();
2700 return __CFIsValid(rlo);
2701 }
2702
2703 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
2704 CHECK_FOR_FORK();
2705 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2706 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2707 *context = rlo->_context;
2708 }
2709
2710 /* CFRunLoopTimer */
2711
2712 static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
2713 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
2714 CFStringRef result;
2715 CFStringRef contextDesc = NULL;
2716 int64_t fireTime;
2717 __CFRunLoopTimerFireTSRLock();
2718 fireTime = rlt->_fireTSR;
2719 __CFRunLoopTimerFireTSRUnlock();
2720 if (NULL != rlt->_context.copyDescription) {
2721 contextDesc = rlt->_context.copyDescription(rlt->_context.info);
2722 }
2723 if (NULL == contextDesc) {
2724 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
2725 }
2726 int64_t now2 = (int64_t)mach_absolute_time();
2727 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
2728 #if DEPLOYMENT_TARGET_MACOSX
2729 void *addr = rlt->_callout;
2730 Dl_info info;
2731 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
2732 result = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlt), lockCount(rlt->_lock) ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, name, addr, contextDesc);
2733 #else
2734 #error Unknown or unspecified DEPLOYMENT_TARGET
2735 #endif
2736 CFRelease(contextDesc);
2737 return result;
2738 }
2739
2740 static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2741 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
2742 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
2743 }
2744
2745 static const CFRuntimeClass __CFRunLoopTimerClass = {
2746 0,
2747 "CFRunLoopTimer",
2748 NULL, // init
2749 NULL, // copy
2750 __CFRunLoopTimerDeallocate,
2751 NULL, // equal
2752 NULL,
2753 NULL, //
2754 __CFRunLoopTimerCopyDescription
2755 };
2756
2757 __private_extern__ void __CFRunLoopTimerInitialize(void) {
2758 __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass);
2759 }
2760
2761 CFTypeID CFRunLoopTimerGetTypeID(void) {
2762 return __kCFRunLoopTimerTypeID;
2763 }
2764
2765 CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
2766 CHECK_FOR_FORK();
2767 CFRunLoopTimerRef memory;
2768 UInt32 size;
2769 size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
2770 memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL);
2771 if (NULL == memory) {
2772 return NULL;
2773 }
2774 __CFSetValid(memory);
2775 __CFRunLoopTimerUnsetFiring(memory);
2776 __CFRunLoopTimerUnsetDidFire(memory);
2777 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
2778 memory->_runLoop = NULL;
2779 memory->_rlCount = 0;
2780 #if DEPLOYMENT_TARGET_MACOSX
2781 memory->_port = MACH_PORT_NULL;
2782 #endif
2783 memory->_order = order;
2784 int64_t now2 = (int64_t)mach_absolute_time();
2785 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
2786 if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9;
2787 if (fireDate < now1) {
2788 memory->_fireTSR = now2;
2789 } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
2790 memory->_fireTSR = LLONG_MAX;
2791 } else {
2792 memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
2793 }
2794 if (3.1556952e+9 < interval) interval = 3.1556952e+9;
2795 if (interval <= 0.0) {
2796 memory->_intervalTSR = 0;
2797 } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) {
2798 memory->_intervalTSR = LLONG_MAX;
2799 } else {
2800 memory->_intervalTSR = __CFTimeIntervalToTSR(interval);
2801 }
2802 memory->_callout = callout;
2803 if (NULL != context) {
2804 if (context->retain) {
2805 memory->_context.info = (void *)context->retain(context->info);
2806 } else {
2807 memory->_context.info = context->info;
2808 }
2809 memory->_context.retain = context->retain;
2810 memory->_context.release = context->release;
2811 memory->_context.copyDescription = context->copyDescription;
2812 } else {
2813 memory->_context.info = 0;
2814 memory->_context.retain = 0;
2815 memory->_context.release = 0;
2816 memory->_context.copyDescription = 0;
2817 }
2818 return memory;
2819 }
2820
2821 CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
2822 CHECK_FOR_FORK();
2823 int64_t fireTime, result = 0;
2824 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime");
2825 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2826 __CFRunLoopTimerFireTSRLock();
2827 fireTime = rlt->_fireTSR;
2828 __CFRunLoopTimerFireTSRUnlock();
2829 __CFRunLoopTimerLock(rlt);
2830 if (__CFIsValid(rlt)) {
2831 result = fireTime;
2832 }
2833 __CFRunLoopTimerUnlock(rlt);
2834 int64_t now2 = (int64_t)mach_absolute_time();
2835 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
2836 return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2);
2837 }
2838
2839 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
2840 CHECK_FOR_FORK();
2841 __CFRunLoopTimerFireTSRLock();
2842 int64_t now2 = (int64_t)mach_absolute_time();
2843 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
2844 if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9;
2845 if (fireDate < now1) {
2846 rlt->_fireTSR = now2;
2847 } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
2848 rlt->_fireTSR = LLONG_MAX;
2849 } else {
2850 rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
2851 }
2852 if (rlt->_runLoop != NULL) {
2853 __CFRunLoopTimerRescheduleWithAllModes(rlt, rlt->_runLoop);
2854 }
2855 __CFRunLoopTimerFireTSRUnlock();
2856 }
2857
2858 CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
2859 CHECK_FOR_FORK();
2860 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval");
2861 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2862 return __CFTSRToTimeInterval(rlt->_intervalTSR);
2863 }
2864
2865 Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
2866 CHECK_FOR_FORK();
2867 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2868 return (0 != rlt->_intervalTSR);
2869 }
2870
2871 CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
2872 CHECK_FOR_FORK();
2873 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order");
2874 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2875 return rlt->_order;
2876 }
2877
2878 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
2879 CHECK_FOR_FORK();
2880 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate");
2881 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2882 CFRetain(rlt);
2883 __CFRunLoopTimerLock(rlt);
2884 if (__CFIsValid(rlt)) {
2885 CFRunLoopRef rl = rlt->_runLoop;
2886 void *info = rlt->_context.info;
2887 __CFUnsetValid(rlt);
2888 #if DEPLOYMENT_TARGET_MACOSX
2889 __CFRunLoopTimerPortMapLock();
2890 if (NULL != __CFRLTPortMap) {
2891 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port);
2892 }
2893 __CFRunLoopTimerPortMapUnlock();
2894 mk_timer_destroy(rlt->_port);
2895 rlt->_port = MACH_PORT_NULL;
2896 #endif
2897 rlt->_context.info = NULL;
2898 __CFRunLoopTimerUnlock(rlt);
2899 if (NULL != rl) {
2900 CFArrayRef array;
2901 CFIndex idx;
2902 array = CFRunLoopCopyAllModes(rl);
2903 for (idx = CFArrayGetCount(array); idx--;) {
2904 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2905 CFRunLoopRemoveTimer(rl, rlt, modeName);
2906 }
2907 CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
2908 CFRelease(array);
2909 }
2910 if (NULL != rlt->_context.release) {
2911 rlt->_context.release(info); /* CALLOUT */
2912 }
2913 } else {
2914 __CFRunLoopTimerUnlock(rlt);
2915 }
2916 CFRelease(rlt);
2917 }
2918
2919 Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
2920 CHECK_FOR_FORK();
2921 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid");
2922 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2923 return __CFIsValid(rlt);
2924 }
2925
2926 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
2927 CHECK_FOR_FORK();
2928 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2929 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2930 *context = rlt->_context;
2931 }
2932
2933 #endif
2934