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