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