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