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