]> git.saurik.com Git - apple/cf.git/blob - RunLoop.subproj/CFRunLoop.c
CF-299.tar.gz
[apple/cf.git] / RunLoop.subproj / CFRunLoop.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFRunLoop.c
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
28 */
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 <limits.h>
36 #if defined(__MACH__)
37 #include <mach/mach.h>
38 #include <mach/clock_types.h>
39 #include <mach/clock.h>
40 #else
41 #include <windows.h>
42 #endif
43
44 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey);
45
46 #if defined(__MACH__)
47 extern mach_port_name_t mk_timer_create(void);
48 extern kern_return_t mk_timer_destroy(mach_port_name_t name);
49 extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time);
50 extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time);
51
52 CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(int64_t x) {
53 AbsoluteTime a;
54 a.hi = x >> 32;
55 a.lo = x & (int64_t)0xFFFFFFFF;
56 return a;
57 }
58 #endif
59
60 #if defined(__MACH__)
61 static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) {
62 kern_return_t result;
63 mach_msg_header_t header;
64 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
65 header.msgh_size = sizeof(mach_msg_header_t);
66 header.msgh_remote_port = port;
67 header.msgh_local_port = MACH_PORT_NULL;
68 header.msgh_id = msg_id;
69 result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
70 return result;
71 }
72
73 static kern_return_t __CFClearPortSet(mach_port_t task, mach_port_t portSet) {
74 kern_return_t ret;
75 mach_port_name_array_t array;
76 mach_msg_type_number_t idx, number;
77
78 ret = mach_port_get_set_status(task, portSet, &array, &number);
79 if (KERN_SUCCESS != ret) return ret;
80 for (idx = 0; idx < number; idx++) {
81 ret = mach_port_extract_member(task, array[idx], portSet);
82 if (KERN_SUCCESS != ret) {
83 vm_deallocate(task, (vm_address_t)array, number * sizeof(mach_port_name_t));
84 return ret;
85 }
86 }
87 vm_deallocate(task, (vm_address_t)array, number * sizeof(mach_port_name_t));
88 return KERN_SUCCESS;
89 }
90 #endif
91
92 /* unlock a run loop and modes before doing callouts/sleeping */
93 /* never try to take the run loop lock with a mode locked */
94 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
95 /* run loop mode structures should never be deallocated, even if they become empty */
96
97 static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID;
98 static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID;
99 static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID;
100 static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID;
101 static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID;
102
103 typedef struct __CFRunLoopMode *CFRunLoopModeRef;
104
105 struct __CFRunLoopMode {
106 CFRuntimeBase _base;
107 CFSpinLock_t _lock; /* must have the run loop locked before locking this */
108 CFStringRef _name;
109 Boolean _stopped;
110 char _padding[3];
111 CFMutableSetRef _sources;
112 CFMutableSetRef _observers;
113 CFMutableSetRef _timers;
114 CFMutableArrayRef _submodes; // names of the submodes
115 #if defined(__MACH__)
116 mach_port_t _portSet;
117 #endif
118 #if defined(__WIN32__)
119 DWORD _msgQMask;
120 #endif
121 };
122
123 CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
124 __CFSpinLock(&(rlm->_lock));
125 }
126
127 CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
128 __CFSpinUnlock(&(rlm->_lock));
129 }
130
131 static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
132 CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
133 CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
134 return CFEqual(rlm1->_name, rlm2->_name);
135 }
136
137 static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
138 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
139 return CFHash(rlm->_name);
140 }
141
142 static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) {
143 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
144 CFMutableStringRef result;
145 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
146 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, rlm->_lock ? "true" : "false");
147 #if defined(__MACH__)
148 CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet);
149 #endif
150 #if defined(__WIN32__)
151 CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p,"), rlm->_msgQMask);
152 #endif
153 CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers);
154 return result;
155 }
156
157 static void __CFRunLoopModeDeallocate(CFTypeRef cf) {
158 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
159 if (NULL != rlm->_sources) CFRelease(rlm->_sources);
160 if (NULL != rlm->_observers) CFRelease(rlm->_observers);
161 if (NULL != rlm->_timers) CFRelease(rlm->_timers);
162 if (NULL != rlm->_submodes) CFRelease(rlm->_submodes);
163 CFRelease(rlm->_name);
164 #if defined(__MACH__)
165 __CFClearPortSet(mach_task_self(), rlm->_portSet);
166 mach_port_destroy(mach_task_self(), rlm->_portSet);
167 #endif
168 }
169
170 struct __CFRunLoop {
171 CFRuntimeBase _base;
172 CFSpinLock_t _lock; /* locked for accessing mode list */
173 #if defined(__MACH__)
174 mach_port_t _waitPort;
175 #endif
176 #if defined(__WIN32__)
177 HANDLE _waitPort;
178 #endif
179 volatile CFIndex *_stopped;
180 CFMutableSetRef _commonModes;
181 CFMutableSetRef _commonModeItems;
182 CFRunLoopModeRef _currentMode;
183 CFMutableSetRef _modes;
184 };
185
186 /* Bit 0 of the base reserved bits is used for stopped state */
187 /* Bit 1 of the base reserved bits is used for sleeping state */
188 /* Bit 2 of the base reserved bits is used for deallocating state */
189
190 CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
191 return (rl->_stopped && rl->_stopped[2]) ? true : false;
192 }
193
194 CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
195 if (rl->_stopped) rl->_stopped[2] = 0x53544F50; // 'STOP'
196 }
197
198 CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
199 if (rl->_stopped) rl->_stopped[2] = 0x0;
200 }
201
202 CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
203 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 1, 1);
204 }
205
206 CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
207 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 1);
208 }
209
210 CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
211 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 0);
212 }
213
214 CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
215 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 2, 2);
216 }
217
218 CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
219 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 2, 2, 1);
220 }
221
222 CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
223 __CFSpinLock(&(((CFRunLoopRef)rl)->_lock));
224 }
225
226 CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
227 __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock));
228 }
229
230 static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) {
231 CFRunLoopRef rl = (CFRunLoopRef)cf;
232 CFMutableStringRef result;
233 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
234 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), rl->_lock ? "true" : "false", rl->_waitPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)"));
235 CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
236 return result;
237 }
238
239 /* call with rl locked */
240 static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
241 CFRunLoopModeRef rlm;
242 struct __CFRunLoopMode srlm;
243 srlm._base._isa = __CFISAForTypeID(__kCFRunLoopModeTypeID);
244 srlm._base._info = 0;
245 _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID);
246 srlm._name = modeName;
247 rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
248 if (NULL != rlm) {
249 __CFRunLoopModeLock(rlm);
250 return rlm;
251 }
252 if (!create) {
253 return NULL;
254 }
255 rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(CFGetAllocator(rl), __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
256 if (NULL == rlm) {
257 return NULL;
258 }
259 rlm->_lock = 0;
260 rlm->_name = CFStringCreateCopy(CFGetAllocator(rlm), modeName);
261 rlm->_stopped = false;
262 rlm->_sources = NULL;
263 rlm->_observers = NULL;
264 rlm->_timers = NULL;
265 rlm->_submodes = NULL;
266 #if defined(__MACH__)
267 {
268 kern_return_t ret;
269 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &(rlm->_portSet));
270 if (KERN_SUCCESS == ret) {
271 ret = mach_port_insert_member(mach_task_self(), rl->_waitPort, rlm->_portSet);
272 }
273 if (KERN_SUCCESS != ret) HALT;
274 }
275 #endif
276 #if defined(__WIN32__)
277 rlm->_msgQMask = 0;
278 #endif
279 CFSetAddValue(rl->_modes, rlm);
280 CFRelease(rlm);
281 __CFRunLoopModeLock(rlm); /* return mode locked */
282 return rlm;
283 }
284
285 #if defined(__WIN32__)
286
287 // expects rl and rlm locked
288 static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
289 if (NULL == rlm) return true;
290 if (0 != rlm->_msgQMask) return false;
291 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false;
292 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false;
293 if (NULL != rlm->_submodes) {
294 CFIndex idx, cnt;
295 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
296 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
297 CFRunLoopModeRef subrlm;
298 Boolean subIsEmpty;
299 subrlm = __CFRunLoopFindMode(rl, modeName, false);
300 subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm) : true;
301 if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm);
302 if (!subIsEmpty) return false;
303 }
304 }
305 return true;
306 }
307
308 DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) {
309 CFRunLoopModeRef rlm;
310 DWORD result = 0;
311 __CFRunLoopLock(rl);
312 rlm = __CFRunLoopFindMode(rl, modeName, false);
313 if (rlm) {
314 result = rlm->_msgQMask;
315 __CFRunLoopModeUnlock(rlm);
316 }
317 __CFRunLoopUnlock(rl);
318 return result;
319 }
320
321 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) {
322 CFRunLoopModeRef rlm;
323 __CFRunLoopLock(rl);
324 rlm = __CFRunLoopFindMode(rl, modeName, true);
325 rlm->_msgQMask = mask;
326 __CFRunLoopModeUnlock(rlm);
327 __CFRunLoopUnlock(rl);
328 }
329
330 #else
331
332 // expects rl and rlm locked
333 static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
334 if (NULL == rlm) return true;
335 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false;
336 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false;
337 if (NULL != rlm->_submodes) {
338 CFIndex idx, cnt;
339 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
340 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
341 CFRunLoopModeRef subrlm;
342 Boolean subIsEmpty;
343 subrlm = __CFRunLoopFindMode(rl, modeName, false);
344 subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm) : true;
345 if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm);
346 if (!subIsEmpty) return false;
347 }
348 }
349 return true;
350 }
351
352 #endif
353
354 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
355
356 CF_INLINE Boolean __CFIsValid(const void *cf) {
357 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 3);
358 }
359
360 CF_INLINE void __CFSetValid(void *cf) {
361 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 1);
362 }
363
364 CF_INLINE void __CFUnsetValid(void *cf) {
365 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 0);
366 }
367
368 struct __CFRunLoopSource {
369 CFRuntimeBase _base;
370 uint32_t _bits;
371 CFSpinLock_t _lock;
372 CFIndex _order; /* immutable */
373 CFMutableBagRef _runLoops;
374 union {
375 CFRunLoopSourceContext version0; /* immutable, except invalidation */
376 #if defined(__MACH__)
377 CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
378 #endif
379 } _context;
380 };
381
382 /* Bit 1 of the base reserved bits is used for signaled state */
383
384 CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
385 return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
386 }
387
388 CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
389 __CFBitfieldSetValue(rls->_bits, 1, 1, 1);
390 }
391
392 CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
393 __CFBitfieldSetValue(rls->_bits, 1, 1, 0);
394 }
395
396 CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) {
397 __CFSpinLock(&(rls->_lock));
398 }
399
400 CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
401 __CFSpinUnlock(&(rls->_lock));
402 }
403
404 /* rlm is not locked */
405 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
406 __CFRunLoopSourceLock(rls);
407 if (NULL == rls->_runLoops) {
408 rls->_runLoops = CFBagCreateMutable(CFGetAllocator(rls), 0, NULL);
409 }
410 CFBagAddValue(rls->_runLoops, rl);
411 __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety
412 if (0 == rls->_context.version0.version) {
413 if (NULL != rls->_context.version0.schedule) {
414 rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name);
415 }
416 #if defined(__MACH__)
417 } else if (1 == rls->_context.version0.version) {
418 mach_port_t port;
419 port = rls->_context.version1.getPort(rls->_context.version1.info);
420 if (MACH_PORT_NULL != port) {
421 mach_port_insert_member(mach_task_self(), port, rlm->_portSet);
422 }
423 #endif
424 }
425 }
426
427 /* rlm is not locked */
428 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
429 if (0 == rls->_context.version0.version) {
430 if (NULL != rls->_context.version0.cancel) {
431 rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */
432 }
433 #if defined(__MACH__)
434 } else if (1 == rls->_context.version0.version) {
435 mach_port_t port;
436 port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
437 if (MACH_PORT_NULL != port) {
438 mach_port_extract_member(mach_task_self(), port, rlm->_portSet);
439 }
440 #endif
441 }
442 __CFRunLoopSourceLock(rls);
443 if (NULL != rls->_runLoops) {
444 CFBagRemoveValue(rls->_runLoops, rl);
445 }
446 __CFRunLoopSourceUnlock(rls);
447 }
448
449 struct __CFRunLoopObserver {
450 CFRuntimeBase _base;
451 CFSpinLock_t _lock;
452 CFRunLoopRef _runLoop;
453 CFIndex _rlCount;
454 CFOptionFlags _activities; /* immutable */
455 CFIndex _order; /* immutable */
456 CFRunLoopObserverCallBack _callout; /* immutable */
457 CFRunLoopObserverContext _context; /* immutable, except invalidation */
458 };
459
460 /* Bit 0 of the base reserved bits is used for firing state */
461 /* Bit 1 of the base reserved bits is used for repeats state */
462
463 CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
464 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_info, 0, 0);
465 }
466
467 CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
468 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 1);
469 }
470
471 CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
472 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 0);
473 }
474
475 CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
476 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_info, 1, 1);
477 }
478
479 CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
480 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 1);
481 }
482
483 CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
484 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 0);
485 }
486
487 CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
488 __CFSpinLock(&(rlo->_lock));
489 }
490
491 CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
492 __CFSpinUnlock(&(rlo->_lock));
493 }
494
495 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
496 __CFRunLoopObserverLock(rlo);
497 if (0 == rlo->_rlCount) {
498 rlo->_runLoop = rl;
499 }
500 rlo->_rlCount++;
501 __CFRunLoopObserverUnlock(rlo);
502 }
503
504 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
505 __CFRunLoopObserverLock(rlo);
506 rlo->_rlCount--;
507 if (0 == rlo->_rlCount) {
508 rlo->_runLoop = NULL;
509 }
510 __CFRunLoopObserverUnlock(rlo);
511 }
512
513 struct __CFRunLoopTimer {
514 CFRuntimeBase _base;
515 CFSpinLock_t _lock;
516 CFRunLoopRef _runLoop;
517 CFIndex _rlCount;
518 #if defined(__MACH__)
519 mach_port_name_t _port;
520 #endif
521 CFIndex _order; /* immutable */
522 int64_t _fireTSR; /* TSR units */
523 int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */
524 CFRunLoopTimerCallBack _callout; /* immutable */
525 CFRunLoopTimerContext _context; /* immutable, except invalidation */
526 };
527
528 /* Bit 0 of the base reserved bits is used for firing state */
529 /* Bit 1 of the base reserved bits is used for has-reset state */
530
531 CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
532 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_info, 0, 0);
533 }
534
535 CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
536 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 1);
537 }
538
539 CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
540 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 0);
541 }
542
543 CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
544 __CFSpinLock(&(rlt->_lock));
545 }
546
547 CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
548 __CFSpinUnlock(&(rlt->_lock));
549 }
550
551 static CFSpinLock_t __CFRLTFireTSRLock = 0;
552
553 CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
554 __CFSpinLock(&__CFRLTFireTSRLock);
555 }
556
557 CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
558 __CFSpinUnlock(&__CFRLTFireTSRLock);
559 }
560
561 static CFMutableDictionaryRef __CFRLTPortMap = NULL;
562 static CFSpinLock_t __CFRLTPortMapLock = 0;
563
564 CF_INLINE void __CFRunLoopTimerPortMapLock(void) {
565 __CFSpinLock(&__CFRLTPortMapLock);
566 }
567
568 CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) {
569 __CFSpinUnlock(&__CFRLTPortMapLock);
570 }
571
572 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
573 #if defined(__MACH__)
574 __CFRunLoopTimerLock(rlt);
575 if (0 == rlt->_rlCount) {
576 rlt->_runLoop = rl;
577 if (MACH_PORT_NULL == rlt->_port) {
578 rlt->_port = mk_timer_create();
579 }
580 __CFRunLoopTimerPortMapLock();
581 if (NULL == __CFRLTPortMap) {
582 __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
583 }
584 CFDictionarySetValue(__CFRLTPortMap, (void *)rlt->_port, rlt);
585 __CFRunLoopTimerPortMapUnlock();
586 }
587 rlt->_rlCount++;
588 mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet);
589 mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
590 __CFRunLoopTimerUnlock(rlt);
591 #endif
592 }
593
594 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
595 #if defined(__MACH__)
596 __CFRunLoopTimerLock(rlt);
597 mach_port_extract_member(mach_task_self(), rlt->_port, rlm->_portSet);
598 rlt->_rlCount--;
599 if (0 == rlt->_rlCount) {
600 __CFRunLoopTimerPortMapLock();
601 if (NULL != __CFRLTPortMap) {
602 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port);
603 }
604 __CFRunLoopTimerPortMapUnlock();
605 rlt->_runLoop = NULL;
606 mk_timer_cancel(rlt->_port, NULL);
607 }
608 __CFRunLoopTimerUnlock(rlt);
609 #endif
610 }
611
612 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt, CFRunLoopRef rl) {
613 #if defined(__MACH__)
614 mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
615 #endif
616 }
617
618
619 /* CFRunLoop */
620
621 CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
622 CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
623
624 #if defined(__MACH__)
625
626 struct _findsource {
627 mach_port_t port;
628 CFRunLoopSourceRef result;
629 };
630
631 static void __CFRunLoopFindSource(const void *value, void *ctx) {
632 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
633 struct _findsource *context = (struct _findsource *)ctx;
634 mach_port_t port;
635 if (NULL != context->result) return;
636 if (1 != rls->_context.version0.version) return;
637 __CFRunLoopSourceLock(rls);
638 port = rls->_context.version1.getPort(rls->_context.version1.info);
639 if (port == context->port) {
640 context->result = rls;
641 }
642 __CFRunLoopSourceUnlock(rls);
643 }
644
645 // call with rl and rlm locked
646 static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, mach_port_t port) { /* DOES CALLOUT */
647 struct _findsource context = {port, NULL};
648 if (NULL != rlm->_sources) {
649 CFSetApplyFunction(rlm->_sources, (__CFRunLoopFindSource), &context);
650 }
651 if (NULL == context.result && NULL != rlm->_submodes) {
652 CFIndex idx, cnt;
653 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
654 CFRunLoopSourceRef source = NULL;
655 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
656 CFRunLoopModeRef subrlm;
657 subrlm = __CFRunLoopFindMode(rl, modeName, false);
658 if (NULL != subrlm) {
659 source = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port);
660 __CFRunLoopModeUnlock(subrlm);
661 }
662 if (NULL != source) {
663 context.result = source;
664 break;
665 }
666 }
667 }
668 return context.result;
669 }
670
671 // call with rl and rlm locked
672 static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, mach_port_name_t port) {
673 CFRunLoopTimerRef result = NULL;
674 __CFRunLoopTimerPortMapLock();
675 if (NULL != __CFRLTPortMap) {
676 result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)port);
677 }
678 __CFRunLoopTimerPortMapUnlock();
679 return result;
680 }
681 #endif
682
683 static void __CFRunLoopDeallocateSources(const void *value, void *context) {
684 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
685 CFRunLoopRef rl = (CFRunLoopRef)context;
686 CFIndex idx, cnt;
687 const void **list, *buffer[256];
688 if (NULL == rlm->_sources) return;
689 cnt = CFSetGetCount(rlm->_sources);
690 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
691 CFSetGetValues(rlm->_sources, list);
692 for (idx = 0; idx < cnt; idx++) {
693 CFRetain(list[idx]);
694 }
695 CFSetRemoveAllValues(rlm->_sources);
696 for (idx = 0; idx < cnt; idx++) {
697 __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm);
698 CFRelease(list[idx]);
699 }
700 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
701 }
702
703 static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
704 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
705 CFRunLoopRef rl = (CFRunLoopRef)context;
706 CFIndex idx, cnt;
707 const void **list, *buffer[256];
708 if (NULL == rlm->_observers) return;
709 cnt = CFSetGetCount(rlm->_observers);
710 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
711 CFSetGetValues(rlm->_observers, list);
712 for (idx = 0; idx < cnt; idx++) {
713 CFRetain(list[idx]);
714 }
715 CFSetRemoveAllValues(rlm->_observers);
716 for (idx = 0; idx < cnt; idx++) {
717 __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm);
718 CFRelease(list[idx]);
719 }
720 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
721 }
722
723 static void __CFRunLoopDeallocateTimers(const void *value, void *context) {
724 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
725 CFRunLoopRef rl = (CFRunLoopRef)context;
726 CFIndex idx, cnt;
727 const void **list, *buffer[256];
728 if (NULL == rlm->_timers) return;
729 cnt = CFSetGetCount(rlm->_timers);
730 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
731 CFSetGetValues(rlm->_timers, list);
732 for (idx = 0; idx < cnt; idx++) {
733 CFRetain(list[idx]);
734 }
735 CFSetRemoveAllValues(rlm->_timers);
736 for (idx = 0; idx < cnt; idx++) {
737 __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm);
738 CFRelease(list[idx]);
739 }
740 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
741 }
742
743 static void __CFRunLoopDeallocate(CFTypeRef cf) {
744 CFRunLoopRef rl = (CFRunLoopRef)cf;
745 /* We try to keep the run loop in a valid state as long as possible,
746 since sources may have non-retained references to the run loop.
747 Another reason is that we don't want to lock the run loop for
748 callback reasons, if we can get away without that. We start by
749 eliminating the sources, since they are the most likely to call
750 back into the run loop during their "cancellation". Common mode
751 items will be removed from the mode indirectly by the following
752 three lines. */
753 __CFRunLoopSetDeallocating(rl);
754 if (NULL != rl->_modes) {
755 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
756 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
757 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
758 }
759 __CFRunLoopLock(rl);
760 if (NULL != rl->_commonModeItems) {
761 CFRelease(rl->_commonModeItems);
762 }
763 if (NULL != rl->_commonModes) {
764 CFRelease(rl->_commonModes);
765 }
766 if (NULL != rl->_modes) {
767 CFRelease(rl->_modes);
768 }
769 #if defined(__MACH__)
770 mach_port_destroy(mach_task_self(), rl->_waitPort);
771 rl->_waitPort = 0;
772 #endif
773 #if defined(__WIN32__)
774 CloseHandle(rl->_waitPort);
775 rl->_waitPort = 0;
776 #endif
777 __CFRunLoopUnlock(rl);
778 }
779
780 static const CFRuntimeClass __CFRunLoopModeClass = {
781 0,
782 "CFRunLoopMode",
783 NULL, // init
784 NULL, // copy
785 __CFRunLoopModeDeallocate,
786 __CFRunLoopModeEqual,
787 __CFRunLoopModeHash,
788 NULL, //
789 __CFRunLoopModeCopyDescription
790 };
791
792 static const CFRuntimeClass __CFRunLoopClass = {
793 0,
794 "CFRunLoop",
795 NULL, // init
796 NULL, // copy
797 __CFRunLoopDeallocate,
798 NULL,
799 NULL,
800 NULL, //
801 __CFRunLoopCopyDescription
802 };
803
804 __private_extern__ void __CFRunLoopInitialize(void) {
805 __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);
806 __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass);
807 }
808
809 CFTypeID CFRunLoopGetTypeID(void) {
810 return __kCFRunLoopTypeID;
811 }
812
813 static CFRunLoopRef __CFRunLoopCreate(void) {
814 CFRunLoopRef loop = NULL;
815 CFRunLoopModeRef rlm;
816 uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
817 loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL);
818 if (NULL == loop) {
819 return NULL;
820 }
821 loop->_stopped = NULL;
822 loop->_lock = 0;
823 #if defined(__MACH__)
824 {
825 kern_return_t ret;
826 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &(loop->_waitPort));
827 if (KERN_SUCCESS == ret) {
828 ret = mach_port_insert_right(mach_task_self(), loop->_waitPort, loop->_waitPort, MACH_MSG_TYPE_MAKE_SEND);
829 }
830 if (KERN_SUCCESS == ret) {
831 mach_port_limits_t limits;
832 limits.mpl_qlimit = 1;
833 ret = mach_port_set_attributes(mach_task_self(), loop->_waitPort, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT);
834 }
835 if (KERN_SUCCESS != ret) HALT;
836 }
837 #elif defined(__WIN32__)
838 loop->_waitPort = CreateEvent(NULL, true, false, NULL);
839 #endif
840 loop->_commonModes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
841 CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
842 loop->_commonModeItems = NULL;
843 loop->_currentMode = NULL;
844 loop->_modes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
845 _CFSetSetCapacity(loop->_modes, 10);
846 rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
847 if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
848 return loop;
849 }
850
851 static CFRunLoopRef mainLoop = NULL;
852 static int mainLoopPid = 0;
853 static CFSpinLock_t mainLoopLock = 0;
854
855 CFRunLoopRef CFRunLoopGetMain(void) {
856 __CFSpinLock(&mainLoopLock);
857 if (mainLoopPid != getpid()) {
858 // intentionally leak mainLoop so we don't kill any ports in the child
859 mainLoop = NULL;
860 }
861 if (!mainLoop) {
862 mainLoop = __CFRunLoopCreate();
863 mainLoopPid = getpid();
864 }
865 __CFSpinUnlock(&mainLoopLock);
866 return mainLoop;
867 }
868
869 static void _CFRunLoopSetMain(CFRunLoopRef rl) {
870 if (rl != mainLoop) {
871 if (rl) CFRetain(rl);
872 // intentionally leak the old main run loop
873 // if (mainLoop) CFRelease(mainLoop);
874 mainLoop = rl;
875 }
876 }
877
878 CFRunLoopRef CFRunLoopGetCurrent(void) {
879 if (pthread_main_np()) {
880 return CFRunLoopGetMain();
881 }
882 CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop;
883 int currentLoopPid = __CFGetThreadSpecificData_inline()->_runLoop_pid;
884 if (currentLoopPid != getpid()) {
885 // intentionally leak currentLoop so we don't kill any ports in the child
886 currentLoop = NULL;
887 }
888 if (!currentLoop) {
889 currentLoop = __CFRunLoopCreate();
890 __CFGetThreadSpecificData_inline()->_runLoop = currentLoop;
891 __CFGetThreadSpecificData_inline()->_runLoop_pid = getpid();
892 }
893 return currentLoop;
894 }
895
896 void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
897 if (pthread_main_np()) {
898 return _CFRunLoopSetMain(rl);
899 }
900 CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop;
901 if (rl != currentLoop) {
902 if (rl) CFRetain(rl);
903 // intentionally leak old run loop
904 // if (currentLoop) CFRelease(currentLoop);
905 __CFGetThreadSpecificData_inline()->_runLoop = rl;
906 __CFGetThreadSpecificData_inline()->_runLoop_pid = getpid();
907 }
908 }
909
910 CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
911 CFStringRef result = NULL;
912 __CFRunLoopLock(rl);
913 if (NULL != rl->_currentMode) {
914 result = CFRetain(rl->_currentMode->_name);
915 }
916 __CFRunLoopUnlock(rl);
917 return result;
918 }
919
920 static void __CFRunLoopGetModeName(const void *value, void *context) {
921 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
922 CFMutableArrayRef array = (CFMutableArrayRef)context;
923 CFArrayAppendValue(array, rlm->_name);
924 }
925
926 CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) {
927 CFMutableArrayRef array;
928 __CFRunLoopLock(rl);
929 array = CFArrayCreateMutable(kCFAllocatorDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks);
930 CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array);
931 __CFRunLoopUnlock(rl);
932 return array;
933 }
934
935 static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
936 CFTypeRef item = (CFTypeRef)value;
937 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
938 CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
939 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
940 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
941 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
942 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
943 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
944 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
945 }
946 }
947
948 static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
949 CFStringRef modeName = (CFStringRef)value;
950 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
951 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
952 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
953 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
954 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
955 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
956 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
957 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
958 }
959 }
960
961 static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
962 CFStringRef modeName = (CFStringRef)value;
963 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
964 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
965 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
966 CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
967 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
968 CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
969 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
970 CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
971 }
972 }
973
974 void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
975 if (__CFRunLoopIsDeallocating(rl)) return;
976 __CFRunLoopLock(rl);
977 if (!CFSetContainsValue(rl->_commonModes, modeName)) {
978 CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
979 CFSetAddValue(rl->_commonModes, modeName);
980 __CFRunLoopUnlock(rl);
981 if (NULL != set) {
982 CFTypeRef context[2] = {rl, modeName};
983 /* add all common-modes items to new mode */
984 CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
985 CFRelease(set);
986 }
987 } else {
988 __CFRunLoopUnlock(rl);
989 }
990 }
991
992 static CFComparisonResult __CFRunLoopObserverComparator(const void *val1, const void *val2, void *context) {
993 CFRunLoopObserverRef o1 = (CFRunLoopObserverRef)val1;
994 CFRunLoopObserverRef o2 = (CFRunLoopObserverRef)val2;
995 if (o1->_order < o2->_order) return kCFCompareLessThan;
996 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
997 return kCFCompareEqualTo;
998 }
999
1000 struct _collectobs {
1001 CFRunLoopActivity activity;
1002 CFMutableArrayRef array;
1003 };
1004
1005 static void __CFRunLoopCollectObservers(const void *value, void *context) {
1006 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)value;
1007 struct _collectobs *info = (struct _collectobs *)context;
1008 if (0 != (rlo->_activities & info->activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
1009 CFArrayAppendValue(info->array, rlo);
1010 }
1011 }
1012
1013 /* rl is unlocked, rlm is locked on entrance and exit */
1014 /* ALERT: this should collect all the candidate observers from the top level
1015 * and all submodes, recursively, THEN start calling them, in order to obey
1016 * the ordering parameter. */
1017 static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
1018 CFIndex idx, cnt;
1019 CFMutableArrayRef array;
1020 CFArrayRef submodes;
1021 struct _collectobs info;
1022
1023 /* Fire the observers */
1024 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
1025 if (NULL != rlm->_observers) {
1026 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rlm->_observers), &kCFTypeArrayCallBacks);
1027 info.array = array;
1028 info.activity = activity;
1029 CFSetApplyFunction(rlm->_observers, (__CFRunLoopCollectObservers), &info);
1030 cnt = CFArrayGetCount(array);
1031 if (0 < cnt) {
1032 __CFRunLoopModeUnlock(rlm);
1033 CFArraySortValues(array, CFRangeMake(0, cnt), (__CFRunLoopObserverComparator), NULL);
1034 for (idx = 0; idx < cnt; idx++) {
1035 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(array, idx);
1036 __CFRunLoopObserverLock(rlo);
1037 if (__CFIsValid(rlo)) {
1038 __CFRunLoopObserverUnlock(rlo);
1039 __CFRunLoopObserverSetFiring(rlo);
1040 rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */
1041 __CFRunLoopObserverUnsetFiring(rlo);
1042 if (!__CFRunLoopObserverRepeats(rlo)) {
1043 CFRunLoopObserverInvalidate(rlo);
1044 }
1045 } else {
1046 __CFRunLoopObserverUnlock(rlo);
1047 }
1048 }
1049 __CFRunLoopModeLock(rlm);
1050 }
1051 CFRelease(array);
1052 }
1053 if (NULL != submodes) {
1054 __CFRunLoopModeUnlock(rlm);
1055 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
1056 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
1057 CFRunLoopModeRef subrlm;
1058 __CFRunLoopLock(rl);
1059 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1060 __CFRunLoopUnlock(rl);
1061 if (NULL != subrlm) {
1062 __CFRunLoopDoObservers(rl, subrlm, activity);
1063 __CFRunLoopModeUnlock(subrlm);
1064 }
1065 }
1066 CFRelease(submodes);
1067 __CFRunLoopModeLock(rlm);
1068 }
1069 }
1070
1071 static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) {
1072 CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1;
1073 CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2;
1074 if (o1->_order < o2->_order) return kCFCompareLessThan;
1075 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
1076 return kCFCompareEqualTo;
1077 }
1078
1079 static void __CFRunLoopCollectSources0(const void *value, void *context) {
1080 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
1081 CFTypeRef *sources = (CFTypeRef *)context;
1082 if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) {
1083 if (NULL == *sources) {
1084 *sources = CFRetain(rls);
1085 } else if (CFGetTypeID(*sources) == __kCFRunLoopSourceTypeID) {
1086 CFTypeRef oldrls = *sources;
1087 *sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1088 CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls);
1089 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1090 CFRelease(oldrls);
1091 } else {
1092 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1093 }
1094 }
1095 }
1096
1097 /* rl is unlocked, rlm is locked on entrance and exit */
1098 static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */
1099 CFTypeRef sources = NULL;
1100 Boolean sourceHandled = false;
1101 CFIndex idx, cnt;
1102
1103 __CFRunLoopModeUnlock(rlm); // locks have to be taken in order
1104 __CFRunLoopLock(rl);
1105 __CFRunLoopModeLock(rlm);
1106 /* Fire the version 0 sources */
1107 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) {
1108 CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources);
1109 }
1110 for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1111 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1112 CFRunLoopModeRef subrlm;
1113 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1114 if (NULL != subrlm) {
1115 if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) {
1116 CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources);
1117 }
1118 __CFRunLoopModeUnlock(subrlm);
1119 }
1120 }
1121 __CFRunLoopUnlock(rl);
1122 if (NULL != sources) {
1123 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1124 __CFRunLoopModeUnlock(rlm);
1125 if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) {
1126 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
1127 __CFRunLoopSourceLock(rls);
1128 __CFRunLoopSourceUnsetSignaled(rls);
1129 if (__CFIsValid(rls)) {
1130 __CFRunLoopSourceUnlock(rls);
1131 if (NULL != rls->_context.version0.perform) {
1132 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1133 }
1134 sourceHandled = true;
1135 } else {
1136 __CFRunLoopSourceUnlock(rls);
1137 }
1138 } else {
1139 cnt = CFArrayGetCount(sources);
1140 CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
1141 for (idx = 0; idx < cnt; idx++) {
1142 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, idx);
1143 __CFRunLoopSourceLock(rls);
1144 __CFRunLoopSourceUnsetSignaled(rls);
1145 if (__CFIsValid(rls)) {
1146 __CFRunLoopSourceUnlock(rls);
1147 if (NULL != rls->_context.version0.perform) {
1148 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1149 }
1150 sourceHandled = true;
1151 } else {
1152 __CFRunLoopSourceUnlock(rls);
1153 }
1154 if (stopAfterHandle && sourceHandled) {
1155 break;
1156 }
1157 }
1158 }
1159 CFRelease(sources);
1160 __CFRunLoopModeLock(rlm);
1161 }
1162 return sourceHandled;
1163 }
1164
1165 #if defined(__MACH__)
1166 static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls, mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply) { /* DOES CALLOUT */
1167 Boolean sourceHandled = false;
1168
1169 /* Fire a version 1 source */
1170 CFRetain(rls);
1171 __CFRunLoopModeUnlock(rlm);
1172 __CFRunLoopSourceLock(rls);
1173 if (__CFIsValid(rls)) {
1174 __CFRunLoopSourceUnsetSignaled(rls);
1175 __CFRunLoopSourceUnlock(rls);
1176 if (NULL != rls->_context.version1.perform) {
1177 *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */
1178 }
1179 sourceHandled = true;
1180 } else {
1181 __CFRunLoopSourceUnlock(rls);
1182 }
1183 CFRelease(rls);
1184 __CFRunLoopModeLock(rlm);
1185 return sourceHandled;
1186 }
1187 #endif
1188
1189 static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
1190 Boolean timerHandled = false;
1191 int64_t oldFireTSR = 0;
1192
1193 /* Fire a timer */
1194 CFRetain(rlt);
1195 __CFRunLoopModeUnlock(rlm);
1196 __CFRunLoopTimerLock(rlt);
1197 if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
1198 __CFRunLoopTimerSetFiring(rlt);
1199 __CFRunLoopTimerUnlock(rlt);
1200 __CFRunLoopTimerFireTSRLock();
1201 oldFireTSR = rlt->_fireTSR;
1202 __CFRunLoopTimerFireTSRUnlock();
1203 rlt->_callout(rlt, rlt->_context.info); /* CALLOUT */
1204 __CFRunLoopTimerUnsetFiring(rlt);
1205 timerHandled = true;
1206 } else {
1207 __CFRunLoopTimerUnlock(rlt);
1208 }
1209 if (__CFIsValid(rlt) && timerHandled) {
1210 if (0 == rlt->_intervalTSR) {
1211 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
1212 } else {
1213 /* This is just a little bit tricky: we want to support calling
1214 * CFRunLoopTimerSetNextFireDate() from within the callout and
1215 * honor that new time here if it is a later date, otherwise
1216 * it is completely ignored. */
1217 int64_t currentFireTSR;
1218 __CFRunLoopTimerFireTSRLock();
1219 currentFireTSR = rlt->_fireTSR;
1220 if (oldFireTSR < currentFireTSR) {
1221 /* Next fire TSR was set, and set to a date after the previous
1222 * fire date, so we honor it. */
1223 } else {
1224 if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) {
1225 currentFireTSR = LLONG_MAX;
1226 } else {
1227 int64_t currentTSR = (int64_t)__CFReadTSR();
1228 currentFireTSR = oldFireTSR;
1229 while (currentFireTSR <= currentTSR) {
1230 currentFireTSR += rlt->_intervalTSR;
1231 }
1232 }
1233 }
1234 rlt->_fireTSR = currentFireTSR;
1235 __CFRunLoopTimerFireTSRUnlock();
1236 __CFRunLoopTimerRescheduleWithAllModes(rlt, rl);
1237 }
1238 }
1239 CFRelease(rlt);
1240 __CFRunLoopModeLock(rlm);
1241 return timerHandled;
1242 }
1243
1244 CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
1245 CFRunLoopModeRef rlm;
1246 Boolean result = false;
1247 __CFRunLoopLock(rl);
1248 rlm = __CFRunLoopFindMode(rl, modeName, false);
1249 if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm)) {
1250 result = true;
1251 }
1252 __CFRunLoopUnlock(rl);
1253 if (rlm) __CFRunLoopModeUnlock(rlm);
1254 return result;
1255 }
1256
1257 // rl is locked, rlm is locked on entry and exit
1258 #if defined(__MACH__)
1259 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, mach_port_t portSet) {
1260 CFIndex idx, cnt;
1261 const void **list, *buffer[256];
1262
1263 // Timers and version 1 sources go into the portSet currently
1264 if (NULL != rlm->_sources) {
1265 cnt = CFSetGetCount(rlm->_sources);
1266 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
1267 CFSetGetValues(rlm->_sources, list);
1268 for (idx = 0; idx < cnt; idx++) {
1269 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
1270 mach_port_t port;
1271 if (1 != rls->_context.version0.version) continue;
1272 port = rls->_context.version1.getPort(rls->_context.version1.info);
1273 if (MACH_PORT_NULL != port) {
1274 mach_port_insert_member(mach_task_self(), port, portSet);
1275 }
1276 }
1277 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1278 }
1279 if (NULL != rlm->_timers) {
1280 cnt = CFSetGetCount(rlm->_timers);
1281 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
1282 CFSetGetValues(rlm->_timers, list);
1283 for (idx = 0; idx < cnt; idx++) {
1284 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx];
1285 if (MACH_PORT_NULL != rlt->_port) {
1286 mach_port_insert_member(mach_task_self(), rlt->_port, portSet);
1287 }
1288 }
1289 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1290 }
1291 // iterate over submodes
1292 for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1293 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1294 CFRunLoopModeRef subrlm;
1295 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1296 if (NULL != subrlm) {
1297 __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet);
1298 __CFRunLoopModeUnlock(subrlm);
1299 }
1300 }
1301 }
1302 #endif
1303
1304 /* rl is unlocked, rlm locked on entrance and exit */
1305 static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, Boolean waitIfEmpty) { /* DOES CALLOUT */
1306 int64_t termTSR;
1307 #if defined(__MACH__)
1308 mach_port_name_t timeoutPort = MACH_PORT_NULL;
1309 Boolean timeoutPortAdded = false;
1310 #elif defined(__WIN32__)
1311 HANDLE timeoutPort = NULL;
1312 #endif
1313 Boolean poll = false;
1314
1315 if (__CFRunLoopIsStopped(rl)) {
1316 return kCFRunLoopRunStopped;
1317 } else if (rlm->_stopped) {
1318 rlm->_stopped = false;
1319 return kCFRunLoopRunStopped;
1320 }
1321 #if !defined(__WIN32__)
1322 if (seconds <= 0.0) {
1323 termTSR = 0;
1324 } else if (__CFTSRToTimeInterval(LLONG_MAX) < seconds) {
1325 termTSR = LLONG_MAX;
1326 } else if ((uint64_t)LLONG_MAX <= __CFReadTSR() + (uint64_t)__CFTimeIntervalToTSR(seconds)) {
1327 termTSR = LLONG_MAX;
1328 } else {
1329 termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds);
1330 timeoutPort = mk_timer_create();
1331 mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR));
1332 }
1333 #elif defined(__WIN32__)
1334 {
1335 //int64_t time = (int64_t)(seconds * -10000000.0);
1336 //timeoutPort = CreateWaitableTimer(NULL,FALSE,NULL);
1337 //SetWaitableTimer(rl->_waitPort, &time, 0, NULL, NULL);
1338 }
1339 #endif
1340 if (seconds <= 0.0) {
1341 poll = true;
1342 }
1343 for (;;) {
1344 #if defined(__MACH__)
1345 mach_msg_header_t *msg;
1346 kern_return_t ret;
1347 mach_port_t waitSet = MACH_PORT_NULL;
1348 Boolean destroyWaitSet = false;
1349 #endif
1350 CFRunLoopSourceRef rls;
1351 int32_t returnValue = 0;
1352 Boolean sourceHandledThisLoop = false;
1353 uint8_t buffer[1024 + 80]; // large enough for 1k of inline payload
1354
1355 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
1356 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
1357
1358 sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
1359
1360 if (sourceHandledThisLoop) {
1361 poll = true;
1362 }
1363
1364 if (!poll) {
1365 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
1366 __CFRunLoopSetSleeping(rl);
1367 }
1368 #if defined(__MACH__)
1369 if (NULL != rlm->_submodes) {
1370 // !!! what do we do if this doesn't succeed?
1371 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &waitSet);
1372 if (KERN_SUCCESS != ret) HALT;
1373 __CFRunLoopModeUnlock(rlm);
1374 __CFRunLoopLock(rl);
1375 __CFRunLoopModeLock(rlm);
1376 __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet);
1377 __CFRunLoopUnlock(rl);
1378 if (MACH_PORT_NULL != timeoutPort) {
1379 mach_port_insert_member(mach_task_self(), timeoutPort, waitSet);
1380 }
1381 destroyWaitSet = true;
1382 } else {
1383 waitSet = rlm->_portSet;
1384 if (!timeoutPortAdded && MACH_PORT_NULL != timeoutPort) {
1385 mach_port_insert_member(mach_task_self(), timeoutPort, waitSet);
1386 timeoutPortAdded = true;
1387 }
1388 }
1389 __CFRunLoopModeUnlock(rlm);
1390
1391 msg = (mach_msg_header_t *)buffer;
1392 msg->msgh_size = sizeof(buffer);
1393
1394 /* In that sleep of death what nightmares may come ... */
1395 try_receive:
1396 msg->msgh_bits = 0;
1397 msg->msgh_local_port = waitSet;
1398 msg->msgh_remote_port = MACH_PORT_NULL;
1399 msg->msgh_id = 0;
1400 #if defined(MACH_RCV_TRAILER_AUDIT)
1401 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);
1402 #else
1403 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_SENDER), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL);
1404 #endif
1405 if (MACH_RCV_TOO_LARGE == ret) {
1406 #if defined(MACH_RCV_TRAILER_AUDIT)
1407 uint32_t newSize = round_msg(msg->msgh_size) + sizeof(mach_msg_audit_trailer_t);
1408 #else
1409 uint32_t newSize = round_msg(msg->msgh_size) + sizeof(mach_msg_security_trailer_t);
1410 #endif
1411 if (msg == (mach_msg_header_t *)buffer) msg = NULL;
1412 msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0);
1413 msg->msgh_size = newSize;
1414 goto try_receive;
1415 } else if (MACH_RCV_TIMED_OUT == ret) {
1416 // timeout, for poll
1417 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
1418 msg = NULL;
1419 } else if (MACH_MSG_SUCCESS != ret) {
1420 HALT;
1421 }
1422 #elif defined(__WIN32__)
1423 // should msgQMask be an OR'ing of this and all submodes' masks?
1424 if (0 == GetQueueStatus(rlm->_msgQMask)) {
1425 HANDLE objects[2];
1426 objects[0] = rl->_waitPort;
1427 //objects[1] = timeoutPort;
1428 MsgWaitForMultipleObjects(1 /*1*/, objects /*&(rl->_waitPort)*/, false, seconds, rlm->_msgQMask);
1429 }
1430 ResetEvent(rl->_waitPort);
1431 #endif
1432
1433 #if defined(__MACH__)
1434 if (destroyWaitSet) {
1435 __CFClearPortSet(mach_task_self(), waitSet);
1436 mach_port_destroy(mach_task_self(), waitSet);
1437 }
1438 #endif
1439 __CFRunLoopLock(rl);
1440 __CFRunLoopModeLock(rlm);
1441 __CFRunLoopUnlock(rl);
1442 if (!poll) {
1443 __CFRunLoopUnsetSleeping(rl);
1444 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
1445 }
1446 poll = false;
1447 __CFRunLoopModeUnlock(rlm);
1448 __CFRunLoopLock(rl);
1449 __CFRunLoopModeLock(rlm);
1450
1451 #if defined(__MACH__)
1452 if (NULL != msg) {
1453 if (msg->msgh_local_port == timeoutPort) {
1454 returnValue = kCFRunLoopRunTimedOut;
1455 __CFRunLoopUnlock(rl);
1456 } else if (msg->msgh_local_port == rl->_waitPort) {
1457 // wakeup
1458 __CFRunLoopUnlock(rl);
1459 } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, msg->msgh_local_port))) {
1460 mach_msg_header_t *reply = NULL;
1461 __CFRunLoopUnlock(rl);
1462 if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) {
1463 sourceHandledThisLoop = true;
1464 }
1465 if (NULL != reply) {
1466 ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
1467 //#warning CF: what should be done with the return value?
1468 CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
1469 }
1470 } else {
1471 CFRunLoopTimerRef rlt;
1472 rlt = __CFRunLoopModeFindTimerForMachPort(rlm, msg->msgh_local_port);
1473 __CFRunLoopUnlock(rl);
1474 if (NULL != rlt) {
1475 __CFRunLoopDoTimer(rl, rlm, rlt);
1476 }
1477 }
1478 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
1479 } else {
1480 __CFRunLoopUnlock(rl);
1481 }
1482 #endif
1483
1484 __CFRunLoopModeUnlock(rlm); // locks must be taken in order
1485 __CFRunLoopLock(rl);
1486 __CFRunLoopModeLock(rlm);
1487 if (sourceHandledThisLoop && stopAfterHandle) {
1488 returnValue = kCFRunLoopRunHandledSource;
1489 } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) {
1490 returnValue = kCFRunLoopRunTimedOut;
1491 } else if (__CFRunLoopIsStopped(rl)) {
1492 returnValue = kCFRunLoopRunStopped;
1493 } else if (rlm->_stopped) {
1494 rlm->_stopped = false;
1495 returnValue = kCFRunLoopRunStopped;
1496 } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm)) {
1497 returnValue = kCFRunLoopRunFinished;
1498 }
1499 __CFRunLoopUnlock(rl);
1500 if (0 != returnValue) {
1501 #if defined(__MACH__)
1502 if (MACH_PORT_NULL != timeoutPort) {
1503 if (!destroyWaitSet) mach_port_extract_member(mach_task_self(), timeoutPort, waitSet);
1504 mk_timer_destroy(timeoutPort);
1505 }
1506 #endif
1507 return returnValue;
1508 }
1509 }
1510 }
1511
1512 void CFRunLoopRun(void) { /* DOES CALLOUT */
1513 int32_t result;
1514 do {
1515 result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
1516 } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
1517 }
1518
1519 SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
1520 CFRunLoopModeRef currentMode, previousMode;
1521 CFIndex *previousStopped;
1522 int32_t result;
1523
1524 if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
1525 __CFRunLoopLock(rl);
1526 currentMode = __CFRunLoopFindMode(rl, modeName, false);
1527 if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode)) {
1528 if (currentMode) __CFRunLoopModeUnlock(currentMode);
1529 __CFRunLoopUnlock(rl);
1530 return kCFRunLoopRunFinished;
1531 }
1532 previousStopped = (CFIndex *)rl->_stopped;
1533 rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 16, 0);
1534 rl->_stopped[0] = 0x4346524C;
1535 rl->_stopped[1] = 0x4346524C; // 'CFRL'
1536 rl->_stopped[2] = 0x00000000; // here the value is stored
1537 rl->_stopped[3] = 0x4346524C;
1538 previousMode = rl->_currentMode;
1539 rl->_currentMode = currentMode;
1540 __CFRunLoopUnlock(rl);
1541 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
1542 result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, false);
1543 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
1544 __CFRunLoopModeUnlock(currentMode);
1545 __CFRunLoopLock(rl);
1546 CFAllocatorDeallocate(kCFAllocatorSystemDefault, (void *)rl->_stopped);
1547 rl->_stopped = previousStopped;
1548 rl->_currentMode = previousMode;
1549 __CFRunLoopUnlock(rl);
1550 return result;
1551 }
1552
1553 SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
1554 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
1555 }
1556
1557 static void __CFRunLoopFindMinTimer(const void *value, void *ctx) {
1558 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
1559 CFRunLoopTimerRef *result = ctx;
1560 if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) {
1561 *result = rlt;
1562 }
1563 }
1564
1565 CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
1566 CFRunLoopModeRef rlm;
1567 CFRunLoopTimerRef result = NULL;
1568 int64_t fireTime = 0;
1569 __CFRunLoopLock(rl);
1570 rlm = __CFRunLoopFindMode(rl, modeName, false);
1571 __CFRunLoopUnlock(rl);
1572 if (rlm) {
1573 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
1574 __CFRunLoopTimerFireTSRLock();
1575 CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result);
1576 fireTime = result->_fireTSR;
1577 __CFRunLoopTimerFireTSRUnlock();
1578 }
1579 __CFRunLoopModeUnlock(rlm);
1580 }
1581 return (0 == fireTime) ? 0.0 : __CFTSRToAbsoluteTime(fireTime);
1582 }
1583
1584 Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
1585 return __CFRunLoopIsSleeping(rl);
1586 }
1587
1588 void CFRunLoopWakeUp(CFRunLoopRef rl) {
1589 #if defined(__MACH__)
1590 kern_return_t ret;
1591 /* We unconditionally try to send the message, since we don't want
1592 * to lose a wakeup, but the send may fail if there is already a
1593 * wakeup pending, since the queue length is 1. */
1594 ret = __CFSendTrivialMachMessage(rl->_waitPort, 0, MACH_SEND_TIMEOUT, 0);
1595 if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) {
1596 HALT;
1597 }
1598 #else
1599 SetEvent(rl->_waitPort);
1600 #endif
1601 }
1602
1603 void CFRunLoopStop(CFRunLoopRef rl) {
1604 __CFRunLoopLock(rl);
1605 __CFRunLoopSetStopped(rl);
1606 __CFRunLoopUnlock(rl);
1607 CFRunLoopWakeUp(rl);
1608 }
1609
1610 CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
1611 CFRunLoopModeRef rlm;
1612 __CFRunLoopLock(rl);
1613 rlm = __CFRunLoopFindMode(rl, modeName, true);
1614 __CFRunLoopUnlock(rl);
1615 if (NULL != rlm) {
1616 rlm->_stopped = true;
1617 __CFRunLoopModeUnlock(rlm);
1618 }
1619 CFRunLoopWakeUp(rl);
1620 }
1621
1622 CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
1623 CFRunLoopModeRef rlm;
1624 if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) {
1625 return false;
1626 } else if (CFEqual(modeName, candidateContainedName)) {
1627 return true;
1628 }
1629 __CFRunLoopLock(rl);
1630 rlm = __CFRunLoopFindMode(rl, modeName, true);
1631 __CFRunLoopUnlock(rl);
1632 if (NULL != rlm) {
1633 CFArrayRef submodes;
1634 if (NULL == rlm->_submodes) {
1635 __CFRunLoopModeUnlock(rlm);
1636 return false;
1637 }
1638 if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) {
1639 __CFRunLoopModeUnlock(rlm);
1640 return true;
1641 }
1642 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
1643 __CFRunLoopModeUnlock(rlm);
1644 if (NULL != submodes) {
1645 CFIndex idx, cnt;
1646 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
1647 CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
1648 if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) {
1649 CFRelease(submodes);
1650 return true;
1651 }
1652 }
1653 CFRelease(submodes);
1654 }
1655 }
1656 return false;
1657 }
1658
1659 CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) {
1660 CFRunLoopModeRef rlm;
1661 if (__CFRunLoopIsDeallocating(rl)) return;
1662 // should really do a recursive check here, to make sure that a cycle isn't
1663 // introduced; of course, if that happens, you aren't going to get very far.
1664 if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) {
1665 return;
1666 } else {
1667 __CFRunLoopLock(rl);
1668 rlm = __CFRunLoopFindMode(rl, toModeName, true);
1669 __CFRunLoopUnlock(rl);
1670 if (NULL != rlm) {
1671 if (NULL == rlm->_submodes) {
1672 rlm->_submodes = CFArrayCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeArrayCallBacks);
1673 }
1674 if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) {
1675 CFArrayAppendValue(rlm->_submodes, modeName);
1676 }
1677 __CFRunLoopModeUnlock(rlm);
1678 }
1679 }
1680 }
1681
1682 CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) {
1683 CFRunLoopModeRef rlm;
1684 // should really do a recursive check here, to make sure that a cycle isn't
1685 // introduced; of course, if that happens, you aren't going to get very far.
1686 if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) {
1687 return;
1688 } else {
1689 __CFRunLoopLock(rl);
1690 rlm = __CFRunLoopFindMode(rl, fromModeName, true);
1691 __CFRunLoopUnlock(rl);
1692 if (NULL != rlm) {
1693 if (NULL != rlm->_submodes) {
1694 CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes);
1695 idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName);
1696 if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx);
1697 }
1698 __CFRunLoopModeUnlock(rlm);
1699 }
1700 }
1701 }
1702
1703 Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
1704 CFRunLoopModeRef rlm;
1705 Boolean hasValue = false;
1706 __CFRunLoopLock(rl);
1707 if (modeName == kCFRunLoopCommonModes) {
1708 if (NULL != rl->_commonModeItems) {
1709 hasValue = CFSetContainsValue(rl->_commonModeItems, rls);
1710 }
1711 __CFRunLoopUnlock(rl);
1712 } else {
1713 rlm = __CFRunLoopFindMode(rl, modeName, false);
1714 __CFRunLoopUnlock(rl);
1715 if (NULL != rlm && NULL != rlm->_sources) {
1716 hasValue = CFSetContainsValue(rlm->_sources, rls);
1717 __CFRunLoopModeUnlock(rlm);
1718 } else if (NULL != rlm) {
1719 __CFRunLoopModeUnlock(rlm);
1720 }
1721 }
1722 return hasValue;
1723 }
1724
1725 void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
1726 CFRunLoopModeRef rlm;
1727 if (__CFRunLoopIsDeallocating(rl)) return;
1728 if (!__CFIsValid(rls)) return;
1729 __CFRunLoopLock(rl);
1730 if (modeName == kCFRunLoopCommonModes) {
1731 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1732 if (NULL == rl->_commonModeItems) {
1733 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
1734 _CFSetSetCapacity(rl->_commonModeItems, 20);
1735 }
1736 CFSetAddValue(rl->_commonModeItems, rls);
1737 __CFRunLoopUnlock(rl);
1738 if (NULL != set) {
1739 CFTypeRef context[2] = {rl, rls};
1740 /* add new item to all common-modes */
1741 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
1742 CFRelease(set);
1743 }
1744 } else {
1745 rlm = __CFRunLoopFindMode(rl, modeName, true);
1746 __CFRunLoopUnlock(rl);
1747 if (NULL != rlm && NULL == rlm->_sources) {
1748 rlm->_sources = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
1749 _CFSetSetCapacity(rlm->_sources, 10);
1750 }
1751 if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) {
1752 CFSetAddValue(rlm->_sources, rls);
1753 __CFRunLoopModeUnlock(rlm);
1754 __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */
1755 } else if (NULL != rlm) {
1756 __CFRunLoopModeUnlock(rlm);
1757 }
1758 }
1759 }
1760
1761 void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
1762 CFRunLoopModeRef rlm;
1763 __CFRunLoopLock(rl);
1764 if (modeName == kCFRunLoopCommonModes) {
1765 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
1766 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1767 CFSetRemoveValue(rl->_commonModeItems, rls);
1768 __CFRunLoopUnlock(rl);
1769 if (NULL != set) {
1770 CFTypeRef context[2] = {rl, rls};
1771 /* remove new item from all common-modes */
1772 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
1773 CFRelease(set);
1774 }
1775 } else {
1776 __CFRunLoopUnlock(rl);
1777 }
1778 } else {
1779 rlm = __CFRunLoopFindMode(rl, modeName, false);
1780 __CFRunLoopUnlock(rl);
1781 if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) {
1782 CFRetain(rls);
1783 CFSetRemoveValue(rlm->_sources, rls);
1784 __CFRunLoopModeUnlock(rlm);
1785 __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */
1786 CFRelease(rls);
1787 } else if (NULL != rlm) {
1788 __CFRunLoopModeUnlock(rlm);
1789 }
1790 }
1791 }
1792
1793 Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
1794 CFRunLoopModeRef rlm;
1795 Boolean hasValue = false;
1796 __CFRunLoopLock(rl);
1797 if (modeName == kCFRunLoopCommonModes) {
1798 if (NULL != rl->_commonModeItems) {
1799 hasValue = CFSetContainsValue(rl->_commonModeItems, rlo);
1800 }
1801 __CFRunLoopUnlock(rl);
1802 } else {
1803 rlm = __CFRunLoopFindMode(rl, modeName, false);
1804 __CFRunLoopUnlock(rl);
1805 if (NULL != rlm && NULL != rlm->_observers) {
1806 hasValue = CFSetContainsValue(rlm->_observers, rlo);
1807 __CFRunLoopModeUnlock(rlm);
1808 } else if (NULL != rlm) {
1809 __CFRunLoopModeUnlock(rlm);
1810 }
1811 }
1812 return hasValue;
1813 }
1814
1815 void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
1816 CFRunLoopModeRef rlm;
1817 if (__CFRunLoopIsDeallocating(rl)) return;
1818 if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
1819 __CFRunLoopLock(rl);
1820 if (modeName == kCFRunLoopCommonModes) {
1821 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1822 if (NULL == rl->_commonModeItems) {
1823 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
1824 }
1825 CFSetAddValue(rl->_commonModeItems, rlo);
1826 __CFRunLoopUnlock(rl);
1827 if (NULL != set) {
1828 CFTypeRef context[2] = {rl, rlo};
1829 /* add new item to all common-modes */
1830 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
1831 CFRelease(set);
1832 }
1833 } else {
1834 rlm = __CFRunLoopFindMode(rl, modeName, true);
1835 __CFRunLoopUnlock(rl);
1836 if (NULL != rlm && NULL == rlm->_observers) {
1837 rlm->_observers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
1838 }
1839 if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) {
1840 CFSetAddValue(rlm->_observers, rlo);
1841 __CFRunLoopModeUnlock(rlm);
1842 __CFRunLoopObserverSchedule(rlo, rl, rlm);
1843 } else if (NULL != rlm) {
1844 __CFRunLoopModeUnlock(rlm);
1845 }
1846 }
1847 }
1848
1849 void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
1850 CFRunLoopModeRef rlm;
1851 __CFRunLoopLock(rl);
1852 if (modeName == kCFRunLoopCommonModes) {
1853 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) {
1854 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1855 CFSetRemoveValue(rl->_commonModeItems, rlo);
1856 __CFRunLoopUnlock(rl);
1857 if (NULL != set) {
1858 CFTypeRef context[2] = {rl, rlo};
1859 /* remove new item from all common-modes */
1860 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
1861 CFRelease(set);
1862 }
1863 } else {
1864 __CFRunLoopUnlock(rl);
1865 }
1866 } else {
1867 rlm = __CFRunLoopFindMode(rl, modeName, false);
1868 __CFRunLoopUnlock(rl);
1869 if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) {
1870 CFRetain(rlo);
1871 CFSetRemoveValue(rlm->_observers, rlo);
1872 __CFRunLoopModeUnlock(rlm);
1873 __CFRunLoopObserverCancel(rlo, rl, rlm);
1874 CFRelease(rlo);
1875 } else if (NULL != rlm) {
1876 __CFRunLoopModeUnlock(rlm);
1877 }
1878 }
1879 }
1880
1881 Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
1882 CFRunLoopModeRef rlm;
1883 Boolean hasValue = false;
1884 __CFRunLoopLock(rl);
1885 if (modeName == kCFRunLoopCommonModes) {
1886 if (NULL != rl->_commonModeItems) {
1887 hasValue = CFSetContainsValue(rl->_commonModeItems, rlt);
1888 }
1889 __CFRunLoopUnlock(rl);
1890 } else {
1891 rlm = __CFRunLoopFindMode(rl, modeName, false);
1892 __CFRunLoopUnlock(rl);
1893 if (NULL != rlm && NULL != rlm->_timers) {
1894 hasValue = CFSetContainsValue(rlm->_timers, rlt);
1895 __CFRunLoopModeUnlock(rlm);
1896 } else if (NULL != rlm) {
1897 __CFRunLoopModeUnlock(rlm);
1898 }
1899 }
1900 return hasValue;
1901 }
1902
1903 void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
1904 CFRunLoopModeRef rlm;
1905 if (__CFRunLoopIsDeallocating(rl)) return;
1906 if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
1907 __CFRunLoopLock(rl);
1908 if (modeName == kCFRunLoopCommonModes) {
1909 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1910 if (NULL == rl->_commonModeItems) {
1911 rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
1912 }
1913 CFSetAddValue(rl->_commonModeItems, rlt);
1914 __CFRunLoopUnlock(rl);
1915 if (NULL != set) {
1916 CFTypeRef context[2] = {rl, rlt};
1917 /* add new item to all common-modes */
1918 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
1919 CFRelease(set);
1920 }
1921 } else {
1922 rlm = __CFRunLoopFindMode(rl, modeName, true);
1923 __CFRunLoopUnlock(rl);
1924 if (NULL != rlm && NULL == rlm->_timers) {
1925 rlm->_timers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
1926 }
1927 if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) {
1928 CFSetAddValue(rlm->_timers, rlt);
1929 __CFRunLoopModeUnlock(rlm);
1930 __CFRunLoopTimerSchedule(rlt, rl, rlm);
1931 } else if (NULL != rlm) {
1932 __CFRunLoopModeUnlock(rlm);
1933 }
1934 }
1935 }
1936
1937 void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
1938 CFRunLoopModeRef rlm;
1939 __CFRunLoopLock(rl);
1940 if (modeName == kCFRunLoopCommonModes) {
1941 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) {
1942 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
1943 CFSetRemoveValue(rl->_commonModeItems, rlt);
1944 __CFRunLoopUnlock(rl);
1945 if (NULL != set) {
1946 CFTypeRef context[2] = {rl, rlt};
1947 /* remove new item from all common-modes */
1948 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
1949 CFRelease(set);
1950 }
1951 } else {
1952 __CFRunLoopUnlock(rl);
1953 }
1954 } else {
1955 rlm = __CFRunLoopFindMode(rl, modeName, false);
1956 __CFRunLoopUnlock(rl);
1957 if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) {
1958 CFRetain(rlt);
1959 CFSetRemoveValue(rlm->_timers, rlt);
1960 __CFRunLoopModeUnlock(rlm);
1961 __CFRunLoopTimerCancel(rlt, rl, rlm);
1962 CFRelease(rlt);
1963 } else if (NULL != rlm) {
1964 __CFRunLoopModeUnlock(rlm);
1965 }
1966 }
1967 }
1968
1969
1970 /* CFRunLoopSource */
1971
1972 static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */
1973 CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1;
1974 CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2;
1975 if (rls1 == rls2) return true;
1976 if (rls1->_order != rls2->_order) return false;
1977 if (rls1->_context.version0.version != rls2->_context.version0.version) return false;
1978 if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false;
1979 if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false;
1980 if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false;
1981 if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false;
1982 if (rls1->_context.version0.equal)
1983 return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info);
1984 return (rls1->_context.version0.info == rls2->_context.version0.info);
1985 }
1986
1987 static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) { /* DOES CALLOUT */
1988 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
1989 if (rls->_context.version0.hash)
1990 return rls->_context.version0.hash(rls->_context.version0.info);
1991 return (CFHashCode)rls->_context.version0.info;
1992 }
1993
1994 static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
1995 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
1996 CFStringRef result;
1997 CFStringRef contextDesc = NULL;
1998 if (NULL != rls->_context.version0.copyDescription) {
1999 contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info);
2000 }
2001 if (NULL == contextDesc) {
2002 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource context %p>"), rls->_context.version0.info);
2003 }
2004 result = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), rls->_lock ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc);
2005 CFRelease(contextDesc);
2006 return result;
2007 }
2008
2009 static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2010 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
2011 CFRunLoopSourceInvalidate(rls);
2012 if (rls->_context.version0.release) {
2013 rls->_context.version0.release(rls->_context.version0.info);
2014 }
2015 }
2016
2017 static const CFRuntimeClass __CFRunLoopSourceClass = {
2018 0,
2019 "CFRunLoopSource",
2020 NULL, // init
2021 NULL, // copy
2022 __CFRunLoopSourceDeallocate,
2023 __CFRunLoopSourceEqual,
2024 __CFRunLoopSourceHash,
2025 NULL, //
2026 __CFRunLoopSourceCopyDescription
2027 };
2028
2029 __private_extern__ void __CFRunLoopSourceInitialize(void) {
2030 __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass);
2031 }
2032
2033 CFTypeID CFRunLoopSourceGetTypeID(void) {
2034 return __kCFRunLoopSourceTypeID;
2035 }
2036
2037 CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
2038 CFRunLoopSourceRef memory;
2039 uint32_t size;
2040 if (NULL == context) HALT;
2041 size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
2042 memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL);
2043 if (NULL == memory) {
2044 return NULL;
2045 }
2046 __CFSetValid(memory);
2047 __CFRunLoopSourceUnsetSignaled(memory);
2048 memory->_lock = 0;
2049 memory->_bits = 0;
2050 memory->_order = order;
2051 memory->_runLoops = NULL;
2052 #if defined(__MACH__)
2053 memmove(&memory->_context, context, (0 == context->version) ? sizeof(CFRunLoopSourceContext) : sizeof(CFRunLoopSourceContext1));
2054 #else
2055 memmove(&memory->_context, context, sizeof(CFRunLoopSourceContext));
2056 #endif
2057 if (context->retain) {
2058 memory->_context.version0.info = (void *)context->retain(context->info);
2059 }
2060 return memory;
2061 }
2062
2063 CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
2064 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2065 return rls->_order;
2066 }
2067
2068 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
2069 CFRunLoopRef rl = (CFRunLoopRef)value;
2070 CFTypeRef *params = context;
2071 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
2072 CFArrayRef array;
2073 CFIndex idx;
2074 if (rl == params[1]) return;
2075 array = CFRunLoopCopyAllModes(rl);
2076 for (idx = CFArrayGetCount(array); idx--;) {
2077 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2078 CFRunLoopRemoveSource(rl, rls, modeName);
2079 }
2080 CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
2081 CFRelease(array);
2082 params[1] = rl;
2083 }
2084
2085 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
2086 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2087 CFRetain(rls);
2088 __CFRunLoopSourceLock(rls);
2089 if (__CFIsValid(rls)) {
2090 __CFUnsetValid(rls);
2091 if (NULL != rls->_runLoops) {
2092 CFTypeRef params[2] = {rls, NULL};
2093 CFBagRef bag = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops);
2094 CFRelease(rls->_runLoops);
2095 rls->_runLoops = NULL;
2096 __CFRunLoopSourceUnlock(rls);
2097 CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params);
2098 CFRelease(bag);
2099 } else {
2100 __CFRunLoopSourceUnlock(rls);
2101 }
2102 /* for hashing- and equality-use purposes, can't actually release the context here */
2103 } else {
2104 __CFRunLoopSourceUnlock(rls);
2105 }
2106 CFRelease(rls);
2107 }
2108
2109 Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
2110 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2111 return __CFIsValid(rls);
2112 }
2113
2114 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
2115 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
2116 #if defined(__MACH__)
2117 CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__);
2118 memmove(context, &rls->_context, (0 == context->version) ? sizeof(CFRunLoopSourceContext) : sizeof(CFRunLoopSourceContext1));
2119 #else
2120 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2121 memmove(context, &rls->_context, sizeof(CFRunLoopSourceContext));
2122 #endif
2123 }
2124
2125 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
2126 __CFRunLoopSourceLock(rls);
2127 if (__CFIsValid(rls)) {
2128 __CFRunLoopSourceSetSignaled(rls);
2129 }
2130 __CFRunLoopSourceUnlock(rls);
2131 }
2132
2133
2134 /* CFRunLoopObserver */
2135
2136 static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
2137 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
2138 CFStringRef result;
2139 CFStringRef contextDesc = NULL;
2140 __CFRunLoopObserverLock(rlo);
2141 if (NULL != rlo->_context.copyDescription) {
2142 contextDesc = rlo->_context.copyDescription(rlo->_context.info);
2143 }
2144 if (!contextDesc) {
2145 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
2146 }
2147 result = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), rlo->_lock ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc);
2148 __CFRunLoopObserverUnlock(rlo);
2149 CFRelease(contextDesc);
2150 return result;
2151 }
2152
2153 static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2154 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
2155 CFRunLoopObserverInvalidate(rlo);
2156 }
2157
2158 static const CFRuntimeClass __CFRunLoopObserverClass = {
2159 0,
2160 "CFRunLoopObserver",
2161 NULL, // init
2162 NULL, // copy
2163 __CFRunLoopObserverDeallocate,
2164 NULL,
2165 NULL,
2166 NULL, //
2167 __CFRunLoopObserverCopyDescription
2168 };
2169
2170 __private_extern__ void __CFRunLoopObserverInitialize(void) {
2171 __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass);
2172 }
2173
2174 CFTypeID CFRunLoopObserverGetTypeID(void) {
2175 return __kCFRunLoopObserverTypeID;
2176 }
2177
2178 CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
2179 CFRunLoopObserverRef memory;
2180 UInt32 size;
2181 size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
2182 memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL);
2183 if (NULL == memory) {
2184 return NULL;
2185 }
2186 __CFSetValid(memory);
2187 __CFRunLoopObserverUnsetFiring(memory);
2188 if (repeats) {
2189 __CFRunLoopObserverSetRepeats(memory);
2190 } else {
2191 __CFRunLoopObserverUnsetRepeats(memory);
2192 }
2193 memory->_lock = 0;
2194 memory->_runLoop = NULL;
2195 memory->_rlCount = 0;
2196 memory->_activities = activities;
2197 memory->_order = order;
2198 memory->_callout = callout;
2199 if (context) {
2200 if (context->retain) {
2201 memory->_context.info = (void *)context->retain(context->info);
2202 } else {
2203 memory->_context.info = context->info;
2204 }
2205 memory->_context.retain = context->retain;
2206 memory->_context.release = context->release;
2207 memory->_context.copyDescription = context->copyDescription;
2208 } else {
2209 memory->_context.info = 0;
2210 memory->_context.retain = 0;
2211 memory->_context.release = 0;
2212 memory->_context.copyDescription = 0;
2213 }
2214 return memory;
2215 }
2216
2217 CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
2218 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2219 return rlo->_activities;
2220 }
2221
2222 CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
2223 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2224 return rlo->_order;
2225 }
2226
2227 Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
2228 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2229 return __CFRunLoopObserverRepeats(rlo);
2230 }
2231
2232 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */
2233 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2234 CFRetain(rlo);
2235 __CFRunLoopObserverLock(rlo);
2236 if (__CFIsValid(rlo)) {
2237 CFRunLoopRef rl = rlo->_runLoop;
2238 __CFUnsetValid(rlo);
2239 __CFRunLoopObserverUnlock(rlo);
2240 if (NULL != rl) {
2241 CFArrayRef array;
2242 CFIndex idx;
2243 array = CFRunLoopCopyAllModes(rl);
2244 for (idx = CFArrayGetCount(array); idx--;) {
2245 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2246 CFRunLoopRemoveObserver(rl, rlo, modeName);
2247 }
2248 CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
2249 CFRelease(array);
2250 }
2251 if (rlo->_context.release)
2252 rlo->_context.release(rlo->_context.info); /* CALLOUT */
2253 rlo->_context.info = NULL;
2254 } else {
2255 __CFRunLoopObserverUnlock(rlo);
2256 }
2257 CFRelease(rlo);
2258 }
2259
2260 Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
2261 return __CFIsValid(rlo);
2262 }
2263
2264 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
2265 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
2266 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2267 *context = rlo->_context;
2268 }
2269
2270 /* CFRunLoopTimer */
2271
2272 static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
2273 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
2274 CFStringRef result;
2275 CFStringRef contextDesc = NULL;
2276 int64_t fireTime;
2277 __CFRunLoopTimerFireTSRLock();
2278 fireTime = rlt->_fireTSR;
2279 __CFRunLoopTimerFireTSRUnlock();
2280 __CFRunLoopTimerLock(rlt);
2281 if (NULL != rlt->_context.copyDescription) {
2282 contextDesc = rlt->_context.copyDescription(rlt->_context.info);
2283 }
2284 if (NULL == contextDesc) {
2285 contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
2286 }
2287 result = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer %x [%x]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), rlt->_lock ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), __CFTSRToAbsoluteTime(fireTime), rlt->_order, rlt->_callout, contextDesc);
2288 __CFRunLoopTimerUnlock(rlt);
2289 CFRelease(contextDesc);
2290 return result;
2291 }
2292
2293 static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
2294 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
2295 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
2296 }
2297
2298 static const CFRuntimeClass __CFRunLoopTimerClass = {
2299 0,
2300 "CFRunLoopTimer",
2301 NULL, // init
2302 NULL, // copy
2303 __CFRunLoopTimerDeallocate,
2304 NULL, // equal
2305 NULL,
2306 NULL, //
2307 __CFRunLoopTimerCopyDescription
2308 };
2309
2310 __private_extern__ void __CFRunLoopTimerInitialize(void) {
2311 __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass);
2312 }
2313
2314 CFTypeID CFRunLoopTimerGetTypeID(void) {
2315 return __kCFRunLoopTimerTypeID;
2316 }
2317
2318 CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
2319 CFRunLoopTimerRef memory;
2320 UInt32 size;
2321 size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
2322 memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL);
2323 if (NULL == memory) {
2324 return NULL;
2325 }
2326 __CFSetValid(memory);
2327 __CFRunLoopTimerUnsetFiring(memory);
2328 memory->_lock = 0;
2329 memory->_runLoop = NULL;
2330 memory->_rlCount = 0;
2331 #if defined(__MACH__)
2332 memory->_port = MACH_PORT_NULL;
2333 #endif
2334 memory->_order = order;
2335 if (fireDate < __CFTSRToAbsoluteTime(0)) {
2336 memory->_fireTSR = 0;
2337 } else if (__CFTSRToAbsoluteTime(LLONG_MAX) < fireDate) {
2338 memory->_fireTSR = LLONG_MAX;
2339 } else {
2340 memory->_fireTSR = __CFAbsoluteTimeToTSR(fireDate);
2341 }
2342 if (interval <= 0.0) {
2343 memory->_intervalTSR = 0;
2344 } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) {
2345 memory->_intervalTSR = LLONG_MAX;
2346 } else {
2347 memory->_intervalTSR = __CFTimeIntervalToTSR(interval);
2348 }
2349 memory->_callout = callout;
2350 if (NULL != context) {
2351 if (context->retain) {
2352 memory->_context.info = (void *)context->retain(context->info);
2353 } else {
2354 memory->_context.info = context->info;
2355 }
2356 memory->_context.retain = context->retain;
2357 memory->_context.release = context->release;
2358 memory->_context.copyDescription = context->copyDescription;
2359 } else {
2360 memory->_context.info = 0;
2361 memory->_context.retain = 0;
2362 memory->_context.release = 0;
2363 memory->_context.copyDescription = 0;
2364 }
2365 return memory;
2366 }
2367
2368 CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
2369 int64_t fireTime, result = 0;
2370 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime");
2371 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2372 __CFRunLoopTimerFireTSRLock();
2373 fireTime = rlt->_fireTSR;
2374 __CFRunLoopTimerFireTSRUnlock();
2375 __CFRunLoopTimerLock(rlt);
2376 if (__CFIsValid(rlt)) {
2377 result = fireTime;
2378 }
2379 __CFRunLoopTimerUnlock(rlt);
2380 return __CFTSRToAbsoluteTime(result);
2381 }
2382
2383 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
2384 __CFRunLoopTimerFireTSRLock();
2385 if (fireDate < __CFTSRToAbsoluteTime(0)) {
2386 rlt->_fireTSR = 0;
2387 } else if (__CFTSRToAbsoluteTime(LLONG_MAX) < fireDate) {
2388 rlt->_fireTSR = LLONG_MAX;
2389 } else {
2390 rlt->_fireTSR = __CFAbsoluteTimeToTSR(fireDate);
2391 }
2392 __CFRunLoopTimerFireTSRUnlock();
2393 if (rlt->_runLoop != NULL) {
2394 __CFRunLoopTimerRescheduleWithAllModes(rlt, rlt->_runLoop);
2395 }
2396 }
2397
2398 CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
2399 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval");
2400 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2401 return __CFTSRToTimeInterval(rlt->_intervalTSR);
2402 }
2403
2404 Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
2405 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2406 return (0 != rlt->_intervalTSR);
2407 }
2408
2409 CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
2410 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order");
2411 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2412 return rlt->_order;
2413 }
2414
2415 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
2416 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate");
2417 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2418 CFRetain(rlt);
2419 __CFRunLoopTimerLock(rlt);
2420 if (__CFIsValid(rlt)) {
2421 CFRunLoopRef rl = rlt->_runLoop;
2422 void *info = rlt->_context.info;
2423 __CFUnsetValid(rlt);
2424 #if defined(__MACH__)
2425 __CFRunLoopTimerPortMapLock();
2426 if (NULL != __CFRLTPortMap) {
2427 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port);
2428 }
2429 __CFRunLoopTimerPortMapUnlock();
2430 mk_timer_destroy(rlt->_port);
2431 rlt->_port = MACH_PORT_NULL;
2432 #endif
2433 rlt->_context.info = NULL;
2434 __CFRunLoopTimerUnlock(rlt);
2435 if (NULL != rl) {
2436 CFArrayRef array;
2437 CFIndex idx;
2438 array = CFRunLoopCopyAllModes(rl);
2439 for (idx = CFArrayGetCount(array); idx--;) {
2440 CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
2441 CFRunLoopRemoveTimer(rl, rlt, modeName);
2442 }
2443 CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
2444 CFRelease(array);
2445 }
2446 if (NULL != rlt->_context.release) {
2447 rlt->_context.release(info); /* CALLOUT */
2448 }
2449 } else {
2450 __CFRunLoopTimerUnlock(rlt);
2451 }
2452 CFRelease(rlt);
2453 }
2454
2455 Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
2456 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid");
2457 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2458 return __CFIsValid(rlt);
2459 }
2460
2461 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
2462 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
2463 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
2464 *context = rlt->_context;
2465 }
2466
2467 struct rlpair {
2468 CFRunLoopRef rl; // not retained
2469 CFStringRef mode; // not retained
2470 };
2471
2472 static Boolean __CFRLPKeyEqual(const void *value1, const void *value2) {
2473 const struct rlpair *s1 = value1;
2474 const struct rlpair *s2 = value2;
2475 return (s1->rl == s2->rl) && CFEqual(s1->mode, s2->mode);
2476 }
2477
2478 static CFHashCode __CFRLPKeyHash(const void *value) {
2479 const struct rlpair *s = value;
2480 return (CFHashCode)s->rl + CFHash(s->mode);
2481 }
2482
2483 static CFSpinLock_t __CFRunLoopPerformLock = 0;
2484 static CFMutableDictionaryRef __CFRunLoopPerformSources = NULL;
2485
2486 struct performentry {
2487 CFRunLoopPerformCallBack callout;
2488 void *info;
2489 };
2490
2491 struct performinfo {
2492 CFSpinLock_t lock;
2493 CFRunLoopSourceRef source;
2494 CFRunLoopRef rl;
2495 CFStringRef mode;
2496 CFIndex count;
2497 CFIndex size;
2498 struct performentry *entries;
2499 };
2500
2501 static void __CFRunLoopPerformCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
2502 // we don't ever remove the source, so we know the run loop is dying
2503 struct rlpair key, *pair;
2504 struct performinfo *pinfo = info;
2505 __CFSpinLock(&__CFRunLoopPerformLock);
2506 key.rl = rl;
2507 key.mode = mode;
2508 if (CFDictionaryGetKeyIfPresent(__CFRunLoopPerformSources, &key, (const void **)&pair)) {
2509 CFDictionaryRemoveValue(__CFRunLoopPerformSources, pair);
2510 CFAllocatorDeallocate(kCFAllocatorSystemDefault, pair);
2511 }
2512 CFRunLoopSourceInvalidate(pinfo->source);
2513 CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo->entries);
2514 CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo);
2515 // We can free pinfo here, even though the source isn't freed and still has
2516 // a weak pointer to it, because the hash and equal callbacks of the source
2517 // don't indirect into the info for their operations.
2518 __CFSpinUnlock(&__CFRunLoopPerformLock);
2519 }
2520
2521 static void __CFRunLoopPerformPerform(void *info) {
2522 struct performinfo *pinfo = info;
2523 struct performentry *entries;
2524 CFIndex idx, cnt;
2525 __CFSpinLock(&(pinfo->lock));
2526 entries = pinfo->entries;
2527 cnt = pinfo->count;
2528 pinfo->entries = NULL;
2529 pinfo->count = 0;
2530 pinfo->size = 0;
2531 __CFSpinUnlock(&(pinfo->lock));
2532 for (idx = 0; idx < cnt; idx++) {
2533 entries[idx].callout(entries[idx].info);
2534 }
2535 // done with this list
2536 CFAllocatorDeallocate(kCFAllocatorSystemDefault, entries);
2537 // don't need to check to see if there's still something in the queue,
2538 // and resignal here, since anything added during the callouts,
2539 // from this or another thread, would have caused resignalling
2540 }
2541
2542 // retaining and freeing the info pointer and stuff inside is completely
2543 // the caller's (and probably the callout's) responsibility
2544 void _CFRunLoopPerformEnqueue(CFRunLoopRef rl, CFStringRef mode, CFRunLoopPerformCallBack callout, void *info) {
2545 CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
2546 CFRunLoopSourceRef source;
2547 struct rlpair key;
2548 struct performinfo *pinfo;
2549 __CFSpinLock(&__CFRunLoopPerformLock);
2550 if (!__CFRunLoopPerformSources) {
2551 CFDictionaryKeyCallBacks kcb = {0, NULL, NULL, NULL, __CFRLPKeyEqual, __CFRLPKeyHash};
2552 __CFRunLoopPerformSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kcb, &kCFTypeDictionaryValueCallBacks);
2553 }
2554 key.rl = rl;
2555 key.mode = mode;
2556 if (!CFDictionaryGetValueIfPresent(__CFRunLoopPerformSources, &key, (const void **)&source)) {
2557 struct rlpair *pair;
2558 context.info = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct performinfo), 0);
2559 pinfo = context.info;
2560 pinfo->lock = 0;
2561 pinfo->rl = rl;
2562 pinfo->mode = mode;
2563 pinfo->count = 0;
2564 pinfo->size = 0;
2565 pinfo->entries = NULL;
2566 context.cancel = __CFRunLoopPerformCancel;
2567 context.perform = __CFRunLoopPerformPerform;
2568 source = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &context);
2569 pair = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(*pair), 0);
2570 *pair = key;
2571 CFDictionarySetValue(__CFRunLoopPerformSources, pair, source);
2572 pinfo->source = source;
2573 CFRunLoopAddSource(rl, source, mode);
2574 } else {
2575 CFRetain(source);
2576 CFRunLoopSourceGetContext(source, &context);
2577 pinfo = context.info;
2578 }
2579 __CFSpinLock(&(pinfo->lock));
2580 __CFSpinUnlock(&__CFRunLoopPerformLock);
2581 if (pinfo->count == pinfo->size) {
2582 pinfo->size = (0 == pinfo->size ? 3 : 2 * pinfo->size);
2583 pinfo->entries = CFAllocatorReallocate(kCFAllocatorSystemDefault, pinfo->entries, pinfo->size * sizeof(struct performentry), 0);
2584 }
2585 pinfo->entries[pinfo->count].callout = callout;
2586 pinfo->entries[pinfo->count].info = info;
2587 pinfo->count++;
2588 __CFSpinUnlock(&(pinfo->lock));
2589 CFRunLoopSourceSignal(source);
2590 CFRunLoopWakeUp(rl);
2591 CFRelease(source);
2592 }
2593