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