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