]> git.saurik.com Git - apple/cf.git/blob - CFRunLoop.c
4527d19cbcdfeba41c6ccaf0624a956f6987dc3d
[apple/cf.git] / CFRunLoop.c
1 /*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFRunLoop.c
24 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFRunLoop.h>
29 #include <CoreFoundation/CFSet.h>
30 #include <CoreFoundation/CFBag.h>
31 #include "CFInternal.h"
32 #include <math.h>
33 #include <stdio.h>
34 #include <limits.h>
35 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
36 #include <dispatch/dispatch.h>
37 #include <mach/mach.h>
38 #include <mach/clock_types.h>
39 #include <mach/clock.h>
40 #include <unistd.h>
41 #include <dlfcn.h>
42 extern mach_port_t _dispatch_get_main_queue_port_4CF(void);
43 extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg);
44 #else
45 #include <process.h>
46 #define __CFReadTSR() mach_absolute_time()
47 #endif
48 #include <Block.h>
49
50 static int _LogCFRunLoop = 0;
51
52 // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63
53 #define TIMER_DATE_LIMIT 4039289856.0
54 #define TIMER_INTERVAL_LIMIT 504911232.0
55
56 #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
57
58 #if DEPLOYMENT_TARGET_WINDOWS
59 static pthread_t kNilPthreadT = { nil, nil };
60 #define pthreadPointer(a) a.p
61
62 static DWORD __CFTSDKeyRunLoopKey = ~0;
63
64 // See function below.
65 bool gMARRY_MESSAGE_QUEUE = FALSE;
66 //
67 // vod __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled)
68 //
69 // This function will exist for a while until code is written
70 // by the WebKit folks to handle the new RunLoop message-queue
71 // model.
72 CF_EXPORT void __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled) {
73 gMARRY_MESSAGE_QUEUE = bEnabled;
74 }
75 bool __CFIsNonMachRunLoopMarryMsgQueueEnabled(void) {
76 return gMARRY_MESSAGE_QUEUE;
77 }
78
79 #else
80
81 static pthread_t kNilPthreadT = (pthread_t)0;
82 #define pthreadPointer(a) a
83 #define lockCount(a) a
84 #endif
85
86 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
87 #include <sys/types.h>
88 #include <sys/event.h>
89
90 typedef struct {
91 CFIndex version;
92 void * info;
93 const void *(*retain)(const void *info);
94 void (*release)(const void *info);
95 CFStringRef (*copyDescription)(const void *info);
96 Boolean (*equal)(const void *info1, const void *info2);
97 CFHashCode (*hash)(const void *info);
98 void (*perform)(const struct kevent *kev, void *info);
99 struct kevent event;
100 } CFRunLoopSourceContext2;
101
102 // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR.
103 // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop.
104 // There is no way to EV_ENABLE or EV_DISABLE a kevent.
105 // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet.
106 // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet.
107 // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos).
108 #endif
109
110 CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey);
111
112 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
113 // simple abstraction layer spanning Mach ports and Windows HANDLES
114 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
115
116 typedef mach_port_t __CFPort;
117 #define CFPORT_NULL MACH_PORT_NULL
118 typedef mach_port_t __CFPortSet;
119
120 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
121 static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) { HALT; };
122
123 static __CFPort __CFPortAllocate(void) {
124 __CFPort result = CFPORT_NULL;
125 kern_return_t ret;
126 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result);
127 if (KERN_SUCCESS == ret) {
128 ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND);
129 } else {
130 __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret);
131 }
132 if (KERN_SUCCESS == ret) {
133 mach_port_limits_t limits;
134 limits.mpl_qlimit = 1;
135 ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT);
136 }
137 if (KERN_SUCCESS != ret) mach_port_destroy(mach_task_self(), result);
138 return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
139 }
140
141 CF_INLINE void __CFPortFree(__CFPort port) {
142 mach_port_destroy(mach_task_self(), port);
143 }
144
145 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
146 static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) { HALT; };
147
148 CF_INLINE __CFPortSet __CFPortSetAllocate(void) {
149 __CFPortSet result;
150 kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result);
151 if (KERN_SUCCESS != ret) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret); }
152 return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
153 }
154
155 CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
156 kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet);
157 return (KERN_SUCCESS == ret);
158 }
159
160 CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
161 kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet);
162 return (KERN_SUCCESS == ret);
163 }
164
165 CF_INLINE void __CFPortSetFree(__CFPortSet portSet) {
166 kern_return_t ret;
167 mach_port_name_array_t array;
168 mach_msg_type_number_t idx, number;
169
170 ret = mach_port_get_set_status(mach_task_self(), portSet, &array, &number);
171 if (KERN_SUCCESS == ret) {
172 for (idx = 0; idx < number; idx++) {
173 mach_port_extract_member(mach_task_self(), array[idx], portSet);
174 }
175 vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t));
176 }
177 mach_port_destroy(mach_task_self(), portSet);
178 }
179
180 #elif DEPLOYMENT_TARGET_WINDOWS
181
182 typedef HANDLE __CFPort;
183 #define CFPORT_NULL NULL
184
185 // A simple dynamic array of HANDLEs, which grows to a high-water mark
186 typedef struct ___CFPortSet {
187 uint16_t used;
188 uint16_t size;
189 HANDLE *handles;
190 CFSpinLock_t lock; // insert and remove must be thread safe, like the Mach calls
191 } *__CFPortSet;
192
193 CF_INLINE __CFPort __CFPortAllocate(void) {
194 return CreateEventA(NULL, true, false, NULL);
195 }
196
197 CF_INLINE void __CFPortFree(__CFPort port) {
198 CloseHandle(port);
199 }
200
201 static __CFPortSet __CFPortSetAllocate(void) {
202 __CFPortSet result = (__CFPortSet)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0);
203 result->used = 0;
204 result->size = 4;
205 result->handles = (HANDLE *)CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0);
206 CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock);
207 return result;
208 }
209
210 static void __CFPortSetFree(__CFPortSet portSet) {
211 CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles);
212 CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet);
213 }
214
215 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
216 static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uint32_t bufSize, uint32_t *portsUsed) {
217 __CFSpinLock(&(portSet->lock));
218 __CFPort *result = portBuf;
219 if (bufSize < portSet->used)
220 result = (__CFPort *)CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0);
221 if (portSet->used > 1) {
222 // rotate the ports to vaguely simulate round-robin behaviour
223 uint16_t lastPort = portSet->used - 1;
224 HANDLE swapHandle = portSet->handles[0];
225 memmove(portSet->handles, &portSet->handles[1], lastPort * sizeof(HANDLE));
226 portSet->handles[lastPort] = swapHandle;
227 }
228 memmove(result, portSet->handles, portSet->used * sizeof(HANDLE));
229 *portsUsed = portSet->used;
230 __CFSpinUnlock(&(portSet->lock));
231 return result;
232 }
233
234 static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
235 __CFSpinLock(&(portSet->lock));
236 if (portSet->used >= portSet->size) {
237 portSet->size += 4;
238 portSet->handles = (HANDLE *)CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0);
239 }
240 if (portSet->used >= MAXIMUM_WAIT_OBJECTS)
241 CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS);
242 portSet->handles[portSet->used++] = port;
243 __CFSpinUnlock(&(portSet->lock));
244 return true;
245 }
246
247 static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
248 int i, j;
249 __CFSpinLock(&(portSet->lock));
250 for (i = 0; i < portSet->used; i++) {
251 if (portSet->handles[i] == port) {
252 for (j = i+1; j < portSet->used; j++) {
253 portSet->handles[j-1] = portSet->handles[j];
254 }
255 portSet->used--;
256 __CFSpinUnlock(&(portSet->lock));
257 return true;
258 }
259 }
260 __CFSpinUnlock(&(portSet->lock));
261 return false;
262 }
263
264 #endif
265
266 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
267 extern mach_port_name_t mk_timer_create(void);
268 extern kern_return_t mk_timer_destroy(mach_port_name_t name);
269 extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time);
270 extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time);
271
272 CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(int64_t x) {
273 AbsoluteTime a;
274 a.hi = x >> 32;
275 a.lo = x & (int64_t)0xFFFFFFFF;
276 return a;
277 }
278
279 static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) {
280 kern_return_t result;
281 mach_msg_header_t header;
282 header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
283 header.msgh_size = sizeof(mach_msg_header_t);
284 header.msgh_remote_port = port;
285 header.msgh_local_port = MACH_PORT_NULL;
286 header.msgh_id = msg_id;
287 result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
288 if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header);
289 return result;
290 }
291 #endif
292
293 /* unlock a run loop and modes before doing callouts/sleeping */
294 /* never try to take the run loop lock with a mode locked */
295 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
296 /* run loop mode structures should never be deallocated, even if they become empty */
297
298 static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID;
299 static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID;
300 static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID;
301 static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID;
302 static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID;
303
304 #if DEPLOYMENT_TARGET_WINDOWS
305 // The MSG identifier for the Windows message injected in the message queue to wake the run loop
306 static unsigned int __kCFRunLoopWakeUpMessage = 0;
307 static unsigned int __kCFRunLoopV1SourceReadyMessage = 0;
308 #endif
309
310 typedef struct __CFRunLoopMode *CFRunLoopModeRef;
311
312 struct __CFRunLoopMode {
313 CFRuntimeBase _base;
314 CFSpinLock_t _lock; /* must have the run loop locked before locking this */
315 CFStringRef _name;
316 Boolean _stopped;
317 char _padding[3];
318 CFMutableSetRef _sources;
319 CFMutableSetRef _observers;
320 CFMutableSetRef _timers;
321 CFMutableDictionaryRef _portToV1SourceMap;
322 CFMutableArrayRef _submodes; // names of the submodes
323 __CFPortSet _portSet;
324 CFIndex _observerMask;
325 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
326 int _kq;
327 #endif
328 #if DEPLOYMENT_TARGET_WINDOWS
329 DWORD _msgQMask;
330 #endif
331 };
332
333 CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
334 __CFSpinLock(&(rlm->_lock));
335 }
336
337 CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
338 __CFSpinUnlock(&(rlm->_lock));
339 }
340
341 static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
342 CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
343 CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
344 return CFEqual(rlm1->_name, rlm2->_name);
345 }
346
347 static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
348 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
349 return CFHash(rlm->_name);
350 }
351
352 static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) {
353 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
354 CFMutableStringRef result;
355 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
356 #if DEPLOYMENT_TARGET_WINDOWS
357 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, "unknown");
358 #else
359 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false");
360 #endif
361 CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet);
362 #if DEPLOYMENT_TARGET_WINDOWS
363 CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p,"), rlm->_msgQMask);
364 #endif
365 CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers);
366 return result;
367 }
368
369 static void __CFRunLoopModeDeallocate(CFTypeRef cf) {
370 CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
371 if (NULL != rlm->_sources) CFRelease(rlm->_sources);
372 if (NULL != rlm->_observers) CFRelease(rlm->_observers);
373 if (NULL != rlm->_timers) CFRelease(rlm->_timers);
374 if (NULL != rlm->_submodes) CFRelease(rlm->_submodes);
375 if (NULL != rlm->_portToV1SourceMap) CFRelease(rlm->_portToV1SourceMap);
376 CFRelease(rlm->_name);
377 __CFPortSetFree(rlm->_portSet);
378 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
379 if (-1 != rlm->_kq) close(rlm->_kq);
380 #endif
381 memset((char *)cf + sizeof(CFRuntimeBase), 0x7C, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase));
382 }
383
384 struct _block_item {
385 struct _block_item *_next;
386 CFTypeRef _mode; // CFString or CFSet or CFRunLoopTimer
387 void (^_block)(void);
388 };
389
390 struct __CFRunLoop {
391 CFRuntimeBase _base;
392 CFSpinLock_t _lock; /* locked for accessing mode list */
393 __CFPort _wakeUpPort; // used for CFRunLoopWakeUp
394 volatile uint32_t *_stopped;
395 pthread_t _pthread;
396 CFMutableSetRef _commonModes;
397 CFMutableSetRef _commonModeItems;
398 CFRunLoopModeRef _currentMode;
399 CFMutableSetRef _modes;
400 struct _block_item *_blocks_head;
401 struct _block_item *_blocks_tail;
402 #if DEPLOYMENT_TARGET_WINDOWS
403 DWORD _threadID;
404 __CFPort _msgUpdatePort;
405 #endif
406 CFTypeRef _counterpart;
407 };
408
409 #if DEPLOYMENT_TARGET_WINDOWS
410 void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl);
411 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl);
412 static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls);
413 CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam);
414 #endif
415
416 /* Bit 0 of the base reserved bits is used for stopped state */
417 /* Bit 1 of the base reserved bits is used for sleeping state */
418 /* Bit 2 of the base reserved bits is used for deallocating state */
419
420 CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
421 return (rl->_stopped && rl->_stopped[2]) ? true : false;
422 }
423
424 CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
425 if (!rl->_stopped) {
426 rl->_stopped = (uint32_t volatile *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 4 * sizeof(uint32_t), 0);
427 rl->_stopped[0] = 0x4346524C;
428 rl->_stopped[1] = 0x4346524C; // 'CFRL'
429 rl->_stopped[2] = 0x00000000; // here the value is stored
430 rl->_stopped[3] = 0x4346524C;
431 }
432 if (rl->_stopped) rl->_stopped[2] = 0x53544F50; // 'STOP'
433 }
434
435 CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
436 if (rl->_stopped) rl->_stopped[2] = 0x0;
437 }
438
439 CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
440 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1);
441 }
442
443 CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
444 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
445 }
446
447 CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
448 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
449 }
450
451 CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
452 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2);
453 }
454
455 CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
456 __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
457 }
458
459 CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
460 __CFSpinLock(&(((CFRunLoopRef)rl)->_lock));
461 }
462
463 CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
464 __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock));
465 }
466
467 static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) {
468 CFRunLoopRef rl = (CFRunLoopRef)cf;
469 CFMutableStringRef result;
470 result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
471 #if DEPLOYMENT_TARGET_WINDOWS
472 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), "unknown", rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)"));
473 #else
474 CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup 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)"));
475 #endif
476 CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
477 return result;
478 }
479
480 __private_extern__ void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it
481 CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
482 }
483
484 /* call with rl locked */
485 static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
486 CHECK_FOR_FORK();
487 CFRunLoopModeRef rlm;
488 struct __CFRunLoopMode srlm;
489 memset(&srlm, 0, sizeof(srlm));
490 srlm._base._cfisa = __CFISAForTypeID(__kCFRunLoopModeTypeID);
491 _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID);
492 srlm._name = modeName;
493 rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
494 if (NULL != rlm) {
495 __CFRunLoopModeLock(rlm);
496 return rlm;
497 }
498 if (!create) {
499 return NULL;
500 }
501 rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
502 if (NULL == rlm) {
503 return NULL;
504 }
505 CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock);
506 rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
507 rlm->_stopped = false;
508 rlm->_portToV1SourceMap = NULL;
509 rlm->_sources = NULL;
510 rlm->_observers = NULL;
511 rlm->_timers = NULL;
512 rlm->_submodes = NULL;
513 rlm->_observerMask = 0;
514 rlm->_portSet = __CFPortSetAllocate();
515 if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT;
516 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
517 rlm->_kq = -1;
518 #endif
519 #if DEPLOYMENT_TARGET_WINDOWS
520 rlm->_msgQMask = 0;
521 #endif
522 CFSetAddValue(rl->_modes, rlm);
523 CFRelease(rlm);
524 __CFRunLoopModeLock(rlm); /* return mode locked */
525 return rlm;
526 }
527
528
529 // expects rl and rlm locked
530 static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
531 CHECK_FOR_FORK();
532 if (NULL == rlm) return true;
533 #if DEPLOYMENT_TARGET_WINDOWS
534 if (0 != rlm->_msgQMask) return false;
535 #endif
536 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
537 Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ)));
538 if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue
539 #endif
540 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false;
541 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false;
542 #if 1
543 struct _block_item *item = rl->_blocks_head;
544 while (item) {
545 struct _block_item *curr = item;
546 item = item->_next;
547 Boolean doit = false;
548 if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
549 doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
550 } else {
551 doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
552 }
553 if (doit) return false;
554 }
555 #endif
556 if (NULL != rlm->_submodes) {
557 CFIndex idx, cnt;
558 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
559 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
560 CFRunLoopModeRef subrlm;
561 Boolean subIsEmpty;
562 subrlm = __CFRunLoopFindMode(rl, modeName, false);
563 subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm, previousMode) : true;
564 if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm);
565 if (!subIsEmpty) return false;
566 }
567 }
568 return true;
569 }
570
571 #if DEPLOYMENT_TARGET_WINDOWS
572 DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) {
573 CFRunLoopModeRef rlm;
574 DWORD result = 0;
575 __CFRunLoopLock(rl);
576 rlm = __CFRunLoopFindMode(rl, modeName, false);
577 if (rlm) {
578 result = rlm->_msgQMask;
579 __CFRunLoopModeUnlock(rlm);
580 }
581 __CFRunLoopUnlock(rl);
582 return result;
583 }
584
585 void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) {
586 CFRunLoopModeRef rlm;
587 __CFRunLoopLock(rl);
588 rlm = __CFRunLoopFindMode(rl, modeName, true);
589 rlm->_msgQMask = mask;
590 __CFRunLoopModeUnlock(rlm);
591 __CFRunLoopUnlock(rl);
592 }
593 #endif
594
595 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
596
597 CF_INLINE Boolean __CFIsValid(const void *cf) {
598 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3);
599 }
600
601 CF_INLINE void __CFSetValid(void *cf) {
602 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
603 }
604
605 CF_INLINE void __CFUnsetValid(void *cf) {
606 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
607 }
608
609 struct __CFRunLoopSource {
610 CFRuntimeBase _base;
611 uint32_t _bits;
612 CFSpinLock_t _lock;
613 CFIndex _order; /* immutable */
614 CFMutableBagRef _runLoops;
615 union {
616 CFRunLoopSourceContext version0; /* immutable, except invalidation */
617 CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
618 } _context;
619 };
620
621 /* Bit 1 of the base reserved bits is used for signalled state */
622
623 CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
624 return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
625 }
626
627 CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
628 __CFBitfieldSetValue(rls->_bits, 1, 1, 1);
629 }
630
631 CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
632 __CFBitfieldSetValue(rls->_bits, 1, 1, 0);
633 }
634
635 CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) {
636 __CFSpinLock(&(rls->_lock));
637 }
638
639 CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
640 __CFSpinUnlock(&(rls->_lock));
641 }
642
643 /* rlm is not locked */
644 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
645 //printf("Scheduling source %p with mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
646 __CFRunLoopSourceLock(rls);
647 if (NULL == rls->_runLoops) {
648 rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops!
649 }
650 CFBagAddValue(rls->_runLoops, rl);
651 __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety
652 if (0 == rls->_context.version0.version) {
653 if (NULL != rls->_context.version0.schedule) {
654 rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name);
655 }
656 } else if (1 == rls->_context.version0.version) {
657 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
658 if (CFPORT_NULL != port) {
659 __CFPortSetInsert(port, rlm->_portSet);
660 }
661 #if DEPLOYMENT_TARGET_WINDOWS
662 __CFRunLoopLock(rl);
663 //#warning Bug here - if rl->_currentMode is NULL and rlm == the default mode, we should also update
664 if (rl->_currentMode == rlm) {
665 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
666 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl);
667 else
668 __CFRunLoopUpdateMsgWait(rl);
669 }
670 __CFRunLoopUnlock(rl);
671 #endif
672 }
673 }
674
675 /* rlm is not locked */
676 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */
677 //printf("Cancelling source %p from mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl);
678 __CFRunLoopSourceLock(rls);
679 if (NULL != rls->_runLoops) {
680 CFBagRemoveValue(rls->_runLoops, rl);
681 }
682 __CFRunLoopSourceUnlock(rls);
683 if (0 == rls->_context.version0.version) {
684 if (NULL != rls->_context.version0.cancel) {
685 rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */
686 }
687 } else if (1 == rls->_context.version0.version) {
688 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
689 if (CFPORT_NULL != port) {
690 __CFPortSetRemove(port, rlm->_portSet);
691 }
692 #if DEPLOYMENT_TARGET_WINDOWS
693 __CFRunLoopLock(rl);
694 //#warning Bug here - must also update if rl->_currentMode == NULL and rlm == default mode
695 if (rl->_currentMode == rlm && rl->_msgUpdatePort != CFPORT_NULL) {
696 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
697 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl);
698 else
699 __CFRunLoopUpdateMsgWait(rl);
700 }
701 __CFRunLoopUnlock(rl);
702 #endif
703 }
704 }
705
706 struct __CFRunLoopObserver {
707 CFRuntimeBase _base;
708 CFSpinLock_t _lock;
709 CFRunLoopRef _runLoop;
710 CFIndex _rlCount;
711 CFOptionFlags _activities; /* immutable */
712 CFIndex _order; /* immutable */
713 CFRunLoopObserverCallBack _callout; /* immutable */
714 CFRunLoopObserverContext _context; /* immutable, except invalidation */
715 };
716
717 /* Bit 0 of the base reserved bits is used for firing state */
718 /* Bit 1 of the base reserved bits is used for repeats state */
719
720 CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
721 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0);
722 }
723
724 CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
725 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
726 }
727
728 CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
729 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
730 }
731
732 CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
733 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1);
734 }
735
736 CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
737 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
738 }
739
740 CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
741 __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
742 }
743
744 CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
745 __CFSpinLock(&(rlo->_lock));
746 }
747
748 CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
749 __CFSpinUnlock(&(rlo->_lock));
750 }
751
752 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
753 __CFRunLoopObserverLock(rlo);
754 if (0 == rlo->_rlCount) {
755 rlo->_runLoop = rl;
756 }
757 rlo->_rlCount++;
758 __CFRunLoopObserverUnlock(rlo);
759 }
760
761 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
762 __CFRunLoopObserverLock(rlo);
763 rlo->_rlCount--;
764 if (0 == rlo->_rlCount) {
765 rlo->_runLoop = NULL;
766 }
767 __CFRunLoopObserverUnlock(rlo);
768 }
769
770 struct __CFRunLoopTimer {
771 CFRuntimeBase _base;
772 CFSpinLock_t _lock;
773 CFRunLoopRef _runLoop;
774 CFMutableSetRef _rlModes;
775 CFAbsoluteTime _nextFireDate;
776 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
777 mach_port_name_t _port;
778 int64_t _fireTSR; /* TSR units */
779 int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */
780 #elif DEPLOYMENT_TARGET_WINDOWS
781 CFIndex _rlCount;
782 int64_t _fireTSR; /* TSR units */
783 int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */
784 #endif
785 CFTimeInterval _interval; /* immutable */
786 CFIndex _order; /* immutable */
787 CFRunLoopTimerCallBack _callout; /* immutable */
788 CFRunLoopTimerContext _context; /* immutable, except invalidation */
789 };
790
791 /* Bit 0 of the base reserved bits is used for firing state */
792 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
793
794 CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
795 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0);
796 }
797
798 CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
799 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
800 }
801
802 CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
803 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
804 }
805
806 CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) {
807 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1);
808 }
809
810 CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) {
811 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
812 }
813
814 CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) {
815 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
816 }
817
818 CF_INLINE Boolean __CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt) {
819 return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2);
820 }
821
822 CF_INLINE void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt) {
823 __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
824 }
825
826 CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
827 __CFSpinLock(&(rlt->_lock));
828 }
829
830 CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
831 __CFSpinUnlock(&(rlt->_lock));
832 }
833
834 static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit;
835
836 CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
837 __CFSpinLock(&__CFRLTFireTSRLock);
838 }
839
840 CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
841 __CFSpinUnlock(&__CFRLTFireTSRLock);
842 }
843
844 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
845 static CFMutableDictionaryRef __CFRLTPortMap = NULL;
846 static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit;
847
848 CF_INLINE void __CFRunLoopTimerPortMapLock(void) {
849 __CFSpinLock(&__CFRLTPortMapLock);
850 }
851
852 CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) {
853 __CFSpinUnlock(&__CFRLTPortMapLock);
854 }
855 #endif
856
857 static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt);
858
859 // called with timer locked in libdispatch mode
860 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt) {
861 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
862 mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
863 #endif
864 }
865
866 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
867 //CFLog(4, CFSTR("__CFRunLoopTimerSchedule(%p, loop %p, mode %@) [%p, %p]"), rlt, rl, rlm->_name, rlt->_runLoop, rlt->_port);
868 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
869 __CFRunLoopTimerLock(rlt);
870 if (NULL == rlt->_runLoop) {
871 rlt->_runLoop = rl;
872 if (MACH_PORT_NULL == rlt->_port) {
873 rlt->_port = mk_timer_create();
874 }
875 __CFRunLoopTimerPortMapLock();
876 if (NULL == __CFRLTPortMap) {
877 __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
878 }
879 CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt);
880 __CFRunLoopTimerPortMapUnlock();
881 __CFRunLoopTimerRescheduleWithAllModes(rlt);
882 }
883 mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet);
884 CFSetAddValue(rlt->_rlModes, rlm->_name);
885 __CFRunLoopTimerUnlock(rlt);
886 #elif DEPLOYMENT_TARGET_WINDOWS
887 if (0 == rlt->_rlCount) {
888 rlt->_runLoop = rl;
889 }
890 rlt->_rlCount++;
891 #endif
892 }
893
894 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
895 //CFLog(6, CFSTR("__CFRunLoopTimerCancel(rlt %p, rl %p, rlm %@)"), rlt, rl, rlm->_name);
896 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
897 __CFRunLoopTimerLock(rlt);
898 CFSetRemoveValue(rlt->_rlModes, rlm->_name);
899 __CFPortSetRemove(rlt->_port, rlm->_portSet);
900 if (0 == CFSetGetCount(rlt->_rlModes)) {
901 __CFRunLoopTimerPortMapLock();
902 if (NULL != __CFRLTPortMap) {
903 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port);
904 }
905 __CFRunLoopTimerPortMapUnlock();
906 mk_timer_cancel(rlt->_port, NULL);
907 rlt->_runLoop = NULL;
908 }
909 __CFRunLoopTimerUnlock(rlt);
910 #elif DEPLOYMENT_TARGET_WINDOWS
911 CFRunLoopWakeUp(rl);
912 #endif
913 }
914
915 #if DEPLOYMENT_TARGET_WINDOWS
916
917 struct _collectTimersContext {
918 CFMutableArrayRef results;
919 int64_t cutoffTSR;
920 };
921
922 static void __CFRunLoopCollectTimers(const void *value, void *ctx) {
923 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
924 struct _collectTimersContext *context = (struct _collectTimersContext *)ctx;
925 if (rlt->_fireTSR <= context->cutoffTSR) {
926 if (NULL == context->results)
927 context->results = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
928 CFArrayAppendValue(context->results, rlt);
929 }
930 }
931
932 // RunLoop and RunLoopMode must be locked
933 static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl, CFRunLoopModeRef rlm, struct _collectTimersContext *ctxt) {
934 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
935 __CFRunLoopTimerFireTSRLock();
936 CFSetApplyFunction(rlm->_timers, __CFRunLoopCollectTimers, ctxt);
937 __CFRunLoopTimerFireTSRUnlock();
938 }
939 if (NULL != rlm->_submodes) {
940 CFIndex idx, cnt;
941 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
942 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
943 CFRunLoopModeRef subrlm;
944 subrlm = __CFRunLoopFindMode(rl, modeName, false);
945 if (NULL != subrlm) {
946 __CFRunLoopTimersToFireRecursive(rl, subrlm, ctxt);
947 __CFRunLoopModeUnlock(subrlm);
948 }
949 }
950 }
951 }
952
953 // RunLoop and RunLoopMode must be locked
954 static CFArrayRef __CFRunLoopTimersToFire(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
955 struct _collectTimersContext ctxt = {NULL, __CFReadTSR()};
956 __CFRunLoopTimersToFireRecursive(rl, rlm, &ctxt);
957 return ctxt.results;
958 }
959 #endif
960
961 /* CFRunLoop */
962
963 CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
964 CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
965
966 // call with rl and rlm locked
967 static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */
968 CHECK_FOR_FORK();
969 CFRunLoopSourceRef found = rlm->_portToV1SourceMap ? (CFRunLoopSourceRef)CFDictionaryGetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)port) : NULL;
970 if (NULL == found && NULL != rlm->_submodes) {
971 CFIndex idx, cnt;
972 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
973 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
974 CFRunLoopModeRef subrlm;
975 subrlm = __CFRunLoopFindMode(rl, modeName, false);
976 if (NULL != subrlm) {
977 found = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port);
978 __CFRunLoopModeUnlock(subrlm);
979 }
980 if (NULL != found) {
981 break;
982 }
983 }
984 }
985 return found;
986 }
987
988 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
989 // call with rl and rlm locked
990 static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) {
991 CHECK_FOR_FORK();
992 CFRunLoopTimerRef result = NULL;
993 __CFRunLoopTimerPortMapLock();
994 if (NULL != __CFRLTPortMap) {
995 result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port);
996 }
997 __CFRunLoopTimerPortMapUnlock();
998 return result;
999 }
1000 #endif
1001
1002 // Remove backreferences the mode's sources have to the rl (context);
1003 // the primary purpose of rls->_runLoops is so that Invalidation can remove
1004 // the source from the run loops it is in, but during deallocation of a
1005 // run loop, we already know that the sources are going to be punted
1006 // from it, so invalidation of sources does not need to remove from a
1007 // deallocating run loop.
1008 static void __CFRunLoopCleanseSources(const void *value, void *context) {
1009 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1010 CFRunLoopRef rl = (CFRunLoopRef)context;
1011 CFIndex idx, cnt;
1012 const void **list, *buffer[256];
1013 if (NULL == rlm->_sources) return;
1014 cnt = CFSetGetCount(rlm->_sources);
1015 list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
1016 CFSetGetValues(rlm->_sources, list);
1017 for (idx = 0; idx < cnt; idx++) {
1018 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
1019 __CFRunLoopSourceLock(rls);
1020 if (NULL != rls->_runLoops) {
1021 CFBagRemoveValue(rls->_runLoops, rl);
1022 }
1023 __CFRunLoopSourceUnlock(rls);
1024 }
1025 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1026 }
1027
1028 static void __CFRunLoopDeallocateSources(const void *value, void *context) {
1029 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1030 CFRunLoopRef rl = (CFRunLoopRef)context;
1031 CFIndex idx, cnt;
1032 const void **list, *buffer[256];
1033 if (NULL == rlm->_sources) return;
1034 cnt = CFSetGetCount(rlm->_sources);
1035 list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
1036 CFSetGetValues(rlm->_sources, list);
1037 for (idx = 0; idx < cnt; idx++) {
1038 CFRetain(list[idx]);
1039 }
1040 CFSetRemoveAllValues(rlm->_sources);
1041 for (idx = 0; idx < cnt; idx++) {
1042 __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm);
1043 CFRelease(list[idx]);
1044 }
1045 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1046 }
1047
1048 static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
1049 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1050 CFRunLoopRef rl = (CFRunLoopRef)context;
1051 CFIndex idx, cnt;
1052 const void **list, *buffer[256];
1053 if (NULL == rlm->_observers) return;
1054 cnt = CFSetGetCount(rlm->_observers);
1055 list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
1056 CFSetGetValues(rlm->_observers, list);
1057 for (idx = 0; idx < cnt; idx++) {
1058 CFRetain(list[idx]);
1059 }
1060 CFSetRemoveAllValues(rlm->_observers);
1061 for (idx = 0; idx < cnt; idx++) {
1062 __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm);
1063 CFRelease(list[idx]);
1064 }
1065 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1066 }
1067
1068 static void __CFRunLoopDeallocateTimers(const void *value, void *context) {
1069 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1070 CFRunLoopRef rl = (CFRunLoopRef)context;
1071 CFIndex idx, cnt;
1072 const void **list, *buffer[256];
1073 if (NULL == rlm->_timers) return;
1074 cnt = CFSetGetCount(rlm->_timers);
1075 list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
1076 CFSetGetValues(rlm->_timers, list);
1077 for (idx = 0; idx < cnt; idx++) {
1078 CFRetain(list[idx]);
1079 }
1080 CFSetRemoveAllValues(rlm->_timers);
1081 for (idx = 0; idx < cnt; idx++) {
1082 __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm);
1083 CFRelease(list[idx]);
1084 }
1085 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1086 }
1087
1088 CF_EXPORT pthread_t _CFMainPThread;
1089 CF_EXPORT CFRunLoopRef _CFRunLoopGet0b(pthread_t t);
1090
1091 static void __CFRunLoopDeallocate(CFTypeRef cf) {
1092 CFRunLoopRef rl = (CFRunLoopRef)cf;
1093
1094 if (_CFRunLoopGet0b(_CFMainPThread) == cf) HALT;
1095
1096 /* We try to keep the run loop in a valid state as long as possible,
1097 since sources may have non-retained references to the run loop.
1098 Another reason is that we don't want to lock the run loop for
1099 callback reasons, if we can get away without that. We start by
1100 eliminating the sources, since they are the most likely to call
1101 back into the run loop during their "cancellation". Common mode
1102 items will be removed from the mode indirectly by the following
1103 three lines. */
1104 __CFRunLoopSetDeallocating(rl);
1105 if (NULL != rl->_modes) {
1106 CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl
1107 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
1108 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
1109 CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
1110 }
1111 __CFRunLoopLock(rl);
1112 struct _block_item *item = rl->_blocks_head;
1113 while (item) {
1114 struct _block_item *curr = item;
1115 item = item->_next;
1116 CFRelease(curr->_mode);
1117 Block_release(curr->_block);
1118 free(curr);
1119 }
1120 if (NULL != rl->_commonModeItems) {
1121 CFRelease(rl->_commonModeItems);
1122 }
1123 if (NULL != rl->_commonModes) {
1124 CFRelease(rl->_commonModes);
1125 }
1126 if (NULL != rl->_modes) {
1127 CFRelease(rl->_modes);
1128 }
1129 __CFPortFree(rl->_wakeUpPort);
1130 rl->_wakeUpPort = CFPORT_NULL;
1131 #if DEPLOYMENT_TARGET_WINDOWS
1132 __CFPortFree(rl->_msgUpdatePort);
1133 rl->_msgUpdatePort = CFPORT_NULL;
1134 #endif
1135 __CFRunLoopUnlock(rl);
1136 memset((char *)cf + sizeof(CFRuntimeBase), 0x8C, sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase));
1137 }
1138
1139 static const CFRuntimeClass __CFRunLoopModeClass = {
1140 0,
1141 "CFRunLoopMode",
1142 NULL, // init
1143 NULL, // copy
1144 __CFRunLoopModeDeallocate,
1145 __CFRunLoopModeEqual,
1146 __CFRunLoopModeHash,
1147 NULL, //
1148 __CFRunLoopModeCopyDescription
1149 };
1150
1151 static const CFRuntimeClass __CFRunLoopClass = {
1152 0,
1153 "CFRunLoop",
1154 NULL, // init
1155 NULL, // copy
1156 __CFRunLoopDeallocate,
1157 NULL,
1158 NULL,
1159 NULL, //
1160 __CFRunLoopCopyDescription
1161 };
1162
1163 static void __CFFinalizeRunLoop(uintptr_t data);
1164
1165 __private_extern__ void __CFRunLoopInitialize(void) {
1166 __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);
1167 __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass);
1168 #if DEPLOYMENT_TARGET_WINDOWS
1169 __kCFRunLoopWakeUpMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopWakeup");
1170 __kCFRunLoopV1SourceReadyMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopV1Ready");
1171 #endif
1172 #if DEPLOYMENT_TARGET_WINDOWS
1173 if (~0 == __CFTSDKeyRunLoopKey) __CFTSDKeyRunLoopKey = TlsAlloc();
1174 #else
1175 pthread_key_init_np(__CFTSDKeyRunLoop, NULL);
1176 pthread_key_init_np(__CFTSDKeyRunLoopCntr, (void *)__CFFinalizeRunLoop);
1177 #endif
1178 }
1179
1180 CFTypeID CFRunLoopGetTypeID(void) {
1181 return __kCFRunLoopTypeID;
1182 }
1183
1184 static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
1185 CFRunLoopRef loop = NULL;
1186 CFRunLoopModeRef rlm;
1187 uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
1188 loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL);
1189 if (NULL == loop) {
1190 return NULL;
1191 }
1192 loop->_stopped = NULL;
1193 CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock);
1194 loop->_wakeUpPort = __CFPortAllocate();
1195 if (CFPORT_NULL == loop->_wakeUpPort) HALT;
1196 #if DEPLOYMENT_TARGET_WINDOWS
1197 loop->_msgUpdatePort = CFPORT_NULL;
1198 #endif
1199 loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
1200 CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
1201 loop->_commonModeItems = NULL;
1202 loop->_currentMode = NULL;
1203 loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
1204 _CFSetSetCapacity(loop->_modes, 10);
1205 loop->_blocks_head = NULL;
1206 loop->_blocks_tail = NULL;
1207 loop->_counterpart = NULL;
1208 loop->_pthread = t;
1209 rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
1210 if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
1211 return loop;
1212 }
1213
1214 static CFMutableDictionaryRef __CFRunLoops = NULL;
1215 static CFSpinLock_t loopsLock = CFSpinLockInit;
1216
1217 // should only be called by Foundation
1218 // t==0 is a synonym for "main thread" that always works
1219 CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
1220 if (pthread_equal(t, kNilPthreadT)) {
1221 t = _CFMainPThread;
1222 }
1223 __CFSpinLock(&loopsLock);
1224 if (!__CFRunLoops) {
1225 __CFSpinUnlock(&loopsLock);
1226 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
1227 CFRunLoopRef mainLoop = __CFRunLoopCreate(_CFMainPThread);
1228 CFDictionarySetValue(dict, pthreadPointer(_CFMainPThread), mainLoop);
1229 if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
1230 CFRelease(dict);
1231 }
1232 CFRelease(mainLoop);
1233 __CFSpinLock(&loopsLock);
1234 }
1235 CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1236 if (!loop) {
1237 __CFSpinUnlock(&loopsLock);
1238 CFRunLoopRef newLoop = __CFRunLoopCreate(t);
1239 __CFSpinLock(&loopsLock);
1240 loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1241 if (!loop) {
1242 CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
1243 loop = newLoop;
1244 }
1245 CFRelease(newLoop);
1246 }
1247 if (pthread_equal(t, pthread_self())) {
1248 #if DEPLOYMENT_TARGET_WINDOWS
1249 TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(PTHREAD_DESTRUCTOR_ITERATIONS-1));
1250 #else
1251 pthread_setspecific(__CFTSDKeyRunLoop, (void *)loop);
1252 if (0 == pthread_getspecific(__CFTSDKeyRunLoopCntr)) {
1253 pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1));
1254 }
1255 #endif
1256 #if DEPLOYMENT_TARGET_WINDOWS
1257 // Install our message hook so we can spin the runloop
1258 loop->_threadID = GetCurrentThreadId();
1259 //#if MARRY_MESSAGE_QUEUE
1260 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) {
1261 #ifdef _DEBUG
1262 __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation_debug.dll"), loop->_threadID);
1263 #else
1264 __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation.dll"), loop->_threadID);
1265 #endif
1266 }
1267 //#endif
1268 #endif
1269 }
1270 __CFSpinUnlock(&loopsLock);
1271 return loop;
1272 }
1273
1274 // should only be called by Foundation
1275 CFRunLoopRef _CFRunLoopGet0b(pthread_t t) {
1276 if (pthread_equal(t, kNilPthreadT)) {
1277 t = _CFMainPThread;
1278 }
1279 __CFSpinLock(&loopsLock);
1280 CFRunLoopRef loop = NULL;
1281 if (__CFRunLoops) {
1282 loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
1283 }
1284 __CFSpinUnlock(&loopsLock);
1285 return loop;
1286 }
1287
1288 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName);
1289
1290 // Called for each thread as it exits
1291 static void __CFFinalizeRunLoop(uintptr_t data) {
1292 CFRunLoopRef rl = NULL;
1293 if (data <= 1) {
1294 __CFSpinLock(&loopsLock);
1295 if (__CFRunLoops) {
1296 rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
1297 if (rl) CFRetain(rl);
1298 CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
1299 }
1300 __CFSpinUnlock(&loopsLock);
1301 } else {
1302 #if DEPLOYMENT_TARGET_WINDOWS
1303 TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(data - 1));
1304 #else
1305 pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(data - 1));
1306 #endif
1307 }
1308 if (rl && CFRunLoopGetMain() != rl) { // protect against cooperative threads
1309 if (NULL != rl->_counterpart) {
1310 CFRelease(rl->_counterpart);
1311 rl->_counterpart = NULL;
1312 }
1313 // purge all sources before deallocation
1314 CFArrayRef array = CFRunLoopCopyAllModes(rl);
1315 for (CFIndex idx = CFArrayGetCount(array); idx--;) {
1316 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
1317 __CFRunLoopRemoveAllSources(rl, modeName);
1318 }
1319 __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
1320 CFRelease(array);
1321 }
1322 if (rl) CFRelease(rl);
1323 }
1324
1325 pthread_t _CFRunLoopGet1(CFRunLoopRef rl) {
1326 return rl->_pthread;
1327 }
1328
1329 // should only be called by Foundation
1330 CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl) {
1331 CFTypeRef ret = NULL;
1332 __CFSpinLock(&loopsLock);
1333 if (NULL == rl->_counterpart) {
1334 Class cls = (Class)objc_lookUpClass("NSRunLoop");
1335 if (cls) {
1336 char hasMethod;
1337 CF_OBJC_CALL1(char, hasMethod, cls, "respondsToSelector:", sel_registerName("_new:"));
1338 if (hasMethod) {
1339 void *ns;
1340 CF_OBJC_CALL1(void *, ns, cls, "_new:", rl);
1341 rl->_counterpart = ns ? CFRetain(ns) : NULL;
1342 }
1343 }
1344 }
1345 ret = rl->_counterpart;
1346 __CFSpinUnlock(&loopsLock);
1347 return ret;
1348 }
1349
1350 // should only be called by Foundation
1351 CF_EXPORT CFTypeRef _CFRunLoopGet2b(CFRunLoopRef rl) {
1352 return rl->_counterpart;
1353 }
1354
1355 #if DEPLOYMENT_TARGET_MACOSX
1356 void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
1357 if (pthread_main_np()) return;
1358 CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
1359 if (rl != currentLoop) {
1360 CFRetain(currentLoop); // avoid a deallocation of the currentLoop inside the lock
1361 __CFSpinLock(&loopsLock);
1362 if (rl) {
1363 CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl);
1364 } else {
1365 CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
1366 }
1367 __CFSpinUnlock(&loopsLock);
1368 CFRelease(currentLoop);
1369 pthread_setspecific(__CFTSDKeyRunLoop, NULL);
1370 pthread_setspecific(__CFTSDKeyRunLoopCntr, 0);
1371 }
1372 }
1373 #endif
1374
1375 CFRunLoopRef CFRunLoopGetMain(void) {
1376 CHECK_FOR_FORK();
1377 static CFRunLoopRef __main = NULL; // no retain needed
1378 if (!__main) __main = _CFRunLoopGet0(_CFMainPThread); // no CAS needed
1379 return __main;
1380 }
1381
1382 CFRunLoopRef CFRunLoopGetCurrent(void) {
1383 CHECK_FOR_FORK();
1384 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1385 CFRunLoopRef rl = (CFRunLoopRef)pthread_getspecific(__CFTSDKeyRunLoop);
1386 if (rl) return rl;
1387 #endif
1388 return _CFRunLoopGet0(pthread_self());
1389 }
1390
1391 CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
1392 CHECK_FOR_FORK();
1393 CFStringRef result = NULL;
1394 __CFRunLoopLock(rl);
1395 if (NULL != rl->_currentMode) {
1396 result = (CFStringRef)CFRetain(rl->_currentMode->_name);
1397 }
1398 __CFRunLoopUnlock(rl);
1399 return result;
1400 }
1401
1402 static void __CFRunLoopGetModeName(const void *value, void *context) {
1403 CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
1404 CFMutableArrayRef array = (CFMutableArrayRef)context;
1405 CFArrayAppendValue(array, rlm->_name);
1406 }
1407
1408 CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) {
1409 CHECK_FOR_FORK();
1410 CFMutableArrayRef array;
1411 __CFRunLoopLock(rl);
1412 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks);
1413 CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array);
1414 __CFRunLoopUnlock(rl);
1415 return array;
1416 }
1417
1418 static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
1419 CFTypeRef item = (CFTypeRef)value;
1420 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1421 CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
1422 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1423 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
1424 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1425 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
1426 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1427 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
1428 }
1429 }
1430
1431 static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
1432 CFStringRef modeName = (CFStringRef)value;
1433 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1434 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
1435 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1436 CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
1437 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1438 CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
1439 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1440 CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
1441 }
1442 }
1443
1444 static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
1445 CFStringRef modeName = (CFStringRef)value;
1446 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
1447 CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
1448 if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) {
1449 CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
1450 } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
1451 CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
1452 } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
1453 CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
1454 }
1455 }
1456
1457 CF_EXPORT Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) {
1458 __CFRunLoopLock(rl);
1459 Boolean present = CFSetContainsValue(rl->_commonModes, modeName);
1460 __CFRunLoopUnlock(rl);
1461 return present;
1462 }
1463
1464 void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
1465 CHECK_FOR_FORK();
1466 if (__CFRunLoopIsDeallocating(rl)) return;
1467 __CFRunLoopLock(rl);
1468 if (!CFSetContainsValue(rl->_commonModes, modeName)) {
1469 CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
1470 CFSetAddValue(rl->_commonModes, modeName);
1471 __CFRunLoopUnlock(rl);
1472 if (NULL != set) {
1473 CFTypeRef context[2] = {rl, modeName};
1474 /* add all common-modes items to new mode */
1475 CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
1476 CFRelease(set);
1477 }
1478 } else {
1479 __CFRunLoopUnlock(rl);
1480 }
1481 }
1482
1483 static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFStringRef curMode) { // Call with rl locked
1484 if (!rl->_blocks_head) return false;
1485 if (!curMode) return false;
1486 Boolean did = false;
1487 CFAbsoluteTime deadline = CFAbsoluteTimeGetCurrent() + 0.0009765625;
1488 struct _block_item *head = rl->_blocks_head;
1489 struct _block_item *tail = rl->_blocks_tail;
1490 rl->_blocks_head = NULL;
1491 rl->_blocks_tail = NULL;
1492 CFSetRef commonModes = rl->_commonModes;
1493 __CFRunLoopUnlock(rl);
1494 struct _block_item *prev = NULL;
1495 struct _block_item *item = head;
1496 while (item && CFAbsoluteTimeGetCurrent() < deadline) {
1497 struct _block_item *curr = item;
1498 item = item->_next;
1499 Boolean doit = false;
1500 if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
1501 doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
1502 } else {
1503 doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
1504 }
1505 if (!doit) prev = curr;
1506 if (doit) {
1507 if (prev) prev->_next = item;
1508 if (curr == head) head = item;
1509 if (curr == tail) tail = prev;
1510 void (^block)(void) = curr->_block;
1511 CFRelease(curr->_mode);
1512 free(curr);
1513 if (doit) {
1514 block(); // rl is not locked, mode is not locked
1515 did = true;
1516 }
1517 Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
1518 }
1519 }
1520 __CFRunLoopLock(rl);
1521 if (head) {
1522 tail->_next = rl->_blocks_head;
1523 rl->_blocks_head = head;
1524 if (!rl->_blocks_tail) rl->_blocks_tail = tail;
1525 }
1526 return did;
1527 }
1528
1529 static CFComparisonResult __CFRunLoopObserverQSortComparator(const void *val1, const void *val2, void *context) {
1530 CFRunLoopObserverRef o1 = *((CFRunLoopObserverRef *)val1);
1531 CFRunLoopObserverRef o2 = *((CFRunLoopObserverRef *)val2);
1532 if (!o1) {
1533 return (!o2) ? kCFCompareEqualTo : kCFCompareLessThan;
1534 }
1535 if (!o2) {
1536 return kCFCompareGreaterThan;
1537 }
1538 if (o1->_order < o2->_order) return kCFCompareLessThan;
1539 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
1540 return kCFCompareEqualTo;
1541 }
1542
1543
1544 /* rl is unlocked, rlm is locked on entrance and exit */
1545 /* ALERT: this should collect all the candidate observers from the top level
1546 * and all submodes, recursively, THEN start calling them, in order to obey
1547 * the ordering parameter. */
1548 static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
1549 CHECK_FOR_FORK();
1550 CFIndex idx, cnt;
1551 CFArrayRef submodes;
1552
1553 /* Fire the observers */
1554 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
1555 if (NULL != rlm->_observers) {
1556 cnt = CFSetGetCount(rlm->_observers);
1557 if (0 < cnt) {
1558 STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
1559 CFRunLoopObserverRef *collectedObservers = (CFRunLoopObserverRef *)((cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0));
1560 CFSetGetValues(rlm->_observers, (const void **)collectedObservers);
1561 for (idx = 0; idx < cnt; idx++) {
1562 CFRunLoopObserverRef rlo = collectedObservers[idx];
1563 if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
1564 CFRetain(rlo);
1565 } else {
1566 /* We're not interested in this one - set it to NULL so we don't process it later */
1567 collectedObservers[idx] = NULL;
1568 }
1569 }
1570 __CFRunLoopModeUnlock(rlm);
1571 CFQSortArray(collectedObservers, cnt, sizeof(CFRunLoopObserverRef), __CFRunLoopObserverQSortComparator, NULL);
1572 for (idx = 0; idx < cnt; idx++) {
1573 CFRunLoopObserverRef rlo = collectedObservers[idx];
1574 if (rlo) {
1575 __CFRunLoopObserverLock(rlo);
1576 if (__CFIsValid(rlo)) {
1577 __CFRunLoopObserverUnlock(rlo);
1578 __CFRunLoopObserverSetFiring(rlo);
1579 rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */
1580 __CFRunLoopObserverUnsetFiring(rlo);
1581 if (!__CFRunLoopObserverRepeats(rlo)) {
1582 CFRunLoopObserverInvalidate(rlo);
1583 }
1584 } else {
1585 __CFRunLoopObserverUnlock(rlo);
1586 }
1587 CFRelease(rlo);
1588 }
1589 }
1590 __CFRunLoopModeLock(rlm);
1591 if (collectedObservers != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, collectedObservers);
1592 }
1593 }
1594 if (NULL != submodes) {
1595 __CFRunLoopModeUnlock(rlm);
1596 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
1597 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
1598 CFRunLoopModeRef subrlm;
1599 __CFRunLoopLock(rl);
1600 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1601 __CFRunLoopUnlock(rl);
1602 if (NULL != subrlm) {
1603 __CFRunLoopDoObservers(rl, subrlm, activity);
1604 __CFRunLoopModeUnlock(subrlm);
1605 }
1606 }
1607 CFRelease(submodes);
1608 __CFRunLoopModeLock(rlm);
1609 }
1610 }
1611
1612 static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) {
1613 CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1;
1614 CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2;
1615 if (o1->_order < o2->_order) return kCFCompareLessThan;
1616 if (o2->_order < o1->_order) return kCFCompareGreaterThan;
1617 return kCFCompareEqualTo;
1618 }
1619
1620 static void __CFRunLoopCollectSources0(const void *value, void *context) {
1621 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
1622 CFTypeRef *sources = (CFTypeRef *)context;
1623 if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) {
1624 if (NULL == *sources) {
1625 *sources = CFRetain(rls);
1626 } else if (CFGetTypeID(*sources) == __kCFRunLoopSourceTypeID) {
1627 CFTypeRef oldrls = *sources;
1628 *sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1629 CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls);
1630 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1631 CFRelease(oldrls);
1632 } else {
1633 CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
1634 }
1635 }
1636 }
1637
1638 /* rl is unlocked, rlm is locked on entrance and exit */
1639 static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */
1640 CHECK_FOR_FORK();
1641 CFTypeRef sources = NULL;
1642 Boolean sourceHandled = false;
1643 CFIndex idx, cnt;
1644
1645 __CFRunLoopModeUnlock(rlm); // locks have to be taken in order
1646 __CFRunLoopLock(rl);
1647 __CFRunLoopModeLock(rlm);
1648 /* Fire the version 0 sources */
1649 if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) {
1650 CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources);
1651 }
1652 for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1653 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1654 CFRunLoopModeRef subrlm;
1655 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1656 if (NULL != subrlm) {
1657 if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) {
1658 CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources);
1659 }
1660 __CFRunLoopModeUnlock(subrlm);
1661 }
1662 }
1663 __CFRunLoopUnlock(rl);
1664 if (NULL != sources) {
1665 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1666 __CFRunLoopModeUnlock(rlm);
1667 if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) {
1668 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
1669 __CFRunLoopSourceLock(rls);
1670 #if DEPLOYMENT_TARGET_WINDOWS
1671 if (__CFRunLoopSourceIsSignaled(rls)) {
1672 #endif
1673 __CFRunLoopSourceUnsetSignaled(rls);
1674 if (__CFIsValid(rls)) {
1675 __CFRunLoopSourceUnlock(rls);
1676 if (NULL != rls->_context.version0.perform) {
1677 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1678 CHECK_FOR_FORK();
1679 }
1680 sourceHandled = true;
1681 } else {
1682 __CFRunLoopSourceUnlock(rls);
1683 }
1684 #if DEPLOYMENT_TARGET_WINDOWS
1685 } else {
1686 __CFRunLoopSourceUnlock(rls);
1687 }
1688 #endif
1689 } else {
1690 cnt = CFArrayGetCount((CFArrayRef)sources);
1691 CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
1692 for (idx = 0; idx < cnt; idx++) {
1693 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx);
1694 __CFRunLoopSourceLock(rls);
1695 #if DEPLOYMENT_TARGET_WINDOWS
1696 if (__CFRunLoopSourceIsSignaled(rls)) {
1697 #endif
1698 __CFRunLoopSourceUnsetSignaled(rls);
1699 if (__CFIsValid(rls)) {
1700 __CFRunLoopSourceUnlock(rls);
1701 if (NULL != rls->_context.version0.perform) {
1702 rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */
1703 CHECK_FOR_FORK();
1704 }
1705 sourceHandled = true;
1706 } else {
1707 __CFRunLoopSourceUnlock(rls);
1708 }
1709 #if DEPLOYMENT_TARGET_WINDOWS
1710 } else {
1711 __CFRunLoopSourceUnlock(rls);
1712 }
1713 #endif
1714 if (stopAfterHandle && sourceHandled) {
1715 break;
1716 }
1717 }
1718 }
1719 CFRelease(sources);
1720 __CFRunLoopModeLock(rlm);
1721 }
1722 return sourceHandled;
1723 }
1724
1725 // msg, size and reply are unused on Windows
1726 static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls
1727 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1728 , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply
1729 #endif
1730 ) { /* DOES CALLOUT */
1731 CHECK_FOR_FORK();
1732 Boolean sourceHandled = false;
1733
1734 /* Fire a version 1 source */
1735 CFRetain(rls);
1736 __CFRunLoopModeUnlock(rlm);
1737 __CFRunLoopSourceLock(rls);
1738 if (__CFIsValid(rls)) {
1739 __CFRunLoopSourceUnsetSignaled(rls);
1740 __CFRunLoopSourceUnlock(rls);
1741 if (NULL != rls->_context.version1.perform) {
1742 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1743 *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */
1744 CHECK_FOR_FORK();
1745 #else
1746 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
1747 rls->_context.version1.perform(rls->_context.version1.info); /* CALLOUT */
1748 CHECK_FOR_FORK();
1749 #endif
1750 } else {
1751 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); }
1752 }
1753 sourceHandled = true;
1754 } else {
1755 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
1756 __CFRunLoopSourceUnlock(rls);
1757 }
1758 CFRelease(rls);
1759 __CFRunLoopModeLock(rlm);
1760 return sourceHandled;
1761 }
1762
1763 // mode is locked on entry and exit
1764 static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
1765 Boolean timerHandled = false, timerEarly = false;
1766 int64_t oldFireTSR = 0;
1767
1768 /* Fire a timer */
1769 CFRetain(rlt);
1770 __CFRunLoopModeUnlock(rlm);
1771 if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
1772 void *context_info = NULL;
1773 void (*context_release)(const void *) = NULL;
1774 if (rlt->_context.retain) {
1775 context_info = (void *)rlt->_context.retain(rlt->_context.info);
1776 context_release = rlt->_context.release;
1777 } else {
1778 context_info = rlt->_context.info;
1779 }
1780 __CFRunLoopTimerUnsetDidFire(rlt);
1781 __CFRunLoopTimerSetFiring(rlt);
1782 //CFLog(4, CFSTR("Firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1783 __CFRunLoopTimerFireTSRLock();
1784 oldFireTSR = rlt->_fireTSR;
1785 __CFRunLoopTimerFireTSRUnlock();
1786 if (0 && CFAbsoluteTimeGetCurrent() < rlt->_nextFireDate) { // not enabled at this time -- causes trouble when clock goes backwards
1787 timerEarly = true;
1788 } else {
1789 rlt->_callout(rlt, context_info); /* CALLOUT */
1790 CHECK_FOR_FORK();
1791 timerHandled = true;
1792 }
1793 //CFLog(4, CFSTR("Done firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name);
1794 __CFRunLoopTimerUnsetFiring(rlt);
1795 if (context_release) {
1796 context_release(context_info);
1797 }
1798 } else {
1799 // If the timer fires while it is firing in a higher activiation,
1800 // it is not allowed to fire, but we have to remember that fact.
1801 // Later, if the timer's fire date is being handled manually, we
1802 // need to re-arm the kernel timer, since it has possibly already
1803 // fired (this firing which is being skipped, say) and the timer
1804 // will permanently stop if we completely drop this firing.
1805 if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt);
1806 }
1807 if (__CFIsValid(rlt) && timerHandled) {
1808 if (0.0 == rlt->_interval) {
1809 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
1810 } else {
1811 /* This is just a little bit tricky: we want to support calling
1812 * CFRunLoopTimerSetNextFireDate() from within the callout and
1813 * honor that new time here if it is a later date, otherwise
1814 * it is completely ignored. */
1815 __CFRunLoopTimerFireTSRLock();
1816 int64_t currentFireTSR = rlt->_fireTSR;
1817 if (oldFireTSR < currentFireTSR) {
1818 /* Next fire TSR was set, and set to a date after the previous
1819 * fire date, so we honor it. */
1820 if (__CFRunLoopTimerDidFire(rlt)) {
1821 __CFRunLoopTimerRescheduleWithAllModes(rlt);
1822 __CFRunLoopTimerUnsetDidFire(rlt);
1823 }
1824 } else {
1825 if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) {
1826 currentFireTSR = LLONG_MAX;
1827 } else {
1828 int64_t currentTSR = (int64_t)__CFReadTSR();
1829 currentFireTSR = oldFireTSR;
1830 while (currentFireTSR <= currentTSR) {
1831 currentFireTSR += rlt->_intervalTSR;
1832 }
1833 }
1834 rlt->_fireTSR = currentFireTSR;
1835 __CFRunLoopTimerRescheduleWithAllModes(rlt);
1836 }
1837 __CFRunLoopTimerFireTSRUnlock();
1838 }
1839 }
1840 if (__CFIsValid(rlt) && timerEarly) {
1841 int64_t now2 = (int64_t)mach_absolute_time();
1842 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
1843 __CFRunLoopTimerFireTSRLock();
1844 if (rlt->_nextFireDate < now1) {
1845 rlt->_fireTSR = now2;
1846 } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < rlt->_nextFireDate) {
1847 rlt->_fireTSR = LLONG_MAX;
1848 } else {
1849 rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(rlt->_nextFireDate - now1);
1850 }
1851 __CFRunLoopTimerRescheduleWithAllModes(rlt);
1852 __CFRunLoopTimerFireTSRUnlock();
1853 }
1854 CFRelease(rlt);
1855 __CFRunLoopModeLock(rlm);
1856 return timerHandled;
1857 }
1858
1859 CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
1860 CHECK_FOR_FORK();
1861 CFRunLoopModeRef rlm;
1862 Boolean result = false;
1863 __CFRunLoopLock(rl);
1864 rlm = __CFRunLoopFindMode(rl, modeName, false);
1865 if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm, NULL)) {
1866 result = true;
1867 }
1868 __CFRunLoopUnlock(rl);
1869 if (rlm) __CFRunLoopModeUnlock(rlm);
1870 return result;
1871 }
1872
1873 // rl is locked, rlm is locked on entry and exit
1874 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) {
1875 CFIndex idx, cnt;
1876 const void **list, *buffer[256];
1877
1878 // Timers and version 1 sources go into the portSet currently
1879 if (NULL != rlm->_sources) {
1880 cnt = CFSetGetCount(rlm->_sources);
1881 list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
1882 CFSetGetValues(rlm->_sources, list);
1883 for (idx = 0; idx < cnt; idx++) {
1884 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
1885 if (1 == rls->_context.version0.version) {
1886 __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */
1887 if (CFPORT_NULL != port) {
1888 __CFPortSetInsert(port, portSet);
1889 }
1890 }
1891 }
1892 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1893 }
1894 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1895 if (NULL != rlm->_timers) {
1896 cnt = CFSetGetCount(rlm->_timers);
1897 list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
1898 CFSetGetValues(rlm->_timers, list);
1899 for (idx = 0; idx < cnt; idx++) {
1900 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx];
1901 if (MACH_PORT_NULL != rlt->_port) {
1902 mach_port_insert_member(mach_task_self(), rlt->_port, portSet);
1903 }
1904 }
1905 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1906 }
1907 #endif
1908 // iterate over submodes
1909 for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
1910 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
1911 CFRunLoopModeRef subrlm;
1912 subrlm = __CFRunLoopFindMode(rl, modeName, false);
1913 if (NULL != subrlm) {
1914 __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet);
1915 __CFRunLoopModeUnlock(subrlm);
1916 }
1917 }
1918 }
1919
1920 static __CFPortSet _LastMainWaitSet = 0;
1921
1922 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1923 // return NO if we're the main runloop and there are no messages waiting on the port set
1924 int _CFRunLoopInputsReady(void) {
1925 CHECK_FOR_FORK();
1926 if (!pthread_main_np()) return true;
1927
1928 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1929 if (_LastMainWaitSet == MACH_PORT_NULL) return false;
1930
1931 // prepare a message header with no space for any data, nor a trailer
1932 mach_msg_header_t msg;
1933 msg.msgh_size = sizeof(msg); // just the header, ma'am
1934 // need the waitset, actually XXX
1935 msg.msgh_local_port = _LastMainWaitSet;
1936 msg.msgh_remote_port = MACH_PORT_NULL;
1937 msg.msgh_id = 0;
1938
1939 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);
1940
1941 return (MACH_RCV_TOO_LARGE == ret);
1942 return true;
1943 }
1944 #endif
1945
1946 #if 0
1947 static void print_msg_scan_header(void) {
1948 printf("======== ======== ======== ========\n");
1949 printf("description\tport\tport type\t\treferences\n");
1950 }
1951
1952 static void print_one_port_info(const char *desc, mach_port_t port, mach_msg_type_name_t type) {
1953 mach_port_urefs_t refs;
1954 kern_return_t ret = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs);
1955 if (ret != KERN_SUCCESS) refs = 0;
1956 const char *type_name = "???";
1957 switch (type) {
1958 case MACH_MSG_TYPE_MOVE_SEND: type_name = "MACH_MSG_TYPE_MOVE_SEND"; break;
1959 case MACH_MSG_TYPE_MOVE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break;
1960 case MACH_MSG_TYPE_MOVE_RECEIVE: type_name = "MACH_MSG_TYPE_MOVE_RECEIVE"; break;
1961 case MACH_MSG_TYPE_MAKE_SEND: type_name = "MACH_MSG_TYPE_MAKE_SEND"; break;
1962 case MACH_MSG_TYPE_MAKE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break;
1963 }
1964 printf("%s\t%p\t%-20s\t%u\n", desc, port, type_name, refs);
1965 }
1966
1967 static void mach_msg_scan(mach_msg_header_t *msg, int clean) {
1968 Boolean printed_header = false;
1969 /*
1970 * The msgh_local_port field doesn't hold a port right.
1971 * The receive operation consumes the destination port right.
1972 */
1973 if (MACH_PORT_NULL != msg->msgh_remote_port) {
1974 if (! printed_header) print_msg_scan_header();
1975 printed_header = true;
1976 print_one_port_info("msg->msgh_remote_port", msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(msg->msgh_bits));
1977 }
1978 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1979 mach_msg_body_t *body = (mach_msg_body_t *) (msg + 1);
1980 mach_msg_descriptor_t *saddr = (mach_msg_descriptor_t *) ((mach_msg_base_t *) msg + 1);
1981 mach_msg_descriptor_t *eaddr = saddr + body->msgh_descriptor_count;
1982 for ( ; saddr < eaddr; saddr++) {
1983 switch (saddr->type.type) {
1984 case MACH_MSG_PORT_DESCRIPTOR:;
1985 mach_msg_port_descriptor_t *dsc = &saddr->port;
1986 if (! printed_header) print_msg_scan_header();
1987 printed_header = true;
1988 print_one_port_info("port in body", dsc->name, dsc->disposition);
1989 // if (clean) mach_port_deallocate(mach_task_self(), dsc->name);
1990 break;
1991 case MACH_MSG_OOL_PORTS_DESCRIPTOR:;
1992 mach_msg_ool_ports_descriptor_t *dsc2 = &saddr->ool_ports;
1993 mach_port_t *ports = (mach_port_t *) dsc2->address;
1994 for (mach_msg_type_number_t j = 0; j < dsc2->count; j++, ports++) {
1995 if (! printed_header) print_msg_scan_header();
1996 printed_header = true;
1997 print_one_port_info("port in OOL ports", *ports, dsc2->disposition);
1998 }
1999 break;
2000 }
2001 }
2002 }
2003 }
2004 #endif
2005
2006 static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) __attribute__((noinline));
2007 #if DEPLOYMENT_TARGET_WINDOWS
2008 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm);
2009 #endif
2010
2011 /* rl is unlocked, rlm locked on entrance and exit */
2012 static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) { /* DOES CALLOUT */
2013 int64_t termTSR;
2014 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2015 mach_port_name_t timeoutPort = MACH_PORT_NULL;
2016 mach_port_name_t dispatchPort = MACH_PORT_NULL;
2017 Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ)));
2018 if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF();
2019 #endif
2020 Boolean poll = false;
2021 Boolean firstPass = true;
2022
2023 if (__CFRunLoopIsStopped(rl)) {
2024 __CFRunLoopUnsetStopped(rl);
2025 return kCFRunLoopRunStopped;
2026 } else if (rlm->_stopped) {
2027 rlm->_stopped = false;
2028 return kCFRunLoopRunStopped;
2029 }
2030 if (seconds <= 0.0) {
2031 termTSR = 0;
2032 } else if (TIMER_INTERVAL_LIMIT < seconds) {
2033 termTSR = LLONG_MAX;
2034 } else {
2035 termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds);
2036 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2037 timeoutPort = mk_timer_create();
2038 mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR));
2039 #endif
2040 }
2041 if (seconds <= 0.0) {
2042 poll = true;
2043 }
2044 if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL;
2045 for (;;) {
2046 __CFPortSet waitSet = CFPORT_NULL;
2047 Boolean destroyWaitSet = false;
2048 CFRunLoopSourceRef rls;
2049 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2050 mach_msg_header_t *msg;
2051 kern_return_t ret;
2052 uint8_t buffer[2048];
2053 #else
2054 CFArrayRef timersToCall = NULL;
2055 #endif
2056 int32_t returnValue = 0;
2057 Boolean sourceHandledThisLoop = false;
2058
2059 // Do not handle blocks here, as there is already a handling at
2060 // the end of this loop, and that just makes for two handlings
2061 // in a row when the loop cycles.
2062 if (rlm->_observerMask & kCFRunLoopBeforeTimers || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
2063 if (rlm->_observerMask & kCFRunLoopBeforeSources || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
2064 if (rl->_blocks_head) {
2065 __CFRunLoopModeUnlock(rlm);
2066 __CFRunLoopLock(rl);
2067 __CFRunLoopDoBlocks(rl, rlm->_name);
2068 __CFRunLoopModeLock(rlm);
2069 __CFRunLoopUnlock(rl);
2070 }
2071
2072 sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle) || sourceHandledThisLoop;
2073
2074 if (sourceHandledThisLoop) {
2075 poll = true;
2076 if (rl->_blocks_head) {
2077 __CFRunLoopModeUnlock(rlm);
2078 __CFRunLoopLock(rl);
2079 __CFRunLoopDoBlocks(rl, rlm->_name);
2080 __CFRunLoopModeLock(rlm);
2081 __CFRunLoopUnlock(rl);
2082 }
2083 }
2084
2085 if (!poll) {
2086 if (rlm->_observerMask & kCFRunLoopBeforeWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
2087 // do not do any user callouts after this point (after notifying of sleeping)
2088 __CFRunLoopSetSleeping(rl);
2089 }
2090 if (NULL != rlm->_submodes) {
2091 // !!! what do we do if this doesn't succeed?
2092 waitSet = __CFPortSetAllocate();
2093 if (CFPORT_NULL == waitSet) HALT;
2094 __CFRunLoopModeUnlock(rlm);
2095 __CFRunLoopLock(rl);
2096 __CFRunLoopModeLock(rlm);
2097 __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet);
2098 __CFRunLoopUnlock(rl);
2099 destroyWaitSet = true;
2100 } else {
2101 waitSet = rlm->_portSet;
2102 }
2103 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2104 if (CFPORT_NULL != timeoutPort) {
2105 __CFPortSetInsert(timeoutPort, waitSet);
2106 }
2107 if (CFPORT_NULL != dispatchPort) {
2108 __CFPortSetInsert(dispatchPort, waitSet);
2109 }
2110 #endif
2111 if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet;
2112 __CFRunLoopModeUnlock(rlm);
2113
2114 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2115 if (kCFUseCollectableAllocator && !poll) {
2116 memset(buffer, 0, sizeof(buffer));
2117 objc_clear_stack(0);
2118 }
2119
2120 msg = (mach_msg_header_t *)buffer;
2121 msg->msgh_size = sizeof(buffer);
2122
2123 //static uint64_t _last_value = 0;
2124 //uint64_t new_val = mach_absolute_time();
2125 //printf(". %d before %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2126 //_last_value = new_val;
2127
2128 /* In that sleep of death what nightmares may come ... */
2129 try_receive:;
2130 msg->msgh_bits = 0;
2131 msg->msgh_local_port = waitSet;
2132 msg->msgh_remote_port = MACH_PORT_NULL;
2133 msg->msgh_id = 0;
2134 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_AV), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL);
2135
2136 if (MACH_RCV_TOO_LARGE == ret) {
2137 uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE);
2138 if (msg == (mach_msg_header_t *)buffer) msg = NULL;
2139 msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0);
2140 msg->msgh_size = newSize;
2141 goto try_receive;
2142 } else if (MACH_RCV_TIMED_OUT == ret) {
2143 // timeout, for poll
2144 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
2145 msg = NULL;
2146 } else if (MACH_MSG_SUCCESS != ret) {
2147 HALT;
2148 }
2149 //new_val = mach_absolute_time();
2150 //printf(". %d after %qd (%qd)\n", getpid(), new_val, new_val - _last_value);
2151 //_last_value = new_val;
2152 #elif DEPLOYMENT_TARGET_WINDOWS
2153 DWORD waitResult = WAIT_TIMEOUT;
2154 HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS];
2155 HANDLE *handles;
2156 uint32_t handleCount;
2157 Boolean freeHandles;
2158 if (destroyWaitSet) {
2159 // wait set is a local, no one else could modify it, no need to copy handles
2160 handles = waitSet->handles;
2161 handleCount = waitSet->used;
2162 freeHandles = FALSE;
2163 } else {
2164 // copy out the handles to be safe from other threads at work
2165 handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount);
2166 freeHandles = (handles != handleBuf);
2167 }
2168 // should msgQMask be an OR'ing of this and all submodes' masks?
2169 if (0 == GetQueueStatus(rlm->_msgQMask)) {
2170 DWORD timeout;
2171 if (poll)
2172 timeout = 0;
2173 else {
2174 int64_t nextStop;
2175 __CFRunLoopModeLock(rlm);
2176 nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm);
2177 if (nextStop <= 0)
2178 nextStop = termTSR;
2179 else if (nextStop > termTSR)
2180 nextStop = termTSR;
2181 // else the next stop is dictated by the next timer
2182 int64_t timeoutTSR = nextStop - __CFReadTSR();
2183 if (timeoutTSR < 0)
2184 timeout = 0;
2185 else {
2186 CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000;
2187 if (timeoutCF > MAXDWORD)
2188 timeout = INFINITE;
2189 else
2190 timeout = (DWORD)timeoutCF;
2191 }
2192 }
2193 waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout);
2194 }
2195 ResetEvent(rl->_wakeUpPort);
2196 #endif
2197 __CFRunLoopLock(rl);
2198 __CFRunLoopModeLock(rlm);
2199 __CFRunLoopUnlock(rl);
2200 if (destroyWaitSet) {
2201 __CFPortSetFree(waitSet);
2202 if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0;
2203 } else {
2204 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2205 if (CFPORT_NULL != timeoutPort) {
2206 __CFPortSetRemove(timeoutPort, waitSet);
2207 }
2208 if (CFPORT_NULL != dispatchPort) {
2209 __CFPortSetRemove(dispatchPort, waitSet);
2210 }
2211 #endif
2212 }
2213
2214 if (!poll) {
2215 __CFRunLoopUnsetSleeping(rl);
2216 if (rlm->_observerMask & kCFRunLoopAfterWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
2217 }
2218 poll = false;
2219 __CFRunLoopModeUnlock(rlm);
2220 __CFRunLoopLock(rl);
2221 __CFRunLoopModeLock(rlm);
2222
2223 __CFPort livePort = CFPORT_NULL;
2224 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2225 if (NULL != msg) {
2226 livePort = msg->msgh_local_port;
2227 }
2228 #elif DEPLOYMENT_TARGET_WINDOWS
2229 CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError());
2230 if (waitResult == WAIT_TIMEOUT) {
2231 // do nothing, just return to caller
2232 } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) {
2233 // a handle was signaled
2234 livePort = handles[waitResult-WAIT_OBJECT_0];
2235 } else if (waitResult == WAIT_OBJECT_0+handleCount) {
2236 // windows message received - the CFWindowsMessageQueue will pick this up when
2237 // the v0 RunLoopSources get their chance
2238 } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) {
2239 // an "abandoned mutex object"
2240 livePort = handles[waitResult-WAIT_ABANDONED_0];
2241 } else {
2242 CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult);
2243 }
2244 if (freeHandles)
2245 CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
2246 timersToCall = __CFRunLoopTimersToFire(rl, rlm);
2247 #endif
2248
2249 if (CFPORT_NULL == livePort) {
2250 __CFRunLoopUnlock(rl);
2251 } else if (livePort == rl->_wakeUpPort) {
2252 // wakeup
2253 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); }
2254 __CFRunLoopUnlock(rl); // leave run loop unlocked
2255 }
2256 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2257 else if (livePort == timeoutPort) {
2258 returnValue = kCFRunLoopRunTimedOut;
2259 __CFRunLoopUnlock(rl);
2260 } else if (dispatchPort == livePort) {
2261 __CFRunLoopModeUnlock(rlm);
2262 __CFRunLoopUnlock(rl);
2263 pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)3);
2264 _dispatch_main_queue_callback_4CF(msg);
2265 sourceHandledThisLoop = true;
2266 pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)0);
2267 __CFRunLoopLock(rl);
2268 __CFRunLoopModeLock(rlm);
2269 __CFRunLoopUnlock(rl); // leave run loop unlocked
2270 } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
2271 mach_msg_header_t *reply = NULL;
2272 __CFRunLoopUnlock(rl);
2273 // mach_msg_scan(msg, 0);
2274 if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) {
2275 sourceHandledThisLoop = true;
2276 }
2277 // mach_msg_scan(msg, 1);
2278 if (NULL != reply) {
2279 ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
2280 //#warning CF: what should be done with the return value?
2281 CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
2282 }
2283 } else {
2284 CFRunLoopTimerRef rlt;
2285 rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort);
2286 __CFRunLoopUnlock(rl);
2287 if (NULL != rlt) {
2288 __CFRunLoopDoTimer(rl, rlm, rlt);
2289 }
2290 }
2291 if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
2292 #else
2293 else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
2294 __CFRunLoopUnlock(rl);
2295 if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("Source %@ was signalled"), rls); }
2296 if (__CFRunLoopDoSource1(rl, rlm, rls)) {
2297 sourceHandledThisLoop = true;
2298 }
2299 }
2300 #endif
2301
2302 #if DEPLOYMENT_TARGET_WINDOWS
2303 if (NULL != timersToCall) {
2304 int i;
2305 for (i = CFArrayGetCount(timersToCall)-1; i >= 0; i--)
2306 __CFRunLoopDoTimer(rl, rlm, (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timersToCall, i));
2307 CFRelease(timersToCall);
2308 }
2309 #endif
2310
2311 if (rl->_blocks_head) {
2312 __CFRunLoopModeUnlock(rlm); // locks must be taken in order
2313 __CFRunLoopLock(rl);
2314 __CFRunLoopDoBlocks(rl, rlm->_name);
2315 __CFRunLoopModeLock(rlm);
2316 __CFRunLoopUnlock(rl);
2317 }
2318 if (sourceHandledThisLoop && stopAfterHandle) {
2319 returnValue = kCFRunLoopRunHandledSource;
2320 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
2321 // internal wakeup signal on the first look at the portset, we'll go around the loop one
2322 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
2323 } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) {
2324 returnValue = kCFRunLoopRunTimedOut;
2325 } else if (__CFRunLoopIsStopped(rl)) {
2326 __CFRunLoopUnsetStopped(rl);
2327 returnValue = kCFRunLoopRunStopped;
2328 } else if (rlm->_stopped) {
2329 rlm->_stopped = false;
2330 returnValue = kCFRunLoopRunStopped;
2331 } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
2332 returnValue = kCFRunLoopRunFinished;
2333 }
2334 if (0 != returnValue) {
2335 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2336 if (MACH_PORT_NULL != timeoutPort) {
2337 mk_timer_destroy(timeoutPort);
2338 }
2339 #endif
2340 return returnValue;
2341 }
2342 firstPass = false;
2343 }
2344 }
2345
2346 SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
2347 CHECK_FOR_FORK();
2348 if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
2349 __CFRunLoopLock(rl);
2350 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
2351 if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
2352 Boolean did = false;
2353 if (currentMode) __CFRunLoopModeUnlock(currentMode);
2354 #if 0
2355 if (rl->_blocks_head) {
2356 __CFRunLoopDoBlocks(rl, modeName);
2357 }
2358 #endif
2359 __CFRunLoopUnlock(rl);
2360 return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
2361 }
2362 uint32_t *previousStopped = (uint32_t *)rl->_stopped;
2363 rl->_stopped = NULL;
2364 CFRunLoopModeRef previousMode = rl->_currentMode;
2365 rl->_currentMode = currentMode;
2366 #if DEPLOYMENT_TARGET_WINDOWS
2367 if (previousMode && currentMode != previousMode) {
2368 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2369 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl);
2370 else
2371 __CFRunLoopUpdateMsgWait(rl);
2372 }
2373 #endif
2374 __CFRunLoopUnlock(rl);
2375 int32_t result;
2376 @try {
2377 if (currentMode->_observerMask & kCFRunLoopEntry || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
2378 result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode, false);
2379 if (currentMode->_observerMask & kCFRunLoopExit || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
2380 } @finally {
2381 // this kvetches if an exception was raised during a run loop callout, because the mode is not locked
2382 if (0 != currentMode->_lock) {
2383 __CFRunLoopModeUnlock(currentMode);
2384 }
2385 __CFRunLoopLock(rl);
2386 if (rl->_stopped) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped);
2387 rl->_stopped = previousStopped;
2388 rl->_currentMode = previousMode;
2389 #if DEPLOYMENT_TARGET_WINDOWS
2390 if (previousMode && currentMode != previousMode) {
2391 if (__CFIsNonMachRunLoopMarryMsgQueueEnabled())
2392 __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl);
2393 else
2394 __CFRunLoopUpdateMsgWait(rl);
2395 }
2396 #endif
2397 __CFRunLoopUnlock(rl);
2398 }
2399 return result;
2400 }
2401
2402 void CFRunLoopRun(void) { /* DOES CALLOUT */
2403 int32_t result;
2404 do {
2405 result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
2406 CHECK_FOR_FORK();
2407 } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
2408 }
2409
2410 SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
2411 CHECK_FOR_FORK();
2412 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
2413 }
2414
2415 static void __CFRunLoopFindMinTimer(const void *value, void *ctx) {
2416 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
2417 if (__CFIsValid(rlt)) {
2418 CFRunLoopTimerRef *result = (CFRunLoopTimerRef *)ctx;
2419 if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) {
2420 *result = rlt;
2421 }
2422 }
2423 }
2424
2425 #if DEPLOYMENT_TARGET_WINDOWS
2426 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
2427 CFRunLoopTimerRef result = NULL;
2428 int64_t fireTime = 0;
2429 if (rlm) {
2430 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
2431 __CFRunLoopTimerFireTSRLock();
2432 CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result);
2433 if (result)
2434 fireTime = result->_fireTSR;
2435 __CFRunLoopTimerFireTSRUnlock();
2436 }
2437 if (NULL != rlm->_submodes) {
2438 CFIndex idx, cnt;
2439 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
2440 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
2441 CFRunLoopModeRef subrlm;
2442 subrlm = __CFRunLoopFindMode(rl, modeName, false);
2443 if (NULL != subrlm) {
2444 int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm);
2445 __CFRunLoopModeUnlock(subrlm);
2446 if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime))
2447 fireTime = newFireTime;
2448 }
2449 }
2450 }
2451 __CFRunLoopModeUnlock(rlm);
2452 }
2453 return fireTime;
2454 }
2455 #endif
2456
2457 // called with rlm locked, if not NULL
2458 static CFAbsoluteTime __CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
2459 CFRunLoopTimerRef result = NULL;
2460 CFAbsoluteTime fireDate = 0.0;
2461 int64_t now2 = (int64_t)mach_absolute_time();
2462 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
2463 if (rlm) {
2464 if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
2465 __CFRunLoopTimerFireTSRLock();
2466 CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result);
2467 if (result) {
2468 fireDate = (0 == result->_fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(result->_fireTSR - now2));
2469 }
2470 __CFRunLoopTimerFireTSRUnlock();
2471 }
2472 if (NULL != rlm->_submodes) {
2473 CFIndex idx, cnt;
2474 for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
2475 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
2476 CFRunLoopModeRef subrlm;
2477 subrlm = __CFRunLoopFindMode(rl, modeName, false);
2478 if (NULL != subrlm) {
2479 CFAbsoluteTime newFireDate = __CFRunLoopGetNextTimerFireDate(rl, subrlm);
2480 __CFRunLoopModeUnlock(subrlm);
2481 if (fireDate == 0 || (newFireDate != 0.0 && newFireDate < fireDate))
2482 fireDate = newFireDate;
2483 }
2484 }
2485 }
2486 __CFRunLoopModeUnlock(rlm);
2487 }
2488 return fireDate;
2489 }
2490
2491 CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
2492 CHECK_FOR_FORK();
2493 CFRunLoopModeRef rlm;
2494 __CFRunLoopLock(rl);
2495 rlm = __CFRunLoopFindMode(rl, modeName, false);
2496 __CFRunLoopUnlock(rl);
2497 return __CFRunLoopGetNextTimerFireDate(rl, rlm);
2498 }
2499
2500 Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
2501 CHECK_FOR_FORK();
2502 return __CFRunLoopIsSleeping(rl);
2503 }
2504
2505 void CFRunLoopWakeUp(CFRunLoopRef rl) {
2506 CHECK_FOR_FORK();
2507 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2508 kern_return_t ret;
2509 /* We unconditionally try to send the message, since we don't want
2510 * to lose a wakeup, but the send may fail if there is already a
2511 * wakeup pending, since the queue length is 1. */
2512 ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0);
2513 if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) {
2514 HALT;
2515 }
2516 #else
2517 SetEvent(rl->_wakeUpPort);
2518 __CFRunLoopLock(rl);
2519 if (rl->_threadID == GetCurrentThreadId()) {
2520 PostMessageW(NULL, __kCFRunLoopWakeUpMessage, NULL, NULL);
2521 } else {
2522 PostThreadMessageW(rl->_threadID, __kCFRunLoopWakeUpMessage, NULL, NULL);
2523 }
2524 __CFRunLoopUnlock(rl);
2525 #endif
2526 }
2527
2528 void CFRunLoopStop(CFRunLoopRef rl) {
2529 Boolean doWake = false;
2530 CHECK_FOR_FORK();
2531 __CFRunLoopLock(rl);
2532 if (rl->_currentMode) {
2533 __CFRunLoopSetStopped(rl);
2534 doWake = true;
2535 }
2536 __CFRunLoopUnlock(rl);
2537 if (doWake) {
2538 CFRunLoopWakeUp(rl);
2539 }
2540 }
2541
2542 CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
2543 CHECK_FOR_FORK();
2544 CFRunLoopModeRef rlm;
2545 __CFRunLoopLock(rl);
2546 rlm = __CFRunLoopFindMode(rl, modeName, true);
2547 __CFRunLoopUnlock(rl);
2548 if (NULL != rlm) {
2549 rlm->_stopped = true;
2550 __CFRunLoopModeUnlock(rlm);
2551 }
2552 CFRunLoopWakeUp(rl);
2553 }
2554
2555 CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
2556 CHECK_FOR_FORK();
2557 CFRunLoopModeRef rlm;
2558 if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) {
2559 return false;
2560 } else if (CFEqual(modeName, candidateContainedName)) {
2561 return true;
2562 }
2563 __CFRunLoopLock(rl);
2564 rlm = __CFRunLoopFindMode(rl, modeName, true);
2565 __CFRunLoopUnlock(rl);
2566 if (NULL != rlm) {
2567 CFArrayRef submodes;
2568 if (NULL == rlm->_submodes) {
2569 __CFRunLoopModeUnlock(rlm);
2570 return false;
2571 }
2572 if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) {
2573 __CFRunLoopModeUnlock(rlm);
2574 return true;
2575 }
2576 submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
2577 __CFRunLoopModeUnlock(rlm);
2578 if (NULL != submodes) {
2579 CFIndex idx, cnt;
2580 for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
2581 CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
2582 if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) {
2583 CFRelease(submodes);
2584 return true;
2585 }
2586 }
2587 CFRelease(submodes);
2588 }
2589 }
2590 return false;
2591 }
2592
2593 CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) {
2594 CHECK_FOR_FORK();
2595 CFRunLoopModeRef rlm;
2596 if (__CFRunLoopIsDeallocating(rl)) return;
2597 // should really do a recursive check here, to make sure that a cycle isn't
2598 // introduced; of course, if that happens, you aren't going to get very far.
2599 if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) {
2600 return;
2601 } else {
2602 __CFRunLoopLock(rl);
2603 rlm = __CFRunLoopFindMode(rl, toModeName, true);
2604 __CFRunLoopUnlock(rl);
2605 if (NULL != rlm) {
2606 if (NULL == rlm->_submodes) {
2607 rlm->_submodes = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
2608 }
2609 if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) {
2610 CFArrayAppendValue(rlm->_submodes, modeName);
2611 }
2612 __CFRunLoopModeUnlock(rlm);
2613 }
2614 }
2615 }
2616
2617 CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) {
2618 CHECK_FOR_FORK();
2619 CFRunLoopModeRef rlm;
2620 // should really do a recursive check here, to make sure that a cycle isn't
2621 // introduced; of course, if that happens, you aren't going to get very far.
2622 if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) {
2623 return;
2624 } else {
2625 __CFRunLoopLock(rl);
2626 rlm = __CFRunLoopFindMode(rl, fromModeName, true);
2627 __CFRunLoopUnlock(rl);
2628 if (NULL != rlm) {
2629 if (NULL != rlm->_submodes) {
2630 CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes);
2631 idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName);
2632 if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx);
2633 }
2634 __CFRunLoopModeUnlock(rlm);
2635 }
2636 }
2637 }
2638
2639 void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) {
2640 CHECK_FOR_FORK();
2641 if (CFStringGetTypeID() == CFGetTypeID(mode)) {
2642 mode = CFStringCreateCopy(kCFAllocatorSystemDefault, (CFStringRef)mode);
2643 __CFRunLoopLock(rl);
2644 // ensure mode exists
2645 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)mode, true);
2646 if (currentMode) __CFRunLoopModeUnlock(currentMode);
2647 __CFRunLoopUnlock(rl);
2648 } else if (CFArrayGetTypeID() == CFGetTypeID(mode)) {
2649 CFIndex cnt = CFArrayGetCount((CFArrayRef)mode);
2650 const void **values = (const void **)malloc(sizeof(const void *) * cnt);
2651 CFArrayGetValues((CFArrayRef)mode, CFRangeMake(0, cnt), values);
2652 mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
2653 __CFRunLoopLock(rl);
2654 // ensure modes exist
2655 for (CFIndex idx = 0; idx < cnt; idx++) {
2656 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
2657 if (currentMode) __CFRunLoopModeUnlock(currentMode);
2658 }
2659 __CFRunLoopUnlock(rl);
2660 free(values);
2661 } else if (CFSetGetTypeID() == CFGetTypeID(mode)) {
2662 CFIndex cnt = CFSetGetCount((CFSetRef)mode);
2663 const void **values = (const void **)malloc(sizeof(const void *) * cnt);
2664 CFSetGetValues((CFSetRef)mode, values);
2665 mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
2666 __CFRunLoopLock(rl);
2667 // ensure modes exist
2668 for (CFIndex idx = 0; idx < cnt; idx++) {
2669 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
2670 if (currentMode) __CFRunLoopModeUnlock(currentMode);
2671 }
2672 __CFRunLoopUnlock(rl);
2673 free(values);
2674 } else {
2675 mode = NULL;
2676 }
2677 #if DEPLOYMENT_TARGET_WINDOWS
2678 // <rdar://problem/6496715> Block.h uses "typeof", which is not available when using Visual Studio on Windows
2679 block = (void (^)(void))_Block_copy(block);
2680 #else
2681 block = Block_copy(block);
2682 #endif
2683 if (!mode || !block) {
2684 if (mode) CFRelease(mode);
2685 if (block) Block_release(block);
2686 return;
2687 }
2688 __CFRunLoopLock(rl);
2689 struct _block_item *new_item = (struct _block_item *)malloc(sizeof(struct _block_item));
2690 new_item->_next = NULL;
2691 new_item->_mode = mode;
2692 new_item->_block = block;
2693 if (!rl->_blocks_tail) {
2694 rl->_blocks_head = new_item;
2695 } else {
2696 rl->_blocks_tail->_next = new_item;
2697 }
2698 rl->_blocks_tail = new_item;
2699 __CFRunLoopUnlock(rl);
2700 }
2701
2702 Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
2703 CHECK_FOR_FORK();
2704 CFRunLoopModeRef rlm;
2705 Boolean hasValue = false;
2706 __CFRunLoopLock(rl);
2707 if (modeName == kCFRunLoopCommonModes) {
2708 if (NULL != rl->_commonModeItems) {
2709 hasValue = CFSetContainsValue(rl->_commonModeItems, rls);
2710 }
2711 __CFRunLoopUnlock(rl);
2712 } else {
2713 rlm = __CFRunLoopFindMode(rl, modeName, false);
2714 __CFRunLoopUnlock(rl);
2715 if (NULL != rlm && NULL != rlm->_sources) {
2716 hasValue = CFSetContainsValue(rlm->_sources, rls);
2717 __CFRunLoopModeUnlock(rlm);
2718 } else if (NULL != rlm) {
2719 __CFRunLoopModeUnlock(rlm);
2720 }
2721 }
2722 return hasValue;
2723 }
2724
2725 void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
2726 CHECK_FOR_FORK();
2727 CFRunLoopModeRef rlm;
2728 if (__CFRunLoopIsDeallocating(rl)) return;
2729 if (!__CFIsValid(rls)) return;
2730 __CFRunLoopLock(rl);
2731 if (modeName == kCFRunLoopCommonModes) {
2732 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2733 if (NULL == rl->_commonModeItems) {
2734 rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2735 _CFSetSetCapacity(rl->_commonModeItems, 20);
2736 }
2737 CFSetAddValue(rl->_commonModeItems, rls);
2738 __CFRunLoopUnlock(rl);
2739 if (NULL != set) {
2740 CFTypeRef context[2] = {rl, rls};
2741 /* add new item to all common-modes */
2742 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2743 CFRelease(set);
2744 }
2745 } else {
2746 rlm = __CFRunLoopFindMode(rl, modeName, true);
2747 __CFRunLoopUnlock(rl);
2748 if (NULL != rlm && NULL == rlm->_sources) {
2749 rlm->_sources = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2750 rlm->_portToV1SourceMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
2751 _CFSetSetCapacity(rlm->_sources, 10);
2752 }
2753 if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) {
2754 CFSetAddValue(rlm->_sources, rls);
2755 if (1 == rls->_context.version0.version) {
2756 __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
2757 CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls);
2758 }
2759 __CFRunLoopModeUnlock(rlm);
2760 __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */
2761 } else if (NULL != rlm) {
2762 __CFRunLoopModeUnlock(rlm);
2763 }
2764 }
2765 }
2766
2767 void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
2768 CHECK_FOR_FORK();
2769 CFRunLoopModeRef rlm;
2770 __CFRunLoopLock(rl);
2771 if (modeName == kCFRunLoopCommonModes) {
2772 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
2773 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2774 CFSetRemoveValue(rl->_commonModeItems, rls);
2775 __CFRunLoopUnlock(rl);
2776 if (NULL != set) {
2777 CFTypeRef context[2] = {rl, rls};
2778 /* remove new item from all common-modes */
2779 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2780 CFRelease(set);
2781 }
2782 } else {
2783 __CFRunLoopUnlock(rl);
2784 }
2785 } else {
2786 rlm = __CFRunLoopFindMode(rl, modeName, false);
2787 __CFRunLoopUnlock(rl);
2788 if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) {
2789 CFRetain(rls);
2790 if (1 == rls->_context.version0.version) {
2791 __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
2792 CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port);
2793 }
2794 CFSetRemoveValue(rlm->_sources, rls);
2795 __CFRunLoopModeUnlock(rlm);
2796 __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */
2797 CFRelease(rls);
2798 } else if (NULL != rlm) {
2799 __CFRunLoopModeUnlock(rlm);
2800 }
2801 }
2802 }
2803
2804 static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
2805 CFStringRef modeName = (CFStringRef)value;
2806 CFRunLoopRef rl = (CFRunLoopRef)ctx;
2807 __CFRunLoopRemoveAllSources(rl, modeName);
2808 }
2809
2810 static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) {
2811 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
2812 CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
2813 CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
2814 CFRunLoopRemoveSource(rl, rls, modeName);
2815 }
2816
2817 static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
2818 CHECK_FOR_FORK();
2819 CFRunLoopModeRef rlm;
2820 __CFRunLoopLock(rl);
2821 if (modeName == kCFRunLoopCommonModes) {
2822 if (NULL != rl->_commonModeItems) {
2823 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2824 __CFRunLoopUnlock(rl);
2825 if (NULL != set) {
2826 CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
2827 CFRelease(set);
2828 }
2829 } else {
2830 __CFRunLoopUnlock(rl);
2831 }
2832 } else {
2833 rlm = __CFRunLoopFindMode(rl, modeName, false);
2834 __CFRunLoopUnlock(rl);
2835 if (NULL != rlm && NULL != rlm->_sources) {
2836 CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources);
2837 __CFRunLoopModeUnlock(rlm);
2838 CFTypeRef context[2] = {rl, modeName};
2839 CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
2840 CFRelease(set);
2841 } else if (NULL != rlm) {
2842 __CFRunLoopModeUnlock(rlm);
2843 }
2844 }
2845 }
2846
2847 Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2848 CHECK_FOR_FORK();
2849 CFRunLoopModeRef rlm;
2850 Boolean hasValue = false;
2851 __CFRunLoopLock(rl);
2852 if (modeName == kCFRunLoopCommonModes) {
2853 if (NULL != rl->_commonModeItems) {
2854 hasValue = CFSetContainsValue(rl->_commonModeItems, rlo);
2855 }
2856 __CFRunLoopUnlock(rl);
2857 } else {
2858 rlm = __CFRunLoopFindMode(rl, modeName, false);
2859 __CFRunLoopUnlock(rl);
2860 if (NULL != rlm && NULL != rlm->_observers) {
2861 hasValue = CFSetContainsValue(rlm->_observers, rlo);
2862 __CFRunLoopModeUnlock(rlm);
2863 } else if (NULL != rlm) {
2864 __CFRunLoopModeUnlock(rlm);
2865 }
2866 }
2867 return hasValue;
2868 }
2869
2870 void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2871 CHECK_FOR_FORK();
2872 CFRunLoopModeRef rlm;
2873 if (__CFRunLoopIsDeallocating(rl)) return;
2874 if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
2875 __CFRunLoopLock(rl);
2876 if (modeName == kCFRunLoopCommonModes) {
2877 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2878 if (NULL == rl->_commonModeItems) {
2879 rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2880 }
2881 CFSetAddValue(rl->_commonModeItems, rlo);
2882 __CFRunLoopUnlock(rl);
2883 if (NULL != set) {
2884 CFTypeRef context[2] = {rl, rlo};
2885 /* add new item to all common-modes */
2886 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2887 CFRelease(set);
2888 }
2889 } else {
2890 rlm = __CFRunLoopFindMode(rl, modeName, true);
2891 __CFRunLoopUnlock(rl);
2892 if (NULL != rlm && NULL == rlm->_observers) {
2893 rlm->_observers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2894 }
2895 if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) {
2896 CFSetAddValue(rlm->_observers, rlo);
2897 rlm->_observerMask |= rlo->_activities;
2898 __CFRunLoopModeUnlock(rlm);
2899 __CFRunLoopObserverSchedule(rlo, rl, rlm);
2900 } else if (NULL != rlm) {
2901 __CFRunLoopModeUnlock(rlm);
2902 }
2903 }
2904 }
2905
2906 void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
2907 CHECK_FOR_FORK();
2908 CFRunLoopModeRef rlm;
2909 __CFRunLoopLock(rl);
2910 if (modeName == kCFRunLoopCommonModes) {
2911 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) {
2912 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2913 CFSetRemoveValue(rl->_commonModeItems, rlo);
2914 __CFRunLoopUnlock(rl);
2915 if (NULL != set) {
2916 CFTypeRef context[2] = {rl, rlo};
2917 /* remove new item from all common-modes */
2918 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
2919 CFRelease(set);
2920 }
2921 } else {
2922 __CFRunLoopUnlock(rl);
2923 }
2924 } else {
2925 rlm = __CFRunLoopFindMode(rl, modeName, false);
2926 __CFRunLoopUnlock(rl);
2927 if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) {
2928 CFRetain(rlo);
2929 CFSetRemoveValue(rlm->_observers, rlo);
2930 __CFRunLoopModeUnlock(rlm);
2931 __CFRunLoopObserverCancel(rlo, rl, rlm);
2932 CFRelease(rlo);
2933 } else if (NULL != rlm) {
2934 __CFRunLoopModeUnlock(rlm);
2935 }
2936 }
2937 }
2938
2939 Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2940 CHECK_FOR_FORK();
2941 CFRunLoopModeRef rlm;
2942 Boolean hasValue = false;
2943 __CFRunLoopLock(rl);
2944 if (modeName == kCFRunLoopCommonModes) {
2945 if (NULL != rl->_commonModeItems) {
2946 hasValue = CFSetContainsValue(rl->_commonModeItems, rlt);
2947 }
2948 __CFRunLoopUnlock(rl);
2949 } else {
2950 rlm = __CFRunLoopFindMode(rl, modeName, false);
2951 __CFRunLoopUnlock(rl);
2952 if (NULL != rlm && NULL != rlm->_timers) {
2953 hasValue = CFSetContainsValue(rlm->_timers, rlt);
2954 __CFRunLoopModeUnlock(rlm);
2955 } else if (NULL != rlm) {
2956 __CFRunLoopModeUnlock(rlm);
2957 }
2958 }
2959 return hasValue;
2960 }
2961
2962 void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2963 CHECK_FOR_FORK();
2964 //CFLog(4, CFSTR("CFRunLoopAddTimer(%p, timer %p, %@)"), rl, rlt, modeName);
2965 CFRunLoopModeRef rlm;
2966 if (__CFRunLoopIsDeallocating(rl)) return;
2967 if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
2968 __CFRunLoopLock(rl);
2969 if (modeName == kCFRunLoopCommonModes) {
2970 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
2971 if (NULL == rl->_commonModeItems) {
2972 rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2973 }
2974 CFSetAddValue(rl->_commonModeItems, rlt);
2975 __CFRunLoopUnlock(rl);
2976 if (NULL != set) {
2977 CFTypeRef context[2] = {rl, rlt};
2978 /* add new item to all common-modes */
2979 CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
2980 CFRelease(set);
2981 }
2982 } else {
2983 rlm = __CFRunLoopFindMode(rl, modeName, true);
2984 __CFRunLoopUnlock(rl);
2985 if (NULL != rlm && NULL == rlm->_timers) {
2986 rlm->_timers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
2987 }
2988 if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) {
2989 CFSetAddValue(rlm->_timers, rlt);
2990 __CFRunLoopModeUnlock(rlm);
2991 __CFRunLoopTimerSchedule(rlt, rl, rlm);
2992 } else if (NULL != rlm) {
2993 __CFRunLoopModeUnlock(rlm);
2994 }
2995 }
2996 }
2997
2998 void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
2999 CHECK_FOR_FORK();
3000 //CFLog(4, CFSTR("CFRunLoopRemoveTimer(%p, timer %p, %@)"), rl, rlt, modeName);
3001 CFRunLoopModeRef rlm;
3002 __CFRunLoopLock(rl);
3003 if (modeName == kCFRunLoopCommonModes) {
3004 if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) {
3005 CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
3006 CFSetRemoveValue(rl->_commonModeItems, rlt);
3007 __CFRunLoopUnlock(rl);
3008 if (NULL != set) {
3009 CFTypeRef context[2] = {rl, rlt};
3010 /* remove new item from all common-modes */
3011 CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
3012 CFRelease(set);
3013 }
3014 } else {
3015 __CFRunLoopUnlock(rl);
3016 }
3017 } else {
3018 rlm = __CFRunLoopFindMode(rl, modeName, false);
3019 __CFRunLoopUnlock(rl);
3020 if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) {
3021 CFRetain(rlt);
3022 CFSetRemoveValue(rlm->_timers, rlt);
3023 __CFRunLoopModeUnlock(rlm);
3024 __CFRunLoopTimerCancel(rlt, rl, rlm);
3025 CFRelease(rlt);
3026 } else if (NULL != rlm) {
3027 __CFRunLoopModeUnlock(rlm);
3028 }
3029 }
3030 }
3031
3032
3033 /* CFRunLoopSource */
3034
3035 static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */
3036 CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1;
3037 CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2;
3038 if (rls1 == rls2) return true;
3039 if (__CFIsValid(rls1) != __CFIsValid(rls2)) return false;
3040 if (rls1->_order != rls2->_order) return false;
3041 if (rls1->_context.version0.version != rls2->_context.version0.version) return false;
3042 if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false;
3043 if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false;
3044 if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false;
3045 if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false;
3046 if (rls1->_context.version0.equal)
3047 return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info);
3048 return (rls1->_context.version0.info == rls2->_context.version0.info);
3049 }
3050
3051 static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) { /* DOES CALLOUT */
3052 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
3053 if (rls->_context.version0.hash)
3054 return rls->_context.version0.hash(rls->_context.version0.info);
3055 return (CFHashCode)rls->_context.version0.info;
3056 }
3057
3058 static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
3059 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
3060 CFStringRef result;
3061 CFStringRef contextDesc = NULL;
3062 if (NULL != rls->_context.version0.copyDescription) {
3063 contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info);
3064 }
3065 if (NULL == contextDesc) {
3066 void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL);
3067 #if DEPLOYMENT_TARGET_WINDOWS
3068 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls->_context.version0.version, rls->_context.version0.info, addr);
3069 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3070 Dl_info info;
3071 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
3072 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr);
3073 #else
3074 #error Unknown or unspecified DEPLOYMENT_TARGET
3075 #endif
3076 }
3077 #if DEPLOYMENT_TARGET_WINDOWS
3078 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), "unknown", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc);
3079 #else
3080 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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);
3081 #endif
3082 CFRelease(contextDesc);
3083 return result;
3084 }
3085
3086 static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
3087 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
3088 CFRunLoopSourceInvalidate(rls);
3089 if (rls->_context.version0.release) {
3090 rls->_context.version0.release(rls->_context.version0.info);
3091 }
3092 memset((char *)cf + sizeof(CFRuntimeBase), 0, sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase));
3093 }
3094
3095 static const CFRuntimeClass __CFRunLoopSourceClass = {
3096 _kCFRuntimeScannedObject,
3097 "CFRunLoopSource",
3098 NULL, // init
3099 NULL, // copy
3100 __CFRunLoopSourceDeallocate,
3101 __CFRunLoopSourceEqual,
3102 __CFRunLoopSourceHash,
3103 NULL, //
3104 __CFRunLoopSourceCopyDescription
3105 };
3106
3107 __private_extern__ void __CFRunLoopSourceInitialize(void) {
3108 __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass);
3109 }
3110
3111 CFTypeID CFRunLoopSourceGetTypeID(void) {
3112 return __kCFRunLoopSourceTypeID;
3113 }
3114
3115 CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
3116 CHECK_FOR_FORK();
3117 CFRunLoopSourceRef memory;
3118 uint32_t size;
3119 if (NULL == context) HALT;
3120 size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
3121 memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL);
3122 if (NULL == memory) {
3123 return NULL;
3124 }
3125 __CFSetValid(memory);
3126 __CFRunLoopSourceUnsetSignaled(memory);
3127 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
3128 memory->_bits = 0;
3129 memory->_order = order;
3130 memory->_runLoops = NULL;
3131 size = 0;
3132 switch (context->version) {
3133 case 0:
3134 size = sizeof(CFRunLoopSourceContext);
3135 break;
3136 case 1:
3137 size = sizeof(CFRunLoopSourceContext1);
3138 break;
3139 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3140 case 2:
3141 size = sizeof(CFRunLoopSourceContext2);
3142 break;
3143 #endif
3144 }
3145 objc_memmove_collectable(&memory->_context, context, size);
3146 if (context->retain) {
3147 memory->_context.version0.info = (void *)context->retain(context->info);
3148 }
3149 return memory;
3150 }
3151
3152 CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
3153 CHECK_FOR_FORK();
3154 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3155 return rls->_order;
3156 }
3157
3158 static void __CFRunLoopSourceWakeUpLoop(const void *value, void *context) {
3159 CFRunLoopWakeUp((CFRunLoopRef)value);
3160 }
3161
3162 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
3163 CFRunLoopRef rl = (CFRunLoopRef)value;
3164 CFTypeRef *params = (CFTypeRef *)context;
3165 CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
3166 CFArrayRef array;
3167 CFIndex idx;
3168 if (rl == params[1]) return;
3169 array = CFRunLoopCopyAllModes(rl);
3170 for (idx = CFArrayGetCount(array); idx--;) {
3171 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
3172 CFRunLoopRemoveSource(rl, rls, modeName);
3173 }
3174 CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
3175 CFRelease(array);
3176 params[1] = rl;
3177 }
3178
3179 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
3180 CHECK_FOR_FORK();
3181 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3182 CFRetain(rls);
3183 __CFRunLoopSourceLock(rls);
3184 if (__CFIsValid(rls)) {
3185 __CFUnsetValid(rls);
3186 __CFRunLoopSourceUnsetSignaled(rls);
3187 if (NULL != rls->_runLoops) {
3188 CFTypeRef params[2] = {rls, NULL};
3189 CFBagRef bag = rls->_runLoops;
3190 rls->_runLoops = NULL;
3191 __CFRunLoopSourceUnlock(rls);
3192 CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params);
3193 CFRelease(bag);
3194 } else {
3195 __CFRunLoopSourceUnlock(rls);
3196 }
3197 /* for hashing- and equality-use purposes, can't actually release the context here */
3198 } else {
3199 __CFRunLoopSourceUnlock(rls);
3200 }
3201 CFRelease(rls);
3202 }
3203
3204 Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
3205 CHECK_FOR_FORK();
3206 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3207 return __CFIsValid(rls);
3208 }
3209
3210 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
3211 CHECK_FOR_FORK();
3212 __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
3213 CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__);
3214 CFIndex size = 0;
3215 switch (context->version) {
3216 case 0:
3217 size = sizeof(CFRunLoopSourceContext);
3218 break;
3219 case 1:
3220 size = sizeof(CFRunLoopSourceContext1);
3221 break;
3222 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3223 case 2:
3224 size = sizeof(CFRunLoopSourceContext2);
3225 break;
3226 #endif
3227 }
3228 memmove(context, &rls->_context, size);
3229 }
3230
3231 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
3232 CHECK_FOR_FORK();
3233 __CFRunLoopSourceLock(rls);
3234 if (__CFIsValid(rls)) {
3235 __CFRunLoopSourceSetSignaled(rls);
3236 }
3237 __CFRunLoopSourceUnlock(rls);
3238 }
3239
3240 Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) {
3241 CHECK_FOR_FORK();
3242 __CFRunLoopSourceLock(rls);
3243 Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false;
3244 __CFRunLoopSourceUnlock(rls);
3245 return ret;
3246 }
3247
3248 __private_extern__ void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) {
3249 __CFRunLoopSourceLock(rls);
3250 if (__CFIsValid(rls) && NULL != rls->_runLoops) {
3251 CFBagApplyFunction(rls->_runLoops, __CFRunLoopSourceWakeUpLoop, NULL);
3252 }
3253 __CFRunLoopSourceUnlock(rls);
3254 }
3255
3256 /* CFRunLoopObserver */
3257
3258 static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
3259 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
3260 CFStringRef result;
3261 CFStringRef contextDesc = NULL;
3262 if (NULL != rlo->_context.copyDescription) {
3263 contextDesc = rlo->_context.copyDescription(rlo->_context.info);
3264 }
3265 if (!contextDesc) {
3266 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
3267 }
3268 #if DEPLOYMENT_TARGET_WINDOWS
3269 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), "unknown", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc);
3270 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3271 void *addr = rlo->_callout;
3272 Dl_info info;
3273 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
3274 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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);
3275 #else
3276 #error Unknown or unspecified DEPLOYMENT_TARGET
3277 #endif
3278 CFRelease(contextDesc);
3279 return result;
3280 }
3281
3282 static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
3283 CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
3284 CFRunLoopObserverInvalidate(rlo);
3285 }
3286
3287 static const CFRuntimeClass __CFRunLoopObserverClass = {
3288 0,
3289 "CFRunLoopObserver",
3290 NULL, // init
3291 NULL, // copy
3292 __CFRunLoopObserverDeallocate,
3293 NULL,
3294 NULL,
3295 NULL, //
3296 __CFRunLoopObserverCopyDescription
3297 };
3298
3299 __private_extern__ void __CFRunLoopObserverInitialize(void) {
3300 __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass);
3301 }
3302
3303 CFTypeID CFRunLoopObserverGetTypeID(void) {
3304 return __kCFRunLoopObserverTypeID;
3305 }
3306
3307 CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
3308 CHECK_FOR_FORK();
3309 CFRunLoopObserverRef memory;
3310 UInt32 size;
3311 size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
3312 memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL);
3313 if (NULL == memory) {
3314 return NULL;
3315 }
3316 __CFSetValid(memory);
3317 __CFRunLoopObserverUnsetFiring(memory);
3318 if (repeats) {
3319 __CFRunLoopObserverSetRepeats(memory);
3320 } else {
3321 __CFRunLoopObserverUnsetRepeats(memory);
3322 }
3323 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
3324 memory->_runLoop = NULL;
3325 memory->_rlCount = 0;
3326 memory->_activities = activities;
3327 memory->_order = order;
3328 memory->_callout = callout;
3329 if (context) {
3330 if (context->retain) {
3331 memory->_context.info = (void *)context->retain(context->info);
3332 } else {
3333 memory->_context.info = context->info;
3334 }
3335 memory->_context.retain = context->retain;
3336 memory->_context.release = context->release;
3337 memory->_context.copyDescription = context->copyDescription;
3338 } else {
3339 memory->_context.info = 0;
3340 memory->_context.retain = 0;
3341 memory->_context.release = 0;
3342 memory->_context.copyDescription = 0;
3343 }
3344 return memory;
3345 }
3346
3347 CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
3348 CHECK_FOR_FORK();
3349 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3350 return rlo->_activities;
3351 }
3352
3353 CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
3354 CHECK_FOR_FORK();
3355 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3356 return rlo->_order;
3357 }
3358
3359 Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
3360 CHECK_FOR_FORK();
3361 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3362 return __CFRunLoopObserverRepeats(rlo);
3363 }
3364
3365 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */
3366 CHECK_FOR_FORK();
3367 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3368 CFRetain(rlo);
3369 __CFRunLoopObserverLock(rlo);
3370 if (__CFIsValid(rlo)) {
3371 CFRunLoopRef rl = rlo->_runLoop;
3372 __CFUnsetValid(rlo);
3373 __CFRunLoopObserverUnlock(rlo);
3374 if (NULL != rl) {
3375 CFArrayRef array;
3376 CFIndex idx;
3377 array = CFRunLoopCopyAllModes(rl);
3378 for (idx = CFArrayGetCount(array); idx--;) {
3379 CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
3380 CFRunLoopRemoveObserver(rl, rlo, modeName);
3381 }
3382 CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
3383 CFRelease(array);
3384 }
3385 if (rlo->_context.release)
3386 rlo->_context.release(rlo->_context.info); /* CALLOUT */
3387 rlo->_context.info = NULL;
3388 } else {
3389 __CFRunLoopObserverUnlock(rlo);
3390 }
3391 CFRelease(rlo);
3392 }
3393
3394 Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
3395 CHECK_FOR_FORK();
3396 return __CFIsValid(rlo);
3397 }
3398
3399 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
3400 CHECK_FOR_FORK();
3401 __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
3402 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
3403 *context = rlo->_context;
3404 }
3405
3406 /* CFRunLoopTimer */
3407
3408 static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */
3409 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
3410 CFStringRef result;
3411 int64_t now2 = (int64_t)mach_absolute_time();
3412 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
3413 __CFRunLoopTimerFireTSRLock();
3414 int64_t fireTime = rlt->_fireTSR;
3415 __CFRunLoopTimerFireTSRUnlock();
3416 CFAbsoluteTime fireDate = now1 + __CFTSRToTimeInterval(fireTime - now2);
3417 CFStringRef contextDesc = NULL;
3418 if (NULL != rlt->_context.copyDescription) {
3419 contextDesc = rlt->_context.copyDescription(rlt->_context.info);
3420 }
3421 if (NULL == contextDesc) {
3422 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
3423 }
3424 #if DEPLOYMENT_TARGET_WINDOWS
3425 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), "unknown", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, rlt->_callout, contextDesc);
3426 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3427 void *addr = rlt->_callout;
3428 Dl_info info;
3429 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
3430 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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", rlt->_interval, fireDate, rlt->_order, name, addr, contextDesc);
3431 #else
3432 #error Unknown or unspecified DEPLOYMENT_TARGET
3433 #endif
3434 CFRelease(contextDesc);
3435 return result;
3436 }
3437
3438 static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */
3439 //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf);
3440 CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
3441 __CFRunLoopTimerSetDeallocating(rlt);
3442 CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
3443 CFRelease(rlt->_rlModes);
3444 rlt->_rlModes = NULL;
3445 }
3446
3447 static const CFRuntimeClass __CFRunLoopTimerClass = {
3448 0,
3449 "CFRunLoopTimer",
3450 NULL, // init
3451 NULL, // copy
3452 __CFRunLoopTimerDeallocate,
3453 NULL, // equal
3454 NULL,
3455 NULL, //
3456 __CFRunLoopTimerCopyDescription
3457 };
3458
3459 __private_extern__ void __CFRunLoopTimerInitialize(void) {
3460 __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass);
3461 }
3462
3463 CFTypeID CFRunLoopTimerGetTypeID(void) {
3464 return __kCFRunLoopTimerTypeID;
3465 }
3466
3467 CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
3468 CHECK_FOR_FORK();
3469 CFRunLoopTimerRef memory;
3470 UInt32 size;
3471 size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
3472 memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL);
3473 if (NULL == memory) {
3474 return NULL;
3475 }
3476 __CFSetValid(memory);
3477 __CFRunLoopTimerUnsetFiring(memory);
3478 __CFRunLoopTimerUnsetDidFire(memory);
3479 CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock);
3480 memory->_runLoop = NULL;
3481 memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
3482 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3483 memory->_port = MACH_PORT_NULL;
3484 #endif
3485 memory->_order = order;
3486 if (interval < 0.0) interval = 0.0;
3487 memory->_interval = interval;
3488 if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
3489 if (TIMER_INTERVAL_LIMIT < interval) interval = TIMER_INTERVAL_LIMIT;
3490 memory->_nextFireDate = fireDate;
3491 int64_t now2 = (int64_t)mach_absolute_time();
3492 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
3493 if (fireDate < now1) {
3494 memory->_fireTSR = now2;
3495 } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
3496 memory->_fireTSR = LLONG_MAX;
3497 } else {
3498 memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
3499 }
3500 if (interval <= 0.0) {
3501 memory->_intervalTSR = 0;
3502 } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) {
3503 memory->_intervalTSR = LLONG_MAX;
3504 } else {
3505 memory->_intervalTSR = __CFTimeIntervalToTSR(interval);
3506 }
3507 memory->_callout = callout;
3508 if (NULL != context) {
3509 if (context->retain) {
3510 memory->_context.info = (void *)context->retain(context->info);
3511 } else {
3512 memory->_context.info = context->info;
3513 }
3514 memory->_context.retain = context->retain;
3515 memory->_context.release = context->release;
3516 memory->_context.copyDescription = context->copyDescription;
3517 } else {
3518 memory->_context.info = 0;
3519 memory->_context.retain = 0;
3520 memory->_context.release = 0;
3521 memory->_context.copyDescription = 0;
3522 }
3523 //CFLog(4, CFSTR("CFRunLoopTimerCreate(%p, %f, %f, 0x%lx, %ld, %p, %p) => %p"), allocator, fireDate, interval, flags, order, callout, context, memory);
3524 return memory;
3525 }
3526
3527 CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
3528 CHECK_FOR_FORK();
3529 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime");
3530 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3531 int64_t fireTime, result = 0;
3532 __CFRunLoopTimerFireTSRLock();
3533 fireTime = rlt->_fireTSR;
3534 __CFRunLoopTimerFireTSRUnlock();
3535 __CFRunLoopTimerLock(rlt);
3536 if (__CFIsValid(rlt)) {
3537 result = fireTime;
3538 }
3539 __CFRunLoopTimerUnlock(rlt);
3540 int64_t now2 = (int64_t)mach_absolute_time();
3541 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
3542 return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2);
3543 }
3544
3545 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
3546 //CFLog(6, CFSTR("CFRunLoopTimerSetNextFireDate(rlt %p, fireDate %f)"), rlt, fireDate);
3547 CHECK_FOR_FORK();
3548 //CFLog(4, CFSTR("CFRunLoopTimerSetNextFireDate(%p, %f) [limit: %f]"), rlt, fireDate, TIMER_DATE_LIMIT);
3549 if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
3550 rlt->_nextFireDate = fireDate;
3551 int64_t now2 = (int64_t)mach_absolute_time();
3552 CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
3553 __CFRunLoopTimerFireTSRLock();
3554 if (fireDate < now1) {
3555 rlt->_fireTSR = now2;
3556 } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
3557 rlt->_fireTSR = LLONG_MAX;
3558 } else {
3559 rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
3560 }
3561 if (rlt->_runLoop != NULL) {
3562 __CFRunLoopTimerRescheduleWithAllModes(rlt);
3563 }
3564 __CFRunLoopTimerFireTSRUnlock();
3565 }
3566
3567 CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
3568 CHECK_FOR_FORK();
3569 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval");
3570 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3571 return rlt->_interval;
3572 }
3573
3574 Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
3575 CHECK_FOR_FORK();
3576 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3577 return (0.0 < rlt->_interval);
3578 }
3579
3580 CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
3581 CHECK_FOR_FORK();
3582 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order");
3583 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3584 return rlt->_order;
3585 }
3586
3587 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
3588 CHECK_FOR_FORK();
3589 //CFLog(4, CFSTR("CFRunLoopTimerInvalidate(%p)"), rlt);
3590 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate");
3591 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3592 if (!__CFRunLoopTimerIsDeallocating(rlt)) {
3593 CFRetain(rlt);
3594 }
3595 __CFRunLoopTimerLock(rlt);
3596 if (__CFIsValid(rlt)) {
3597 CFRunLoopRef rl = rlt->_runLoop;
3598 void *info = rlt->_context.info;
3599 __CFUnsetValid(rlt);
3600 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3601 __CFRunLoopTimerPortMapLock();
3602 if (NULL != __CFRLTPortMap) {
3603 CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port);
3604 }
3605 __CFRunLoopTimerPortMapUnlock();
3606 mk_timer_destroy(rlt->_port);
3607 rlt->_port = MACH_PORT_NULL;
3608 #endif
3609 rlt->_context.info = NULL;
3610 __CFRunLoopTimerUnlock(rlt);
3611 if (NULL != rl) {
3612 CFIndex cnt = CFSetGetCount(rlt->_rlModes);
3613 STACK_BUFFER_DECL(CFStringRef, modes, cnt);
3614 CFSetGetValues(rlt->_rlModes, (const void **)modes);
3615 for (CFIndex idx = 0; idx < cnt; idx++) {
3616 CFRunLoopRemoveTimer(rl, rlt, modes[idx]);
3617 }
3618 CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
3619 }
3620 if (NULL != rlt->_context.release) {
3621 rlt->_context.release(info); /* CALLOUT */
3622 }
3623 } else {
3624 __CFRunLoopTimerUnlock(rlt);
3625 }
3626 if (!__CFRunLoopTimerIsDeallocating(rlt)) {
3627 CFRelease(rlt);
3628 }
3629 }
3630
3631 Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
3632 CHECK_FOR_FORK();
3633 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid");
3634 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3635 return __CFIsValid(rlt);
3636 }
3637
3638 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
3639 CHECK_FOR_FORK();
3640 __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
3641 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
3642 *context = rlt->_context;
3643 }
3644
3645
3646 #if DEPLOYMENT_TARGET_WINDOWS
3647
3648 //#if MARRY_MESSAGE_QUEUE
3649
3650 // Do we need to make sure it's not CFRunLoopRun processing the message queue?
3651 CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam) {
3652 //if nCode < 0, we're supposed to blindly call CallNexthookEx instead of processing the message ourselves
3653 if (nCode >= 0) {
3654 MSG *msgPtr = (MSG *)lParam;
3655 CFRunLoopRef rl = CFRunLoopGetCurrent();
3656 CFStringRef currMode;
3657
3658 if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage) {
3659 CFRunLoopModeRef rlm;
3660 CFRunLoopSourceRef rls;
3661 __CFRunLoopLock(rl);
3662 rlm = rl->_currentMode;
3663 if (!rlm) {
3664 rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // returns the mode locked
3665 } else {
3666 __CFRunLoopModeLock(rlm);
3667 }
3668 rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, (__CFPort)msgPtr->lParam);
3669 __CFRunLoopUnlock(rl);
3670 if (rls) {
3671 // Must still hold the mode lock when calling DoSource1
3672 __CFRunLoopDoSource1(rl, rlm, rls);
3673 }
3674 __CFRunLoopModeUnlock(rlm);
3675 }
3676 if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage || msgPtr->message == __kCFRunLoopWakeUpMessage) {
3677 // Must always pump the RL regardless of whether we received the wakeup message because whomever processed the v1 source may be assuming that the RL is running and will see further callouts.
3678 currMode = CFRunLoopCopyCurrentMode(rl);
3679 if (!currMode) {
3680 currMode = kCFRunLoopDefaultMode;
3681 CFRetain(currMode);
3682 }
3683 while (CFRunLoopRunInMode(currMode, 0.0, true) == kCFRunLoopRunHandledSource) {
3684 ;
3685 }
3686 CFRelease(currMode);
3687 }
3688 }
3689 return CallNextHookEx(__CFGetThreadSpecificData_inline()->_messageHook, nCode, wParam, lParam);
3690 }
3691
3692 void __CFRunLoopMsgWaitThread(void *theRL) {
3693 CFRunLoopRef rl = (CFRunLoopRef)theRL;
3694 Boolean allDone = FALSE;
3695
3696 while (!allDone) {
3697
3698 CFRunLoopModeRef rlm;
3699 __CFPortSet waitSet;
3700 DWORD waitResult = WAIT_TIMEOUT;
3701 DWORD qMask;
3702 HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS];
3703 HANDLE *handles, *currHandle;
3704 uint32_t handleCount, handleIndex;
3705 Boolean freeHandles;
3706
3707 __CFRunLoopLock(rl);
3708 rlm = rl->_currentMode;
3709 if (!rlm) {
3710 rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // Returns a locked mode
3711 } else {
3712 __CFRunLoopModeLock(rlm);
3713 }
3714 CFRetain(rlm);
3715 waitSet = rlm->_portSet;
3716
3717 // copy out the handles to be safe from other threads at work
3718 handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount);
3719 freeHandles = (handles != handleBuf);
3720 // Replace the wakeup port with our own update port
3721 for (handleIndex = 0, currHandle = handles; handleIndex < handleCount; handleIndex ++, currHandle++) {
3722 if (*currHandle == rl->_wakeUpPort) {
3723 *currHandle = rl->_msgUpdatePort;
3724 break;
3725 }
3726 }
3727
3728 // Not sure what to do with this....
3729 // handles[handleCount] = rl->_msgShutdownPort;
3730 // handleCount ++;
3731
3732 qMask = rlm->_msgQMask;
3733
3734 while (1) {
3735 Boolean shuttingDown = false;
3736 __CFRunLoopModeUnlock(rlm);
3737 __CFRunLoopUnlock(rl);
3738
3739 // What do we do if there are more than MAXIMUM_WAIT_OBJECTS
3740 //waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE, qMask);
3741 waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE);
3742 // Need to poll here to see if we've been told to die; if so, we must not touch rl. I think.
3743 __CFRunLoopLock(rl);
3744 __CFRunLoopModeLock(rlm);
3745 ResetEvent(rl->_msgUpdatePort);
3746
3747 __CFPort livePort = CFPORT_NULL;
3748 if (waitResult == WAIT_FAILED) {
3749 DWORD error = GetLastError();
3750 if (error == ERROR_INVALID_HANDLE) {
3751 // A handle got freed out from underneath us. Force an update of our handle watch list.
3752 livePort = rl->_msgUpdatePort;
3753 } else {
3754 CFAssert2(true, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects\n", __PRETTY_FUNCTION__,error);
3755 }
3756 }
3757 if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) {
3758 // a handle was signaled
3759 livePort = handles[waitResult-WAIT_OBJECT_0];
3760 } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) {
3761 // an "abandoned mutex object"
3762 livePort = handles[waitResult-WAIT_ABANDONED_0];
3763 }
3764 if (freeHandles){
3765 CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
3766 }
3767
3768 if (livePort == rl->_msgUpdatePort) {
3769 break;
3770 // } else if (livePort == rl->_msgShutdownPort) {
3771 // allDone = true;
3772 // break;
3773 } else {
3774 // OutputDebugStr(L"Posting v1 source ready msg\n");
3775 ResetEvent(livePort);
3776 PostThreadMessageW(rl->_threadID, __kCFRunLoopV1SourceReadyMessage, NULL, (LPARAM)livePort);
3777 }
3778 }
3779 __CFRunLoopModeUnlock(rlm);
3780 CFRelease(rlm);
3781 __CFRunLoopUnlock(rl);
3782 }
3783 }
3784
3785 // #endif
3786
3787 // Called while holding the run loop lock
3788
3789 //#if MARRY_MESSAGE_QUEUE
3790
3791 void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl) {
3792 if (rl->_msgUpdatePort == CFPORT_NULL) {
3793 rl->_msgUpdatePort = __CFPortAllocate();
3794 if (CFPORT_NULL == rl->_msgUpdatePort) HALT;
3795
3796 // Kick off the MsgWaitThread
3797 _beginthread(__CFRunLoopMsgWaitThread, 0, rl);
3798 }
3799 SetEvent(rl->_msgUpdatePort);
3800 }
3801 //#else
3802 CF_INLINE void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl) {}
3803 //#endif
3804
3805 #endif