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