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