#include <CoreFoundation/CFRunLoop.h>
#include <CoreFoundation/CFSet.h>
#include <CoreFoundation/CFBag.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFPreferences.h>
#include "CFInternal.h"
#include <math.h>
#include <stdio.h>
#include <limits.h>
#include <pthread.h>
#include <dispatch/dispatch.h>
#if DEPLOYMENT_TARGET_WINDOWS
#include <typeinfo.h>
#endif
#include <checkint.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#include <sys/param.h>
#include <dispatch/private.h>
#include <CoreFoundation/CFUserNotification.h>
#include <mach/mach.h>
#include <mach/clock_types.h>
#include <mach/clock.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pthread/private.h>
#include <os/voucher_private.h>
extern mach_port_t _dispatch_get_main_queue_port_4CF(void);
extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg);
#elif DEPLOYMENT_TARGET_WINDOWS
#include <process.h>
DISPATCH_EXPORT HANDLE _dispatch_get_main_queue_handle_4CF(void);
DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void);
#define MACH_PORT_NULL 0
#define mach_port_name_t HANDLE
#define mach_port_t HANDLE
#define _dispatch_get_main_queue_port_4CF _dispatch_get_main_queue_handle_4CF
#define _dispatch_main_queue_callback_4CF(x) _dispatch_main_queue_callback_4CF()
#define AbsoluteTime LARGE_INTEGER
#endif
#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
#define pthread_main_thread_np() _CF_pthread_main_thread_np()
#endif
#include <Block.h>
#include <Block_private.h>
#if DEPLOYMENT_TARGET_MACOSX
#define USE_DISPATCH_SOURCE_FOR_TIMERS 1
#define USE_MK_TIMER_TOO 1
#else
#define USE_DISPATCH_SOURCE_FOR_TIMERS 0
#define USE_MK_TIMER_TOO 1
#endif
static int _LogCFRunLoop = 0;
static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer, void *opaqueBlock);
#define TIMER_DATE_LIMIT 4039289856.0
#define TIMER_INTERVAL_LIMIT 504911232.0
#define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0
#define CRASH(string, errcode) do { char msg[256]; snprintf(msg, 256, string, errcode); CRSetCrashLogMessage(msg); HALT; } while (0)
#if DEPLOYMENT_TARGET_WINDOWS
static pthread_t kNilPthreadT = { nil, nil };
#define pthreadPointer(a) a.p
typedef int kern_return_t;
#define KERN_SUCCESS 0
#else
static pthread_t kNilPthreadT = (pthread_t)0;
#define pthreadPointer(a) a
#define lockCount(a) a
#endif
#pragma mark -
#define CF_RUN_LOOP_PROBES 0
#if CF_RUN_LOOP_PROBES
#include "CFRunLoopProbes.h"
#else
#define CFRUNLOOP_NEXT_TIMER_ARMED(arg0) do { } while (0)
#define CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED() (0)
#define CFRUNLOOP_POLL() do { } while (0)
#define CFRUNLOOP_POLL_ENABLED() (0)
#define CFRUNLOOP_SLEEP() do { } while (0)
#define CFRUNLOOP_SLEEP_ENABLED() (0)
#define CFRUNLOOP_SOURCE_FIRED(arg0, arg1, arg2) do { } while (0)
#define CFRUNLOOP_SOURCE_FIRED_ENABLED() (0)
#define CFRUNLOOP_TIMER_CREATED(arg0, arg1, arg2, arg3, arg4, arg5, arg6) do { } while (0)
#define CFRUNLOOP_TIMER_CREATED_ENABLED() (0)
#define CFRUNLOOP_TIMER_FIRED(arg0, arg1, arg2, arg3, arg4) do { } while (0)
#define CFRUNLOOP_TIMER_FIRED_ENABLED() (0)
#define CFRUNLOOP_TIMER_RESCHEDULED(arg0, arg1, arg2, arg3, arg4, arg5) do { } while (0)
#define CFRUNLOOP_TIMER_RESCHEDULED_ENABLED() (0)
#define CFRUNLOOP_WAKEUP(arg0) do { } while (0)
#define CFRUNLOOP_WAKEUP_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_DISPATCH() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_DISPATCH_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_NOTHING() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_NOTHING_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_SOURCE() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_SOURCE_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_TIMEOUT() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_TIMEOUT_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_TIMER() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_TIMER_ENABLED() (0)
#define CFRUNLOOP_WAKEUP_FOR_WAKEUP() do { } while (0)
#define CFRUNLOOP_WAKEUP_FOR_WAKEUP_ENABLED() (0)
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
CF_PRIVATE uint32_t __CFGetProcessPortCount(void) {
ipc_info_space_t info;
ipc_info_name_array_t table = 0;
mach_msg_type_number_t tableCount = 0;
ipc_info_tree_name_array_t tree = 0;
mach_msg_type_number_t treeCount = 0;
kern_return_t ret = mach_port_space_info(mach_task_self(), &info, &table, &tableCount, &tree, &treeCount);
if (ret != KERN_SUCCESS) {
return (uint32_t)0;
}
if (table != NULL) {
ret = vm_deallocate(mach_task_self(), (vm_address_t)table, tableCount * sizeof(*table));
}
if (tree != NULL) {
ret = vm_deallocate(mach_task_self(), (vm_address_t)tree, treeCount * sizeof(*tree));
}
return (uint32_t)tableCount;
}
CF_PRIVATE CFArrayRef __CFStopAllThreads(void) {
CFMutableArrayRef suspended_list = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
mach_port_t my_task = mach_task_self();
mach_port_t my_thread = mach_thread_self();
thread_act_array_t thr_list = 0;
mach_msg_type_number_t thr_cnt = 0;
kern_return_t ret = task_threads(my_task, &thr_list, &thr_cnt);
if (ret == KERN_SUCCESS) {
for (CFIndex idx = 0; idx < thr_cnt; idx++) {
thread_act_t thread = thr_list[idx];
if (thread == my_thread) continue;
if (CFArrayContainsValue(suspended_list, CFRangeMake(0, CFArrayGetCount(suspended_list)), (const void *)(uintptr_t)thread)) continue;
ret = thread_suspend(thread);
if (ret == KERN_SUCCESS) {
CFArrayAppendValue(suspended_list, (const void *)(uintptr_t)thread);
} else {
mach_port_deallocate(my_task, thread);
}
}
vm_deallocate(my_task, (vm_address_t)thr_list, sizeof(thread_t) * thr_cnt);
}
mach_port_deallocate(my_task, my_thread);
return suspended_list;
}
CF_PRIVATE void __CFRestartAllThreads(CFArrayRef threads) {
for (CFIndex idx = 0; idx < CFArrayGetCount(threads); idx++) {
thread_act_t thread = (thread_act_t)(uintptr_t)CFArrayGetValueAtIndex(threads, idx);
kern_return_t ret = thread_resume(thread);
if (ret != KERN_SUCCESS) CRASH("*** Failure from thread_resume (%d) ***", ret);
mach_port_deallocate(mach_task_self(), thread);
}
}
static uint32_t __CF_last_warned_port_count = 0;
static void foo() __attribute__((unused));
static void foo() {
uint32_t pcnt = __CFGetProcessPortCount();
if (__CF_last_warned_port_count + 1000 < pcnt) {
CFArrayRef threads = __CFStopAllThreads();
CFOptionFlags responseFlags = 0;
SInt32 result = CFUserNotificationDisplayAlert(0.0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL, CFSTR("High Mach Port Usage"), CFSTR("This application is using a lot of Mach ports."), CFSTR("Default"), CFSTR("Altern"), CFSTR("Other b"), &responseFlags);
if (0 != result) {
CFLog(3, CFSTR("ERROR"));
} else {
switch (responseFlags) {
case kCFUserNotificationDefaultResponse: CFLog(3, CFSTR("DefaultR")); break;
case kCFUserNotificationAlternateResponse: CFLog(3, CFSTR("AltR")); break;
case kCFUserNotificationOtherResponse: CFLog(3, CFSTR("OtherR")); break;
case kCFUserNotificationCancelResponse: CFLog(3, CFSTR("CancelR")); break;
}
}
__CFRestartAllThreads(threads);
CFRelease(threads);
__CF_last_warned_port_count = pcnt;
}
}
typedef mach_port_t __CFPort;
#define CFPORT_NULL MACH_PORT_NULL
typedef mach_port_t __CFPortSet;
static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) { HALT; };
static __CFPort __CFPortAllocate(void) {
__CFPort result = CFPORT_NULL;
kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result);
if (KERN_SUCCESS != ret) {
char msg[256];
snprintf(msg, 256, "*** The system has no mach ports available. You may be able to diagnose which application(s) are using ports by using 'top' or Activity Monitor. (%d) ***", ret);
CRSetCrashLogMessage(msg);
__THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret);
return CFPORT_NULL;
}
ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND);
if (KERN_SUCCESS != ret) CRASH("*** Unable to set send right on mach port. (%d) ***", ret);
mach_port_limits_t limits;
limits.mpl_qlimit = 1;
ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT);
if (KERN_SUCCESS != ret) CRASH("*** Unable to set attributes on mach port. (%d) ***", ret);
return result;
}
CF_INLINE void __CFPortFree(__CFPort port) {
mach_port_destroy(mach_task_self(), port);
}
static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) __attribute__((noinline));
static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) { HALT; };
CF_INLINE __CFPortSet __CFPortSetAllocate(void) {
__CFPortSet result;
kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result);
if (KERN_SUCCESS != ret) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret); }
return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
}
CF_INLINE kern_return_t __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
if (MACH_PORT_NULL == port) {
return -1;
}
return mach_port_insert_member(mach_task_self(), port, portSet);
}
CF_INLINE kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
if (MACH_PORT_NULL == port) {
return -1;
}
return mach_port_extract_member(mach_task_self(), port, portSet);
}
CF_INLINE void __CFPortSetFree(__CFPortSet portSet) {
kern_return_t ret;
mach_port_name_array_t array;
mach_msg_type_number_t idx, number;
ret = mach_port_get_set_status(mach_task_self(), portSet, &array, &number);
if (KERN_SUCCESS == ret) {
for (idx = 0; idx < number; idx++) {
mach_port_extract_member(mach_task_self(), array[idx], portSet);
}
vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t));
}
mach_port_destroy(mach_task_self(), portSet);
}
#elif DEPLOYMENT_TARGET_WINDOWS
typedef HANDLE __CFPort;
#define CFPORT_NULL NULL
typedef struct ___CFPortSet {
uint16_t used;
uint16_t size;
HANDLE *handles;
CFLock_t lock; } *__CFPortSet;
CF_INLINE __CFPort __CFPortAllocate(void) {
return CreateEventA(NULL, true, false, NULL);
}
CF_INLINE void __CFPortFree(__CFPort port) {
CloseHandle(port);
}
static __CFPortSet __CFPortSetAllocate(void) {
__CFPortSet result = (__CFPortSet)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0);
result->used = 0;
result->size = 4;
result->handles = (HANDLE *)CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0);
CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock);
return result;
}
static void __CFPortSetFree(__CFPortSet portSet) {
CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet);
}
static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uint32_t bufSize, uint32_t *portsUsed) {
__CFLock(&(portSet->lock));
__CFPort *result = portBuf;
if (bufSize < portSet->used)
result = (__CFPort *)CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0);
if (portSet->used > 1) {
uint16_t lastPort = portSet->used - 1;
HANDLE swapHandle = portSet->handles[0];
memmove(portSet->handles, &portSet->handles[1], lastPort * sizeof(HANDLE));
portSet->handles[lastPort] = swapHandle;
}
memmove(result, portSet->handles, portSet->used * sizeof(HANDLE));
*portsUsed = portSet->used;
__CFUnlock(&(portSet->lock));
return result;
}
static kern_return_t __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
if (NULL == port) {
return -1;
}
__CFLock(&(portSet->lock));
if (portSet->used >= portSet->size) {
portSet->size += 4;
portSet->handles = (HANDLE *)CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0);
}
if (portSet->used >= MAXIMUM_WAIT_OBJECTS) {
CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS);
}
portSet->handles[portSet->used++] = port;
__CFUnlock(&(portSet->lock));
return KERN_SUCCESS;
}
static kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
int i, j;
if (NULL == port) {
return -1;
}
__CFLock(&(portSet->lock));
for (i = 0; i < portSet->used; i++) {
if (portSet->handles[i] == port) {
for (j = i+1; j < portSet->used; j++) {
portSet->handles[j-1] = portSet->handles[j];
}
portSet->used--;
__CFUnlock(&(portSet->lock));
return true;
}
}
__CFUnlock(&(portSet->lock));
return KERN_SUCCESS;
}
#endif
#if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H)
#if defined(__BIG_ENDIAN__)
typedef struct UnsignedWide {
UInt32 hi;
UInt32 lo;
} UnsignedWide;
#elif defined(__LITTLE_ENDIAN__)
typedef struct UnsignedWide {
UInt32 lo;
UInt32 hi;
} UnsignedWide;
#endif
typedef UnsignedWide AbsoluteTime;
#endif
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#if USE_DISPATCH_SOURCE_FOR_TIMERS
#endif
#if USE_MK_TIMER_TOO
extern mach_port_name_t mk_timer_create(void);
extern kern_return_t mk_timer_destroy(mach_port_name_t name);
extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time);
extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time);
CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(uint64_t x) {
AbsoluteTime a;
a.hi = x >> 32;
a.lo = x & (uint64_t)0xFFFFFFFF;
return a;
}
#endif
static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) {
kern_return_t result;
mach_msg_header_t header;
header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
header.msgh_size = sizeof(mach_msg_header_t);
header.msgh_remote_port = port;
header.msgh_local_port = MACH_PORT_NULL;
header.msgh_id = msg_id;
result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL);
if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header);
return result;
}
#elif DEPLOYMENT_TARGET_WINDOWS
static HANDLE mk_timer_create(void) {
return CreateWaitableTimer(NULL, FALSE, NULL);
}
static kern_return_t mk_timer_destroy(HANDLE name) {
BOOL res = CloseHandle(name);
if (!res) {
DWORD err = GetLastError();
CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to destroy timer: %d"), err);
}
return (int)res;
}
static kern_return_t mk_timer_arm(HANDLE name, LARGE_INTEGER expire_time) {
BOOL res = SetWaitableTimer(name, &expire_time, 0, NULL, NULL, FALSE);
if (!res) {
DWORD err = GetLastError();
CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to set timer: %d"), err);
}
return (int)res;
}
static kern_return_t mk_timer_cancel(HANDLE name, LARGE_INTEGER *result_time) {
BOOL res = CancelWaitableTimer(name);
if (!res) {
DWORD err = GetLastError();
CFLog(kCFLogLevelError, CFSTR("CFRunLoop: Unable to cancel timer: %d"), err);
}
return (int)res;
}
CF_INLINE LARGE_INTEGER __CFUInt64ToAbsoluteTime(uint64_t desiredFireTime) {
LARGE_INTEGER result;
uint64_t now = mach_absolute_time();
if (now > desiredFireTime) {
result.QuadPart = 0;
} else {
uint64_t timeDiff = desiredFireTime - now;
CFTimeInterval amountOfTimeToWait = __CFTSRToTimeInterval(timeDiff);
result.QuadPart = -(amountOfTimeToWait * 10000000);
}
return result;
}
#endif
#pragma mark -
#pragma mark Modes
static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID;
static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID;
static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID;
static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID;
static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID;
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline;
uint64_t _timerHardDeadline;
};
CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
pthread_mutex_lock(&(rlm->_lock));
}
CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
pthread_mutex_unlock(&(rlm->_lock));
}
static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
return CFEqual(rlm1->_name, rlm2->_name);
}
static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
return CFHash(rlm->_name);
}
static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, "), rlm, CFGetAllocator(rlm), rlm->_name);
CFStringAppendFormat(result, NULL, CFSTR("port set = 0x%x, "), rlm->_portSet);
#if USE_DISPATCH_SOURCE_FOR_TIMERS
CFStringAppendFormat(result, NULL, CFSTR("queue = %p, "), rlm->_queue);
CFStringAppendFormat(result, NULL, CFSTR("source = %p (%s), "), rlm->_timerSource, rlm->_timerFired ? "fired" : "not fired");
#endif
#if USE_MK_TIMER_TOO
CFStringAppendFormat(result, NULL, CFSTR("timer port = 0x%x, "), rlm->_timerPort);
#endif
#if DEPLOYMENT_TARGET_WINDOWS
CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p, "), rlm->_msgQMask);
#endif
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);
return result;
}
static void __CFRunLoopModeDeallocate(CFTypeRef cf) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
if (NULL != rlm->_sources0) CFRelease(rlm->_sources0);
if (NULL != rlm->_sources1) CFRelease(rlm->_sources1);
if (NULL != rlm->_observers) CFRelease(rlm->_observers);
if (NULL != rlm->_timers) CFRelease(rlm->_timers);
if (NULL != rlm->_portToV1SourceMap) CFRelease(rlm->_portToV1SourceMap);
CFRelease(rlm->_name);
__CFPortSetFree(rlm->_portSet);
#if USE_DISPATCH_SOURCE_FOR_TIMERS
if (rlm->_timerSource) {
dispatch_source_cancel(rlm->_timerSource);
dispatch_release(rlm->_timerSource);
}
if (rlm->_queue) {
dispatch_release(rlm->_queue);
}
#endif
#if USE_MK_TIMER_TOO
if (MACH_PORT_NULL != rlm->_timerPort) mk_timer_destroy(rlm->_timerPort);
#endif
pthread_mutex_destroy(&rlm->_lock);
memset((char *)cf + sizeof(CFRuntimeBase), 0x7C, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase));
}
#pragma mark -
#pragma mark Run Loops
struct _block_item {
struct _block_item *_next;
CFTypeRef _mode; void (^_block)(void);
};
typedef struct _per_run_data {
uint32_t a;
uint32_t b;
uint32_t stopped;
uint32_t ignoreWakeUps;
} _per_run_data;
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock;
__CFPort _wakeUpPort; Boolean _unused;
volatile _per_run_data *_perRunData; pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
CF_INLINE volatile _per_run_data *__CFRunLoopPushPerRunData(CFRunLoopRef rl) {
volatile _per_run_data *previous = rl->_perRunData;
rl->_perRunData = (volatile _per_run_data *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(_per_run_data), 0);
rl->_perRunData->a = 0x4346524C;
rl->_perRunData->b = 0x4346524C; rl->_perRunData->stopped = 0x00000000;
rl->_perRunData->ignoreWakeUps = 0x00000000;
return previous;
}
CF_INLINE void __CFRunLoopPopPerRunData(CFRunLoopRef rl, volatile _per_run_data *previous) {
if (rl->_perRunData) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (void *)rl->_perRunData);
rl->_perRunData = previous;
}
CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
return (rl->_perRunData->stopped) ? true : false;
}
CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
rl->_perRunData->stopped = 0x53544F50; }
CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
rl->_perRunData->stopped = 0x0;
}
CF_INLINE Boolean __CFRunLoopIsIgnoringWakeUps(CFRunLoopRef rl) {
return (rl->_perRunData->ignoreWakeUps) ? true : false;
}
CF_INLINE void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl) {
rl->_perRunData->ignoreWakeUps = 0x57414B45; }
CF_INLINE void __CFRunLoopUnsetIgnoreWakeUps(CFRunLoopRef rl) {
rl->_perRunData->ignoreWakeUps = 0x0;
}
CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1);
}
CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
}
CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
}
CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2);
}
CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1);
}
CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
pthread_mutex_lock(&(((CFRunLoopRef)rl)->_lock));
}
CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
pthread_mutex_unlock(&(((CFRunLoopRef)rl)->_lock));
}
static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) {
CFRunLoopRef rl = (CFRunLoopRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
#if DEPLOYMENT_TARGET_WINDOWS
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)"));
#else
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)"));
#endif
CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
return result;
}
CF_PRIVATE void __CFRunLoopDump() { CFShow(CFCopyDescription(CFRunLoopGetCurrent()));
}
CF_INLINE void __CFRunLoopLockInit(pthread_mutex_t *lock) {
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
int32_t mret = pthread_mutex_init(lock, &mattr);
pthread_mutexattr_destroy(&mattr);
if (0 != mret) {
}
}
static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
struct __CFRunLoopMode srlm;
memset(&srlm, 0, sizeof(srlm));
_CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
srlm._name = modeName;
rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
if (NULL != rlm) {
__CFRunLoopModeLock(rlm);
return rlm;
}
if (!create) {
return NULL;
}
rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
if (NULL == rlm) {
return NULL;
}
__CFRunLoopLockInit(&rlm->_lock);
rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
rlm->_stopped = false;
rlm->_portToV1SourceMap = NULL;
rlm->_sources0 = NULL;
rlm->_sources1 = NULL;
rlm->_observers = NULL;
rlm->_timers = NULL;
rlm->_observerMask = 0;
rlm->_portSet = __CFPortSetAllocate();
rlm->_timerSoftDeadline = UINT64_MAX;
rlm->_timerHardDeadline = UINT64_MAX;
kern_return_t ret = KERN_SUCCESS;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
rlm->_timerFired = false;
rlm->_queue = _dispatch_runloop_root_queue_create_4CF("Run Loop Mode Queue", 0);
mach_port_t queuePort = _dispatch_runloop_root_queue_get_port_4CF(rlm->_queue);
if (queuePort == MACH_PORT_NULL) CRASH("*** Unable to create run loop mode queue port. (%d) ***", -1);
rlm->_timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, rlm->_queue);
__block Boolean *timerFiredPointer = &(rlm->_timerFired);
dispatch_source_set_event_handler(rlm->_timerSource, ^{
*timerFiredPointer = true;
});
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 321);
dispatch_resume(rlm->_timerSource);
ret = __CFPortSetInsert(queuePort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
#endif
#if USE_MK_TIMER_TOO
rlm->_timerPort = mk_timer_create();
ret = __CFPortSetInsert(rlm->_timerPort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
#endif
ret = __CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret);
#if DEPLOYMENT_TARGET_WINDOWS
rlm->_msgQMask = 0;
rlm->_msgPump = NULL;
#endif
CFSetAddValue(rl->_modes, rlm);
CFRelease(rlm);
__CFRunLoopModeLock(rlm);
return rlm;
}
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
CHECK_FOR_FORK();
if (NULL == rlm) return true;
#if DEPLOYMENT_TARGET_WINDOWS
if (0 != rlm->_msgQMask) return false;
#endif
Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false;
if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false;
if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false;
struct _block_item *item = rl->_blocks_head;
while (item) {
struct _block_item *curr = item;
item = item->_next;
Boolean doit = false;
if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
} else {
doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
}
if (doit) return false;
}
return true;
}
#if DEPLOYMENT_TARGET_WINDOWS
uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) {
if (modeName == kCFRunLoopCommonModes) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
HALT;
}
DWORD result = 0;
__CFRunLoopLock(rl);
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
if (rlm) {
result = rlm->_msgQMask;
__CFRunLoopModeUnlock(rlm);
}
__CFRunLoopUnlock(rl);
return (uint32_t)result;
}
void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t mask, CFStringRef modeName) {
if (modeName == kCFRunLoopCommonModes) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
HALT;
}
__CFRunLoopLock(rl);
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
rlm->_msgQMask = (DWORD)mask;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
}
uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl) {
return rl->_winthread;
}
CFWindowsMessageQueueHandler _CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName) {
if (modeName == kCFRunLoopCommonModes) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
HALT;
}
if (rl != CFRunLoopGetCurrent()) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
HALT;
}
void (*result)(void) = NULL;
__CFRunLoopLock(rl);
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
if (rlm) {
result = rlm->_msgPump;
__CFRunLoopModeUnlock(rlm);
}
__CFRunLoopUnlock(rl);
return result;
}
void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName, CFWindowsMessageQueueHandler func) {
if (modeName == kCFRunLoopCommonModes) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported"));
HALT;
}
if (rl != CFRunLoopGetCurrent()) {
CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop"));
HALT;
}
__CFRunLoopLock(rl);
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
rlm->_msgPump = func;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
}
#endif
#pragma mark -
#pragma mark Sources
CF_INLINE Boolean __CFIsValid(const void *cf) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3);
}
CF_INLINE void __CFSetValid(void *cf) {
__CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
}
CF_INLINE void __CFUnsetValid(void *cf) {
__CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
}
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order;
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0;
CFRunLoopSourceContext1 version1;
} _context;
};
CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
}
CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
__CFBitfieldSetValue(rls->_bits, 1, 1, 1);
}
CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
__CFBitfieldSetValue(rls->_bits, 1, 1, 0);
}
CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) {
pthread_mutex_lock(&(rls->_lock));
}
CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
pthread_mutex_unlock(&(rls->_lock));
}
#pragma mark Observers
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities;
CFIndex _order;
CFRunLoopObserverCallBack _callout;
CFRunLoopObserverContext _context;
};
CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0);
}
CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
}
CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
}
CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1);
}
CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
}
CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
}
CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
pthread_mutex_lock(&(rlo->_lock));
}
CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
pthread_mutex_unlock(&(rlo->_lock));
}
static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
__CFRunLoopObserverLock(rlo);
if (0 == rlo->_rlCount) {
rlo->_runLoop = rl;
}
rlo->_rlCount++;
__CFRunLoopObserverUnlock(rlo);
}
static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
__CFRunLoopObserverLock(rlo);
rlo->_rlCount--;
if (0 == rlo->_rlCount) {
rlo->_runLoop = NULL;
}
__CFRunLoopObserverUnlock(rlo);
}
#pragma mark Timers
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval;
CFTimeInterval _tolerance;
uint64_t _fireTSR;
CFIndex _order;
CFRunLoopTimerCallBack _callout;
CFRunLoopTimerContext _context;
};
CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
return (Boolean)__CFBitfieldGetValue(rlt->_bits, 0, 0);
}
CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(rlt->_bits, 0, 0, 1);
}
CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(rlt->_bits, 0, 0, 0);
}
CF_INLINE Boolean __CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt) {
return (Boolean)__CFBitfieldGetValue(rlt->_bits, 2, 2);
}
CF_INLINE void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(rlt->_bits, 2, 2, 1);
}
CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
pthread_mutex_lock(&(rlt->_lock));
}
CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
pthread_mutex_unlock(&(rlt->_lock));
}
static CFLock_t __CFRLTFireTSRLock = CFLockInit;
CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
__CFLock(&__CFRLTFireTSRLock);
}
CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
__CFUnlock(&__CFRLTFireTSRLock);
}
#pragma mark -
CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) {
CHECK_FOR_FORK();
CFRunLoopSourceRef found = rlm->_portToV1SourceMap ? (CFRunLoopSourceRef)CFDictionaryGetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)port) : NULL;
return found;
}
static void __CFRunLoopCleanseSources(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)context;
CFIndex idx, cnt;
const void **list, *buffer[256];
if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;
cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0);
list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list);
if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0));
for (idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
__CFRunLoopSourceLock(rls);
if (NULL != rls->_runLoops) {
CFBagRemoveValue(rls->_runLoops, rl);
}
__CFRunLoopSourceUnlock(rls);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
static void __CFRunLoopDeallocateSources(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)context;
CFIndex idx, cnt;
const void **list, *buffer[256];
if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;
cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0);
list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list);
if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0));
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
if (rlm->_sources0) CFSetRemoveAllValues(rlm->_sources0);
if (rlm->_sources1) CFSetRemoveAllValues(rlm->_sources1);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
__CFRunLoopSourceLock(rls);
if (NULL != rls->_runLoops) {
CFBagRemoveValue(rls->_runLoops, rl);
}
__CFRunLoopSourceUnlock(rls);
if (0 == rls->_context.version0.version) {
if (NULL != rls->_context.version0.cancel) {
rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name);
}
} else if (1 == rls->_context.version0.version) {
__CFPort port = rls->_context.version1.getPort(rls->_context.version1.info);
if (CFPORT_NULL != port) {
__CFPortSetRemove(port, rlm->_portSet);
}
}
CFRelease(rls);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)context;
CFIndex idx, cnt;
const void **list, *buffer[256];
if (NULL == rlm->_observers) return;
cnt = CFArrayGetCount(rlm->_observers);
list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
CFArrayGetValues(rlm->_observers, CFRangeMake(0, cnt), list);
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
CFArrayRemoveAllValues(rlm->_observers);
for (idx = 0; idx < cnt; idx++) {
__CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm);
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
static void __CFRunLoopDeallocateTimers(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
if (NULL == rlm->_timers) return;
void (^deallocateTimers)(CFMutableArrayRef timers) = ^(CFMutableArrayRef timers) {
CFIndex idx, cnt;
const void **list, *buffer[256];
cnt = CFArrayGetCount(timers);
list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
CFArrayGetValues(timers, CFRangeMake(0, CFArrayGetCount(timers)), list);
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
CFArrayRemoveAllValues(timers);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx];
__CFRunLoopTimerLock(rlt);
CFSetRemoveAllValues(rlt->_rlModes);
rlt->_runLoop = NULL;
__CFRunLoopTimerUnlock(rlt);
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
};
if (rlm->_timers && CFArrayGetCount(rlm->_timers)) deallocateTimers(rlm->_timers);
}
CF_EXPORT CFRunLoopRef _CFRunLoopGet0b(pthread_t t);
static void __CFRunLoopDeallocate(CFTypeRef cf) {
CFRunLoopRef rl = (CFRunLoopRef)cf;
if (_CFRunLoopGet0b(pthread_main_thread_np()) == cf) HALT;
__CFRunLoopSetDeallocating(rl);
if (NULL != rl->_modes) {
CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
}
__CFRunLoopLock(rl);
struct _block_item *item = rl->_blocks_head;
while (item) {
struct _block_item *curr = item;
item = item->_next;
CFRelease(curr->_mode);
Block_release(curr->_block);
free(curr);
}
if (NULL != rl->_commonModeItems) {
CFRelease(rl->_commonModeItems);
}
if (NULL != rl->_commonModes) {
CFRelease(rl->_commonModes);
}
if (NULL != rl->_modes) {
CFRelease(rl->_modes);
}
__CFPortFree(rl->_wakeUpPort);
rl->_wakeUpPort = CFPORT_NULL;
__CFRunLoopPopPerRunData(rl, NULL);
__CFRunLoopUnlock(rl);
pthread_mutex_destroy(&rl->_lock);
memset((char *)cf + sizeof(CFRuntimeBase), 0x8C, sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase));
}
static const CFRuntimeClass __CFRunLoopModeClass = {
0,
"CFRunLoopMode",
NULL, NULL, __CFRunLoopModeDeallocate,
__CFRunLoopModeEqual,
__CFRunLoopModeHash,
NULL, __CFRunLoopModeCopyDescription
};
static const CFRuntimeClass __CFRunLoopClass = {
0,
"CFRunLoop",
NULL, NULL, __CFRunLoopDeallocate,
NULL,
NULL,
NULL, __CFRunLoopCopyDescription
};
CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data);
CFTypeID CFRunLoopGetTypeID(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{ __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass); __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); });
return __kCFRunLoopTypeID;
}
static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL);
if (NULL == loop) {
return NULL;
}
(void)__CFRunLoopPushPerRunData(loop);
__CFRunLoopLockInit(&loop->_lock);
loop->_wakeUpPort = __CFPortAllocate();
if (CFPORT_NULL == loop->_wakeUpPort) HALT;
__CFRunLoopSetIgnoreWakeUps(loop);
loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
loop->_commonModeItems = NULL;
loop->_currentMode = NULL;
loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
loop->_blocks_head = NULL;
loop->_blocks_tail = NULL;
loop->_counterpart = NULL;
loop->_pthread = t;
#if DEPLOYMENT_TARGET_WINDOWS
loop->_winthread = GetCurrentThreadId();
#else
loop->_winthread = 0;
#endif
rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
return loop;
}
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFLock_t loopsLock = CFLockInit;
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
if (!__CFRunLoops) {
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
CFRelease(mainLoop);
__CFLock(&loopsLock);
}
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFUnlock(&loopsLock);
if (!loop) {
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
__CFUnlock(&loopsLock);
CFRelease(newLoop);
}
if (pthread_equal(t, pthread_self())) {
_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
}
}
return loop;
}
CFRunLoopRef _CFRunLoopGet0b(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
CFRunLoopRef loop = NULL;
if (__CFRunLoops) {
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
}
__CFUnlock(&loopsLock);
return loop;
}
static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName);
CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data) {
CFRunLoopRef rl = NULL;
if (data <= 1) {
__CFLock(&loopsLock);
if (__CFRunLoops) {
rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
if (rl) CFRetain(rl);
CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
}
__CFUnlock(&loopsLock);
} else {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(data - 1), (void (*)(void *))__CFFinalizeRunLoop);
}
if (rl && CFRunLoopGetMain() != rl) { if (NULL != rl->_counterpart) {
CFRelease(rl->_counterpart);
rl->_counterpart = NULL;
}
CFArrayRef array = CFRunLoopCopyAllModes(rl);
for (CFIndex idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
__CFRunLoopRemoveAllSources(rl, modeName);
}
__CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
CFRelease(array);
}
if (rl) CFRelease(rl);
}
pthread_t _CFRunLoopGet1(CFRunLoopRef rl) {
return rl->_pthread;
}
CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl) {
CFTypeRef ret = NULL;
__CFLock(&loopsLock);
ret = rl->_counterpart;
__CFUnlock(&loopsLock);
return ret;
}
CF_EXPORT CFTypeRef _CFRunLoopGet2b(CFRunLoopRef rl) {
return rl->_counterpart;
}
#if DEPLOYMENT_TARGET_MACOSX
void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
if (pthread_main_np()) return;
CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
if (rl != currentLoop) {
CFRetain(currentLoop); __CFLock(&loopsLock);
if (rl) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl);
} else {
CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
}
__CFUnlock(&loopsLock);
CFRelease(currentLoop);
_CFSetTSD(__CFTSDKeyRunLoop, NULL, NULL);
_CFSetTSD(__CFTSDKeyRunLoopCntr, 0, (void (*)(void *))__CFFinalizeRunLoop);
}
}
#endif
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); return __main;
}
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
CHECK_FOR_FORK();
CFStringRef result = NULL;
__CFRunLoopLock(rl);
if (NULL != rl->_currentMode) {
result = (CFStringRef)CFRetain(rl->_currentMode->_name);
}
__CFRunLoopUnlock(rl);
return result;
}
static void __CFRunLoopGetModeName(const void *value, void *context) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
CFMutableArrayRef array = (CFMutableArrayRef)context;
CFArrayAppendValue(array, rlm->_name);
}
CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) {
CHECK_FOR_FORK();
CFMutableArrayRef array;
__CFRunLoopLock(rl);
array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks);
CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array);
__CFRunLoopUnlock(rl);
return array;
}
static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) {
CFTypeRef item = (CFTypeRef)value;
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
}
}
static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) {
CFStringRef modeName = (CFStringRef)value;
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName);
}
}
static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
CFStringRef modeName = (CFStringRef)value;
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
}
}
CF_EXPORT Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) {
__CFRunLoopLock(rl);
Boolean present = CFSetContainsValue(rl->_commonModes, modeName);
__CFRunLoopUnlock(rl);
return present;
}
void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
__CFRunLoopLock(rl);
if (!CFSetContainsValue(rl->_commonModes, modeName)) {
CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
CFSetAddValue(rl->_commonModes, modeName);
if (NULL != set) {
CFTypeRef context[2] = {rl, modeName};
CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
CFRelease(set);
}
} else {
}
__CFRunLoopUnlock(rl);
}
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() __attribute__((noinline));
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(void *msg) {
_dispatch_main_queue_callback_4CF(msg);
asm __volatile__(""); }
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
if (func) {
func(observer, activity, info);
}
asm __volatile__(""); }
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func, CFRunLoopTimerRef timer, void *info) {
if (func) {
func(timer, info);
}
asm __volatile__(""); }
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block)(void)) {
if (block) {
block();
}
asm __volatile__(""); }
static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm) { if (!rl->_blocks_head) return false;
if (!rlm || !rlm->_name) return false;
Boolean did = false;
struct _block_item *head = rl->_blocks_head;
struct _block_item *tail = rl->_blocks_tail;
rl->_blocks_head = NULL;
rl->_blocks_tail = NULL;
CFSetRef commonModes = rl->_commonModes;
CFStringRef curMode = rlm->_name;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
struct _block_item *prev = NULL;
struct _block_item *item = head;
while (item) {
struct _block_item *curr = item;
item = item->_next;
Boolean doit = false;
if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
} else {
doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
}
if (!doit) prev = curr;
if (doit) {
if (prev) prev->_next = item;
if (curr == head) head = item;
if (curr == tail) tail = prev;
void (^block)(void) = curr->_block;
CFRelease(curr->_mode);
free(curr);
if (doit) {
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
did = true;
}
Block_release(block); }
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (head) {
tail->_next = rl->_blocks_head;
rl->_blocks_head = head;
if (!rl->_blocks_tail) rl->_blocks_tail = tail;
}
return did;
}
static void __CFRunLoopDoObservers() __attribute__((noinline));
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) {
CHECK_FOR_FORK();
CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
if (cnt < 1) return;
STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef));
CFIndex obs_cnt = 0;
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo);
}
}
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
for (CFIndex idx = 0; idx < obs_cnt; idx++) {
CFRunLoopObserverRef rlo = collectedObservers[idx];
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo);
__CFRunLoopObserverSetFiring(rlo);
__CFRunLoopObserverUnlock(rlo);
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info);
if (doInvalidate) {
CFRunLoopObserverInvalidate(rlo);
}
__CFRunLoopObserverUnsetFiring(rlo);
} else {
__CFRunLoopObserverUnlock(rlo);
}
CFRelease(rlo);
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (collectedObservers != buffer) free(collectedObservers);
}
static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) {
CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1;
CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2;
if (o1->_order < o2->_order) return kCFCompareLessThan;
if (o2->_order < o1->_order) return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
static void __CFRunLoopCollectSources0(const void *value, void *context) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
CFTypeRef *sources = (CFTypeRef *)context;
if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) {
if (NULL == *sources) {
*sources = CFRetain(rls);
} else if (CFGetTypeID(*sources) == CFRunLoopSourceGetTypeID()) {
CFTypeRef oldrls = *sources;
*sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls);
CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
CFRelease(oldrls);
} else {
CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
}
}
}
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info) {
if (perform) {
perform(info);
}
asm __volatile__(""); }
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
void *(*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info),
mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply,
#else
void (*perform)(void *),
#endif
void *info) {
if (perform) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
*reply = perform(msg, size, kCFAllocatorSystemDefault, info);
#else
perform(info);
#endif
}
asm __volatile__(""); }
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) __attribute__((noinline));
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) {
CHECK_FOR_FORK();
CFTypeRef sources = NULL;
Boolean sourceHandled = false;
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) {
CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources);
}
if (NULL != sources) {
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
if (CFGetTypeID(sources) == CFRunLoopSourceGetTypeID()) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
__CFRunLoopSourceLock(rls);
if (__CFRunLoopSourceIsSignaled(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
CFIndex cnt = CFArrayGetCount((CFArrayRef)sources);
CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx);
__CFRunLoopSourceLock(rls);
if (__CFRunLoopSourceIsSignaled(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
if (stopAfterHandle && sourceHandled) {
break;
}
}
}
CFRelease(sources);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
}
return sourceHandled;
}
CF_INLINE void __CFRunLoopDebugInfoForRunLoopSource(CFRunLoopSourceRef rls) {
}
static Boolean __CFRunLoopDoSource1() __attribute__((noinline));
static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
, mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply
#endif
) {
CHECK_FOR_FORK();
Boolean sourceHandled = false;
CFRetain(rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
__CFRunLoopSourceUnlock(rls);
__CFRunLoopDebugInfoForRunLoopSource(rls);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(rls->_context.version1.perform,
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
msg, size, reply,
#endif
rls->_context.version1.info);
CHECK_FOR_FORK();
sourceHandled = true;
} else {
if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
__CFRunLoopSourceUnlock(rls);
}
CFRelease(rls);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
return sourceHandled;
}
static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) __attribute__((noinline));
static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) {
CFIndex cnt = CFArrayGetCount(array);
if (cnt <= 0) {
return 0;
}
if (256 < cnt) {
CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, cnt - 1);
if (item->_fireTSR <= rlt->_fireTSR) {
return cnt;
}
item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, 0);
if (rlt->_fireTSR < item->_fireTSR) {
return 0;
}
}
CFIndex add = (1 << flsl(cnt)) * 2;
CFIndex idx = 0;
Boolean lastTestLEQ;
do {
add = add / 2;
lastTestLEQ = false;
CFIndex testIdx = idx + add;
if (testIdx < cnt) {
CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, testIdx);
if (item->_fireTSR <= rlt->_fireTSR) {
idx = testIdx;
lastTestLEQ = true;
}
}
} while (0 < add);
return lastTestLEQ ? idx + 1 : idx;
}
static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm, CFRunLoopRef rl) {
uint64_t nextHardDeadline = UINT64_MAX;
uint64_t nextSoftDeadline = UINT64_MAX;
if (rlm->_timers) {
for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) {
CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers , idx);
if (__CFRunLoopTimerIsFiring(t)) continue;
int32_t err = CHECKINT_NO_ERROR;
uint64_t oneTimerSoftDeadline = t->_fireTSR;
uint64_t oneTimerHardDeadline = check_uint64_add(t->_fireTSR, __CFTimeIntervalToTSR(t->_tolerance), &err);
if (err != CHECKINT_NO_ERROR) oneTimerHardDeadline = UINT64_MAX;
if (oneTimerSoftDeadline > nextHardDeadline) {
break;
}
if (oneTimerSoftDeadline < nextSoftDeadline) {
nextSoftDeadline = oneTimerSoftDeadline;
}
if (oneTimerHardDeadline < nextHardDeadline) {
nextHardDeadline = oneTimerHardDeadline;
}
}
if (nextSoftDeadline < UINT64_MAX && (nextHardDeadline != rlm->_timerHardDeadline || nextSoftDeadline != rlm->_timerSoftDeadline)) {
if (CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED()) {
CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline - mach_absolute_time()));
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
uint64_t leeway = __CFTSRToNanoseconds(nextHardDeadline - nextSoftDeadline);
dispatch_time_t deadline = __CFTSRToDispatchTime(nextSoftDeadline);
#if USE_MK_TIMER_TOO
if (leeway > 0) {
if (rlm->_mkTimerArmed && rlm->_timerPort) {
AbsoluteTime dummy;
mk_timer_cancel(rlm->_timerPort, &dummy);
rlm->_mkTimerArmed = false;
}
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
rlm->_dispatchTimerArmed = true;
} else {
if (rlm->_dispatchTimerArmed) {
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 888);
rlm->_dispatchTimerArmed = false;
}
if (rlm->_timerPort) {
mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
rlm->_mkTimerArmed = true;
}
}
#else
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
#endif
#else
if (rlm->_timerPort) {
mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
}
#endif
} else if (nextSoftDeadline == UINT64_MAX) {
if (rlm->_mkTimerArmed && rlm->_timerPort) {
AbsoluteTime dummy;
mk_timer_cancel(rlm->_timerPort, &dummy);
rlm->_mkTimerArmed = false;
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
if (rlm->_dispatchTimerArmed) {
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 333);
rlm->_dispatchTimerArmed = false;
}
#endif
}
}
rlm->_timerHardDeadline = nextHardDeadline;
rlm->_timerSoftDeadline = nextSoftDeadline;
}
static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) __attribute__((noinline));
static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) {
if (!rlt) return;
CFMutableArrayRef timerArray = rlm->_timers;
if (!timerArray) return;
Boolean found = false;
if (isInArray) {
CFIndex idx = CFArrayGetFirstIndexOfValue(timerArray, CFRangeMake(0, CFArrayGetCount(timerArray)), rlt);
if (kCFNotFound != idx) {
CFRetain(rlt);
CFArrayRemoveValueAtIndex(timerArray, idx);
found = true;
}
}
if (!found && isInArray) return;
CFIndex newIdx = __CFRunLoopInsertionIndexInTimerArray(timerArray, rlt);
CFArrayInsertValueAtIndex(timerArray, newIdx, rlt);
__CFArmNextTimerInMode(rlm, rlt->_runLoop);
if (isInArray) CFRelease(rlt);
}
static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) {
Boolean timerHandled = false;
uint64_t oldFireTSR = 0;
CFRetain(rlt);
__CFRunLoopTimerLock(rlt);
if (__CFIsValid(rlt) && rlt->_fireTSR <= mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl) {
void *context_info = NULL;
void (*context_release)(const void *) = NULL;
if (rlt->_context.retain) {
context_info = (void *)rlt->_context.retain(rlt->_context.info);
context_release = rlt->_context.release;
} else {
context_info = rlt->_context.info;
}
Boolean doInvalidate = (0.0 == rlt->_interval);
__CFRunLoopTimerSetFiring(rlt);
rlm->_timerSoftDeadline = UINT64_MAX;
rlm->_timerHardDeadline = UINT64_MAX;
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
oldFireTSR = rlt->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
__CFArmNextTimerInMode(rlm, rl);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt->_callout, rlt, context_info);
CHECK_FOR_FORK();
if (doInvalidate) {
CFRunLoopTimerInvalidate(rlt);
}
if (context_release) {
context_release(context_info);
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFRunLoopTimerLock(rlt);
timerHandled = true;
__CFRunLoopTimerUnsetFiring(rlt);
}
if (__CFIsValid(rlt) && timerHandled) {
if (oldFireTSR < rlt->_fireTSR) {
__CFRunLoopTimerUnlock(rlt);
__CFArmNextTimerInMode(rlm, rl);
} else {
uint64_t nextFireTSR = 0LL;
uint64_t intervalTSR = 0LL;
if (rlt->_interval <= 0.0) {
} else if (TIMER_INTERVAL_LIMIT < rlt->_interval) {
intervalTSR = __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
} else {
intervalTSR = __CFTimeIntervalToTSR(rlt->_interval);
}
if (LLONG_MAX - intervalTSR <= oldFireTSR) {
nextFireTSR = LLONG_MAX;
} else {
if (intervalTSR == 0) {
CRSetCrashLogMessage("A CFRunLoopTimer with an interval of 0 is set to repeat");
HALT;
}
uint64_t currentTSR = mach_absolute_time();
nextFireTSR = oldFireTSR;
while (nextFireTSR <= currentTSR) {
nextFireTSR += intervalTSR;
}
}
CFRunLoopRef rlt_rl = rlt->_runLoop;
if (rlt_rl) {
CFRetain(rlt_rl);
CFIndex cnt = CFSetGetCount(rlt->_rlModes);
STACK_BUFFER_DECL(CFTypeRef, modes, cnt);
CFSetGetValues(rlt->_rlModes, (const void **)modes);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRetain(modes[idx]);
}
__CFRunLoopTimerUnlock(rlt);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFStringRef name = (CFStringRef)modes[idx];
modes[idx] = (CFTypeRef)__CFRunLoopFindMode(rlt_rl, name, false);
CFRelease(name);
}
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx];
if (rlm) {
__CFRepositionTimerInMode(rlm, rlt, true);
}
}
__CFRunLoopTimerFireTSRUnlock();
for (CFIndex idx = 0; idx < cnt; idx++) {
__CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]);
}
CFRelease(rlt_rl);
} else {
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
__CFRunLoopTimerFireTSRUnlock();
}
}
} else {
__CFRunLoopTimerUnlock(rlt);
}
CFRelease(rlt);
return timerHandled;
}
static Boolean __CFRunLoopDoTimers(CFRunLoopRef rl, CFRunLoopModeRef rlm, uint64_t limitTSR) {
Boolean timerHandled = false;
CFMutableArrayRef timers = NULL;
for (CFIndex idx = 0, cnt = rlm->_timers ? CFArrayGetCount(rlm->_timers) : 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx);
if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
if (rlt->_fireTSR <= limitTSR) {
if (!timers) timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(timers, rlt);
}
}
}
for (CFIndex idx = 0, cnt = timers ? CFArrayGetCount(timers) : 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timers, idx);
Boolean did = __CFRunLoopDoTimer(rl, rlm, rlt);
timerHandled = timerHandled || did;
}
if (timers) CFRelease(timers);
return timerHandled;
}
CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
Boolean result = false;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm, NULL)) {
result = true;
}
if (rlm) __CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
return result;
}
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) __attribute__((noinline));
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0)
static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_port_t *livePort, mach_msg_timeout_t timeout, voucher_mach_msg_state_t *voucherState, voucher_t *voucherCopy) {
Boolean originalBuffer = true;
kern_return_t ret = KERN_SUCCESS;
for (;;) {
mach_msg_header_t *msg = (mach_msg_header_t *)*buffer;
msg->msgh_bits = 0;
msg->msgh_local_port = port;
msg->msgh_remote_port = MACH_PORT_NULL;
msg->msgh_size = buffer_size;
msg->msgh_id = 0;
if (TIMEOUT_INFINITY == timeout) { CFRUNLOOP_SLEEP(); } else { CFRUNLOOP_POLL(); }
ret = mach_msg(msg, MACH_RCV_MSG|(voucherState ? MACH_RCV_VOUCHER : 0)|MACH_RCV_LARGE|((TIMEOUT_INFINITY != timeout) ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, timeout, MACH_PORT_NULL);
voucher_mach_msg_revert(*voucherState);
*voucherState = voucher_mach_msg_adopt(msg);
if (voucherCopy) {
if (*voucherState != VOUCHER_MACH_MSG_STATE_UNCHANGED) {
*voucherCopy = voucher_copy();
} else {
*voucherCopy = NULL;
}
}
CFRUNLOOP_WAKEUP(ret);
if (MACH_MSG_SUCCESS == ret) {
*livePort = msg ? msg->msgh_local_port : MACH_PORT_NULL;
return true;
}
if (MACH_RCV_TIMED_OUT == ret) {
if (!originalBuffer) free(msg);
*buffer = NULL;
*livePort = MACH_PORT_NULL;
return false;
}
if (MACH_RCV_TOO_LARGE != ret) break;
buffer_size = round_msg(msg->msgh_size + MAX_TRAILER_SIZE);
if (originalBuffer) *buffer = NULL;
originalBuffer = false;
*buffer = realloc(*buffer, buffer_size);
}
HALT;
return false;
}
#elif DEPLOYMENT_TARGET_WINDOWS
#define TIMEOUT_INFINITY INFINITE
static Boolean __CFRunLoopWaitForMultipleObjects(__CFPortSet portSet, HANDLE *onePort, DWORD timeout, DWORD mask, HANDLE *livePort, Boolean *msgReceived) {
DWORD waitResult = WAIT_TIMEOUT;
HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS];
HANDLE *handles = NULL;
uint32_t handleCount = 0;
Boolean freeHandles = false;
Boolean result = false;
if (portSet) {
handles = __CFPortSetGetPorts(portSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount);
freeHandles = (handles != handleBuf);
} else {
handles = onePort;
handleCount = 1;
freeHandles = FALSE;
}
waitResult = MsgWaitForMultipleObjectsEx(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, timeout, mask, MWMO_INPUTAVAILABLE);
CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError());
if (waitResult == WAIT_TIMEOUT) {
result = false;
} else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) {
if (livePort) *livePort = handles[waitResult-WAIT_OBJECT_0];
result = true;
} else if (waitResult == WAIT_OBJECT_0+handleCount) {
if (msgReceived) *msgReceived = true;
result = true;
} else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) {
if (livePort) *livePort = handles[waitResult-WAIT_ABANDONED_0];
result = true;
} else {
CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult);
result = false;
}
if (freeHandles) {
CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
}
return result;
}
#endif
struct __timeout_context {
dispatch_source_t ds;
CFRunLoopRef rl;
uint64_t termTSR;
};
static void __CFRunLoopTimeoutCancel(void *arg) {
struct __timeout_context *context = (struct __timeout_context *)arg;
CFRelease(context->rl);
dispatch_release(context->ds);
free(context);
}
static void __CFRunLoopTimeout(void *arg) {
struct __timeout_context *context = (struct __timeout_context *)arg;
context->termTSR = 0ULL;
CFRUNLOOP_WAKEUP_FOR_TIMEOUT();
CFRunLoopWakeUp(context->rl);
}
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
uint64_t startTSR = mach_absolute_time();
if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
return kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
return kCFRunLoopRunStopped;
}
mach_port_name_t dispatchPort = MACH_PORT_NULL;
Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF();
#if USE_DISPATCH_SOURCE_FOR_TIMERS
mach_port_name_t modeQueuePort = MACH_PORT_NULL;
if (rlm->_queue) {
modeQueuePort = _dispatch_runloop_root_queue_get_port_4CF(rlm->_queue);
if (!modeQueuePort) {
CRASH("Unable to get port for run loop mode queue (%d)", -1);
}
}
#endif
dispatch_source_t timeout_timer = NULL;
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
if (seconds <= 0.0) { seconds = 0.0;
timeout_context->termTSR = 0ULL;
} else if (seconds <= TIMER_INTERVAL_LIMIT) {
dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_retain(timeout_timer);
timeout_context->ds = timeout_timer;
timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
dispatch_set_context(timeout_timer, timeout_context); dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
dispatch_resume(timeout_timer);
} else { seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
Boolean didDispatchPortLastTime = true;
int32_t retVal = 0;
do {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
voucher_mach_msg_state_t voucherState = VOUCHER_MACH_MSG_STATE_UNCHANGED;
voucher_t voucherCopy = NULL;
#endif
uint8_t msg_buffer[3 * 1024];
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
mach_msg_header_t *msg = NULL;
mach_port_t livePort = MACH_PORT_NULL;
#elif DEPLOYMENT_TARGET_WINDOWS
HANDLE livePort = NULL;
Boolean windowsMessageReceived = false;
#endif
__CFPortSet waitSet = rlm->_portSet;
__CFRunLoopUnsetIgnoreWakeUps(rl);
if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
__CFRunLoopDoBlocks(rl, rlm);
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
__CFRunLoopDoBlocks(rl, rlm);
}
Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
msg = (mach_msg_header_t *)msg_buffer;
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
goto handle_msg;
}
#elif DEPLOYMENT_TARGET_WINDOWS
if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) {
goto handle_msg;
}
#endif
}
didDispatchPortLastTime = false;
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
__CFPortSetInsert(dispatchPort, waitSet);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent();
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#if USE_DISPATCH_SOURCE_FOR_TIMERS
do {
if (kCFUseCollectableAllocator) {
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
while (_dispatch_runloop_root_queue_perform_4CF(rlm->_queue));
if (rlm->_timerFired) {
rlm->_timerFired = false;
break;
} else {
if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
}
} else {
break;
}
} while (1);
#else
if (kCFUseCollectableAllocator) {
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
#endif
#elif DEPLOYMENT_TARGET_WINDOWS
__CFRunLoopWaitForMultipleObjects(waitSet, NULL, poll ? 0 : TIMEOUT_INFINITY, rlm->_msgQMask, &livePort, &windowsMessageReceived);
#endif
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart));
__CFPortSetRemove(dispatchPort, waitSet);
__CFRunLoopSetIgnoreWakeUps(rl);
__CFRunLoopUnsetSleeping(rl);
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:;
__CFRunLoopSetIgnoreWakeUps(rl);
#if DEPLOYMENT_TARGET_WINDOWS
if (windowsMessageReceived) {
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
if (rlm->_msgPump) {
rlm->_msgPump();
} else {
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
sourceHandledThisLoop = true;
__CFRunLoopSetSleeping(rl);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
__CFRunLoopWaitForMultipleObjects(waitSet, NULL, 0, 0, &livePort, NULL);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFRunLoopUnsetSleeping(rl);
}
#endif
if (MACH_PORT_NULL == livePort) {
CFRUNLOOP_WAKEUP_FOR_NOTHING();
} else if (livePort == rl->_wakeUpPort) {
CFRUNLOOP_WAKEUP_FOR_WAKEUP();
#if DEPLOYMENT_TARGET_WINDOWS
ResetEvent(rl->_wakeUpPort);
#endif
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
CFRUNLOOP_WAKEUP_FOR_TIMER();
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
#if USE_MK_TIMER_TOO
else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
CFRUNLOOP_WAKEUP_FOR_TIMER();
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
else if (livePort == dispatchPort) {
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
#if DEPLOYMENT_TARGET_WINDOWS
void *msg = 0;
#endif
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
sourceHandledThisLoop = true;
didDispatchPortLastTime = true;
} else {
CFRUNLOOP_WAKEUP_FOR_SOURCE();
voucher_t previousVoucher = _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, (void *)voucherCopy, os_release);
CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);
if (rls) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
mach_msg_header_t *reply = NULL;
sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
if (NULL != reply) {
(void)mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
}
#elif DEPLOYMENT_TARGET_WINDOWS
sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop;
#endif
}
_CFSetTSD(__CFTSDKeyMachMessageHasVoucher, previousVoucher, os_release);
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
#endif
__CFRunLoopDoBlocks(rl, rlm);
if (sourceHandledThisLoop && stopAfterHandle) {
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
retVal = kCFRunLoopRunFinished;
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
voucher_mach_msg_revert(voucherState);
os_release(voucherCopy);
#endif
} while (0 == retVal);
if (timeout_timer) {
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
} else {
free(timeout_context);
}
return retVal;
}
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
Boolean did = false;
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
CFRunLoopModeRef previousMode = rl->_currentMode;
rl->_currentMode = currentMode;
int32_t result = kCFRunLoopRunFinished;
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopPopPerRunData(rl, previousPerRun);
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
void CFRunLoopRun(void) {
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {
CHECK_FOR_FORK();
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
CHECK_FOR_FORK();
__CFRunLoopLock(rl);
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
CFAbsoluteTime at = 0.0;
CFRunLoopTimerRef nextTimer = (rlm && rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) ? (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, 0) : NULL;
if (nextTimer) {
at = CFRunLoopTimerGetNextFireDate(nextTimer);
}
if (rlm) __CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
return at;
}
Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
CHECK_FOR_FORK();
return __CFRunLoopIsSleeping(rl);
}
void CFRunLoopWakeUp(CFRunLoopRef rl) {
CHECK_FOR_FORK();
__CFRunLoopLock(rl);
if (__CFRunLoopIsIgnoringWakeUps(rl)) {
__CFRunLoopUnlock(rl);
return;
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
kern_return_t ret;
ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0);
if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) CRASH("*** Unable to send message to wake up port. (%d) ***", ret);
#elif DEPLOYMENT_TARGET_WINDOWS
SetEvent(rl->_wakeUpPort);
#endif
__CFRunLoopUnlock(rl);
}
void CFRunLoopStop(CFRunLoopRef rl) {
Boolean doWake = false;
CHECK_FOR_FORK();
__CFRunLoopLock(rl);
if (rl->_currentMode) {
__CFRunLoopSetStopped(rl);
doWake = true;
}
__CFRunLoopUnlock(rl);
if (doWake) {
CFRunLoopWakeUp(rl);
}
}
CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm) {
rlm->_stopped = true;
__CFRunLoopModeUnlock(rlm);
}
__CFRunLoopUnlock(rl);
CFRunLoopWakeUp(rl);
}
CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
CHECK_FOR_FORK();
return false;
}
void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) {
CHECK_FOR_FORK();
if (CFStringGetTypeID() == CFGetTypeID(mode)) {
mode = CFStringCreateCopy(kCFAllocatorSystemDefault, (CFStringRef)mode);
__CFRunLoopLock(rl);
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)mode, true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
} else if (CFArrayGetTypeID() == CFGetTypeID(mode)) {
CFIndex cnt = CFArrayGetCount((CFArrayRef)mode);
const void **values = (const void **)malloc(sizeof(const void *) * cnt);
CFArrayGetValues((CFArrayRef)mode, CFRangeMake(0, cnt), values);
mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
__CFRunLoopLock(rl);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
}
__CFRunLoopUnlock(rl);
free(values);
} else if (CFSetGetTypeID() == CFGetTypeID(mode)) {
CFIndex cnt = CFSetGetCount((CFSetRef)mode);
const void **values = (const void **)malloc(sizeof(const void *) * cnt);
CFSetGetValues((CFSetRef)mode, values);
mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
__CFRunLoopLock(rl);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
}
__CFRunLoopUnlock(rl);
free(values);
} else {
mode = NULL;
}
block = Block_copy(block);
if (!mode || !block) {
if (mode) CFRelease(mode);
if (block) Block_release(block);
return;
}
__CFRunLoopLock(rl);
struct _block_item *new_item = (struct _block_item *)malloc(sizeof(struct _block_item));
new_item->_next = NULL;
new_item->_mode = mode;
new_item->_block = block;
if (!rl->_blocks_tail) {
rl->_blocks_head = new_item;
} else {
rl->_blocks_tail->_next = new_item;
}
rl->_blocks_tail = new_item;
__CFRunLoopUnlock(rl);
}
Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rls);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm) {
hasValue = (rlm->_sources0 ? CFSetContainsValue(rlm->_sources0, rls) : false) || (rlm->_sources1 ? CFSetContainsValue(rlm->_sources1, rls) : false);
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
return hasValue;
}
void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rls)) return;
Boolean doVer0Callout = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rls);
if (NULL != set) {
CFTypeRef context[2] = {rl, rls};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm && NULL == rlm->_sources0) {
rlm->_sources0 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
rlm->_sources1 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
rlm->_portToV1SourceMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
}
if (NULL != rlm && !CFSetContainsValue(rlm->_sources0, rls) && !CFSetContainsValue(rlm->_sources1, rls)) {
if (0 == rls->_context.version0.version) {
CFSetAddValue(rlm->_sources0, rls);
} else if (1 == rls->_context.version0.version) {
CFSetAddValue(rlm->_sources1, rls);
__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
if (CFPORT_NULL != src_port) {
CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls);
__CFPortSetInsert(src_port, rlm->_portSet);
}
}
__CFRunLoopSourceLock(rls);
if (NULL == rls->_runLoops) {
rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); }
CFBagAddValue(rls->_runLoops, rl);
__CFRunLoopSourceUnlock(rls);
if (0 == rls->_context.version0.version) {
if (NULL != rls->_context.version0.schedule) {
doVer0Callout = true;
}
}
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
if (doVer0Callout) {
rls->_context.version0.schedule(rls->_context.version0.info, rl, modeName);
}
}
void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CHECK_FOR_FORK();
Boolean doVer0Callout = false, doRLSRelease = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
CFSetRemoveValue(rl->_commonModeItems, rls);
if (NULL != set) {
CFTypeRef context[2] = {rl, rls};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
}
} else {
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm && ((NULL != rlm->_sources0 && CFSetContainsValue(rlm->_sources0, rls)) || (NULL != rlm->_sources1 && CFSetContainsValue(rlm->_sources1, rls)))) {
CFRetain(rls);
if (1 == rls->_context.version0.version) {
__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
if (CFPORT_NULL != src_port) {
CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port);
__CFPortSetRemove(src_port, rlm->_portSet);
}
}
CFSetRemoveValue(rlm->_sources0, rls);
CFSetRemoveValue(rlm->_sources1, rls);
__CFRunLoopSourceLock(rls);
if (NULL != rls->_runLoops) {
CFBagRemoveValue(rls->_runLoops, rl);
}
__CFRunLoopSourceUnlock(rls);
if (0 == rls->_context.version0.version) {
if (NULL != rls->_context.version0.cancel) {
doVer0Callout = true;
}
}
doRLSRelease = true;
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
if (doVer0Callout) {
rls->_context.version0.cancel(rls->_context.version0.info, rl, modeName);
}
if (doRLSRelease) CFRelease(rls);
}
static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
CFStringRef modeName = (CFStringRef)value;
CFRunLoopRef rl = (CFRunLoopRef)ctx;
__CFRunLoopRemoveAllSources(rl, modeName);
}
static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
CFRunLoopRemoveSource(rl, rls, modeName);
}
static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL != set) {
CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
CFRelease(set);
}
} else {
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm && NULL != rlm->_sources0) {
CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources0);
CFTypeRef context[2] = {rl, modeName};
CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
CFRelease(set);
}
if (NULL != rlm && NULL != rlm->_sources1) {
CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources1);
CFTypeRef context[2] = {rl, modeName};
CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
CFRelease(set);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rlo);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm && NULL != rlm->_observers) {
hasValue = CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
return hasValue;
}
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlo);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm && NULL == rlm->_observers) {
rlm->_observers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
}
if (NULL != rlm && !CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo)) {
Boolean inserted = false;
for (CFIndex idx = CFArrayGetCount(rlm->_observers); idx--; ) {
CFRunLoopObserverRef obs = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
if (obs->_order <= rlo->_order) {
CFArrayInsertValueAtIndex(rlm->_observers, idx + 1, rlo);
inserted = true;
break;
}
}
if (!inserted) {
CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo);
}
rlm->_observerMask |= rlo->_activities;
__CFRunLoopObserverSchedule(rlo, rl, rlm);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
CFSetRemoveValue(rl->_commonModeItems, rlo);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm && NULL != rlm->_observers) {
CFRetain(rlo);
CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo);
if (kCFNotFound != idx) {
CFArrayRemoveValueAtIndex(rlm->_observers, idx);
__CFRunLoopObserverCancel(rlo, rl, rlm);
}
CFRelease(rlo);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
if (NULL == rlt->_runLoop || rl != rlt->_runLoop) return false;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rlt);
}
} else {
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != rlm) {
if (NULL != rlm->_timers) {
CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), rlt);
hasValue = (kCFNotFound != idx);
}
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
return hasValue;
}
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlt);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlt};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm) {
if (NULL == rlm->_timers) {
CFArrayCallBacks cb = kCFTypeArrayCallBacks;
cb.equal = NULL;
rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
}
}
if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
__CFRunLoopTimerLock(rlt);
if (NULL == rlt->_runLoop) {
rlt->_runLoop = rl;
} else if (rl != rlt->_runLoop) {
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
return;
}
CFSetAddValue(rlt->_rlModes, rlm->_name);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
__CFRepositionTimerInMode(rlm, rlt, false);
__CFRunLoopTimerFireTSRUnlock();
if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
}
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
CFSetRemoveValue(rl->_commonModeItems, rlt);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlt};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
}
} else {
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
CFIndex idx = kCFNotFound;
CFMutableArrayRef timerList = NULL;
if (NULL != rlm) {
timerList = rlm->_timers;
if (NULL != timerList) {
idx = CFArrayGetFirstIndexOfValue(timerList, CFRangeMake(0, CFArrayGetCount(timerList)), rlt);
}
}
if (kCFNotFound != idx) {
__CFRunLoopTimerLock(rlt);
CFSetRemoveValue(rlt->_rlModes, rlm->_name);
if (0 == CFSetGetCount(rlt->_rlModes)) {
rlt->_runLoop = NULL;
}
__CFRunLoopTimerUnlock(rlt);
CFArrayRemoveValueAtIndex(timerList, idx);
__CFArmNextTimerInMode(rlm, rl);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) {
CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1;
CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2;
if (rls1 == rls2) return true;
if (__CFIsValid(rls1) != __CFIsValid(rls2)) return false;
if (rls1->_order != rls2->_order) return false;
if (rls1->_context.version0.version != rls2->_context.version0.version) return false;
if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false;
if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false;
if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false;
if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false;
if (rls1->_context.version0.equal)
return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info);
return (rls1->_context.version0.info == rls2->_context.version0.info);
}
static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
if (rls->_context.version0.hash)
return rls->_context.version0.hash(rls->_context.version0.info);
return (CFHashCode)rls->_context.version0.info;
}
static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
CFStringRef result;
CFStringRef contextDesc = NULL;
if (NULL != rls->_context.version0.copyDescription) {
contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info);
}
if (NULL == contextDesc) {
void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL);
#if DEPLOYMENT_TARGET_WINDOWS
contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls->_context.version0.version, rls->_context.version0.info, addr);
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
Dl_info info;
const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr);
#endif
}
#if DEPLOYMENT_TARGET_WINDOWS
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);
#else
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);
#endif
CFRelease(contextDesc);
return result;
}
static void __CFRunLoopSourceDeallocate(CFTypeRef cf) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf;
CFRunLoopSourceInvalidate(rls);
if (rls->_context.version0.release) {
rls->_context.version0.release(rls->_context.version0.info);
}
pthread_mutex_destroy(&rls->_lock);
memset((char *)cf + sizeof(CFRuntimeBase), 0, sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase));
}
static const CFRuntimeClass __CFRunLoopSourceClass = {
_kCFRuntimeScannedObject,
"CFRunLoopSource",
NULL, NULL, __CFRunLoopSourceDeallocate,
__CFRunLoopSourceEqual,
__CFRunLoopSourceHash,
NULL, __CFRunLoopSourceCopyDescription
};
CFTypeID CFRunLoopSourceGetTypeID(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{ __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass); });
return __kCFRunLoopSourceTypeID;
}
CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
CHECK_FOR_FORK();
CFRunLoopSourceRef memory;
uint32_t size;
if (NULL == context) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, CFRunLoopSourceGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopSourceUnsetSignaled(memory);
__CFRunLoopLockInit(&memory->_lock);
memory->_bits = 0;
memory->_order = order;
memory->_runLoops = NULL;
size = 0;
switch (context->version) {
case 0:
size = sizeof(CFRunLoopSourceContext);
break;
case 1:
size = sizeof(CFRunLoopSourceContext1);
break;
}
objc_memmove_collectable(&memory->_context, context, size);
if (context->retain) {
memory->_context.version0.info = (void *)context->retain(context->info);
}
return memory;
}
CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
CHECK_FOR_FORK();
__CFGenericValidateType(rls, CFRunLoopSourceGetTypeID());
return rls->_order;
}
static void __CFRunLoopSourceWakeUpLoop(const void *value, void *context) {
CFRunLoopWakeUp((CFRunLoopRef)value);
}
static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
CFRunLoopRef rl = (CFRunLoopRef)value;
CFTypeRef *params = (CFTypeRef *)context;
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
CFIndex idx;
if (rl == params[1]) return;
__CFRunLoopLock(rl);
CFArrayRef array = CFRunLoopCopyAllModes(rl);
for (idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
CFRunLoopRemoveSource(rl, rls, modeName);
}
CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
__CFRunLoopUnlock(rl);
CFRelease(array);
params[1] = rl;
}
void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
CHECK_FOR_FORK();
__CFGenericValidateType(rls, CFRunLoopSourceGetTypeID());
__CFRunLoopSourceLock(rls);
CFRetain(rls);
if (__CFIsValid(rls)) {
CFBagRef rloops = rls->_runLoops;
__CFUnsetValid(rls);
__CFRunLoopSourceUnsetSignaled(rls);
if (NULL != rloops) {
rls->_runLoops = NULL; __CFRunLoopSourceUnlock(rls);
CFTypeRef params[2] = {rls, NULL};
CFBagApplyFunction(rloops, (__CFRunLoopSourceRemoveFromRunLoop), params);
CFRelease(rloops);
__CFRunLoopSourceLock(rls);
}
}
__CFRunLoopSourceUnlock(rls);
CFRelease(rls);
}
Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
CHECK_FOR_FORK();
__CFGenericValidateType(rls, CFRunLoopSourceGetTypeID());
return __CFIsValid(rls);
}
void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
CHECK_FOR_FORK();
__CFGenericValidateType(rls, CFRunLoopSourceGetTypeID());
CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__);
CFIndex size = 0;
switch (context->version) {
case 0:
size = sizeof(CFRunLoopSourceContext);
break;
case 1:
size = sizeof(CFRunLoopSourceContext1);
break;
}
memmove(context, &rls->_context, size);
}
void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
CHECK_FOR_FORK();
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceSetSignaled(rls);
}
__CFRunLoopSourceUnlock(rls);
}
Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) {
CHECK_FOR_FORK();
__CFRunLoopSourceLock(rls);
Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false;
__CFRunLoopSourceUnlock(rls);
return ret;
}
CF_PRIVATE void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) {
CFBagRef loops = NULL;
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls) && NULL != rls->_runLoops) {
loops = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops);
}
__CFRunLoopSourceUnlock(rls);
if (loops) {
CFBagApplyFunction(loops, __CFRunLoopSourceWakeUpLoop, NULL);
CFRelease(loops);
}
}
static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
CFStringRef result;
CFStringRef contextDesc = NULL;
if (NULL != rlo->_context.copyDescription) {
contextDesc = rlo->_context.copyDescription(rlo->_context.info);
}
if (!contextDesc) {
contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
}
#if DEPLOYMENT_TARGET_WINDOWS
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);
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
void *addr = rlo->_callout;
Dl_info info;
const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
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);
#endif
CFRelease(contextDesc);
return result;
}
static void __CFRunLoopObserverDeallocate(CFTypeRef cf) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
CFRunLoopObserverInvalidate(rlo);
pthread_mutex_destroy(&rlo->_lock);
}
static const CFRuntimeClass __CFRunLoopObserverClass = {
0,
"CFRunLoopObserver",
NULL, NULL, __CFRunLoopObserverDeallocate,
NULL,
NULL,
NULL, __CFRunLoopObserverCopyDescription
};
CFTypeID CFRunLoopObserverGetTypeID(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{ __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass); });
return __kCFRunLoopObserverTypeID;
}
CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
CHECK_FOR_FORK();
CFRunLoopObserverRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, CFRunLoopObserverGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopObserverUnsetFiring(memory);
if (repeats) {
__CFRunLoopObserverSetRepeats(memory);
} else {
__CFRunLoopObserverUnsetRepeats(memory);
}
__CFRunLoopLockInit(&memory->_lock);
memory->_runLoop = NULL;
memory->_rlCount = 0;
memory->_activities = activities;
memory->_order = order;
memory->_callout = callout;
if (context) {
if (context->retain) {
memory->_context.info = (void *)context->retain(context->info);
} else {
memory->_context.info = context->info;
}
memory->_context.retain = context->retain;
memory->_context.release = context->release;
memory->_context.copyDescription = context->copyDescription;
} else {
memory->_context.info = 0;
memory->_context.retain = 0;
memory->_context.release = 0;
memory->_context.copyDescription = 0;
}
return memory;
}
static void _runLoopObserverWithBlockContext(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *opaqueBlock) {
typedef void (^observer_block_t) (CFRunLoopObserverRef observer, CFRunLoopActivity activity);
observer_block_t block = (observer_block_t)opaqueBlock;
block(observer, activity);
}
CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order,
void (^block) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) {
CFRunLoopObserverContext blockContext;
blockContext.version = 0;
blockContext.info = (void *)block;
blockContext.retain = (const void *(*)(const void *info))_Block_copy;
blockContext.release = (void (*)(const void *info))_Block_release;
blockContext.copyDescription = NULL;
return CFRunLoopObserverCreate(allocator, activities, repeats, order, _runLoopObserverWithBlockContext, &blockContext);
}
CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlo, CFRunLoopObserverGetTypeID());
return rlo->_activities;
}
CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlo, CFRunLoopObserverGetTypeID());
return rlo->_order;
}
Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlo, CFRunLoopObserverGetTypeID());
return __CFRunLoopObserverRepeats(rlo);
}
void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlo, CFRunLoopObserverGetTypeID());
__CFRunLoopObserverLock(rlo);
CFRetain(rlo);
if (__CFIsValid(rlo)) {
CFRunLoopRef rl = rlo->_runLoop;
void *info = rlo->_context.info;
rlo->_context.info = NULL;
__CFUnsetValid(rlo);
if (NULL != rl) {
CFRetain(rl);
__CFRunLoopObserverUnlock(rlo);
__CFRunLoopLock(rl);
CFArrayRef array = CFRunLoopCopyAllModes(rl);
for (CFIndex idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
CFRunLoopRemoveObserver(rl, rlo, modeName);
}
CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
__CFRunLoopUnlock(rl);
CFRelease(array);
CFRelease(rl);
__CFRunLoopObserverLock(rlo);
}
if (NULL != rlo->_context.release) {
rlo->_context.release(info);
}
}
__CFRunLoopObserverUnlock(rlo);
CFRelease(rlo);
}
Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
CHECK_FOR_FORK();
return __CFIsValid(rlo);
}
void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlo, CFRunLoopObserverGetTypeID());
CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
*context = rlo->_context;
}
#pragma mark -
#pragma mark CFRunLoopTimer
static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
CFStringRef contextDesc = NULL;
if (NULL != rlt->_context.copyDescription) {
contextDesc = rlt->_context.copyDescription(rlt->_context.info);
}
if (NULL == contextDesc) {
contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
}
void *addr = (void *)rlt->_callout;
char libraryName[2048];
char functionName[2048];
void *functionPtr = NULL;
libraryName[0] = '?'; libraryName[1] = '\0';
functionName[0] = '?'; functionName[1] = '\0';
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL,
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 = %@}"),
cf,
CFGetAllocator(rlt),
__CFIsValid(rlt) ? "Yes" : "No",
__CFRunLoopTimerIsFiring(rlt) ? "Yes" : "No",
rlt->_interval,
rlt->_tolerance,
rlt->_nextFireDate,
rlt->_nextFireDate - CFAbsoluteTimeGetCurrent(),
rlt->_fireTSR,
functionName,
addr,
functionPtr,
libraryName,
contextDesc);
CFRelease(contextDesc);
return result;
}
static void __CFRunLoopTimerDeallocate(CFTypeRef cf) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
__CFRunLoopTimerSetDeallocating(rlt);
CFRunLoopTimerInvalidate(rlt);
CFRelease(rlt->_rlModes);
rlt->_rlModes = NULL;
pthread_mutex_destroy(&rlt->_lock);
}
static const CFRuntimeClass __CFRunLoopTimerClass = {
0,
"CFRunLoopTimer",
NULL, NULL, __CFRunLoopTimerDeallocate,
NULL, NULL,
NULL, __CFRunLoopTimerCopyDescription
};
CFTypeID CFRunLoopTimerGetTypeID(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{ __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass); });
return __kCFRunLoopTimerTypeID;
}
CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
CHECK_FOR_FORK();
if (isnan(interval)) {
CRSetCrashLogMessage("NaN was used as an interval for a CFRunLoopTimer");
HALT;
}
CFRunLoopTimerRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, CFRunLoopTimerGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopTimerUnsetFiring(memory);
__CFRunLoopLockInit(&memory->_lock);
memory->_runLoop = NULL;
memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
memory->_order = order;
if (interval < 0.0) interval = 0.0;
memory->_interval = interval;
memory->_tolerance = 0.0;
if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
memory->_nextFireDate = fireDate;
memory->_fireTSR = 0ULL;
uint64_t now2 = mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
if (fireDate < now1) {
memory->_fireTSR = now2;
} else if (TIMER_INTERVAL_LIMIT < fireDate - now1) {
memory->_fireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
} else {
memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
}
memory->_callout = callout;
if (NULL != context) {
if (context->retain) {
memory->_context.info = (void *)context->retain(context->info);
} else {
memory->_context.info = context->info;
}
memory->_context.retain = context->retain;
memory->_context.release = context->release;
memory->_context.copyDescription = context->copyDescription;
} else {
memory->_context.info = 0;
memory->_context.retain = 0;
memory->_context.release = 0;
memory->_context.copyDescription = 0;
}
return memory;
}
static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer, void *opaqueBlock) {
typedef void (^timer_block_t) (CFRunLoopTimerRef timer);
timer_block_t block = (timer_block_t)opaqueBlock;
block(timer);
}
CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order,
void (^block) (CFRunLoopTimerRef timer)) {
CFRunLoopTimerContext blockContext;
blockContext.version = 0;
blockContext.info = (void *)block;
blockContext.retain = (const void *(*)(const void *info))_Block_copy;
blockContext.release = (void (*)(const void *info))_Block_release;
blockContext.copyDescription = NULL;
return CFRunLoopTimerCreate(allocator, fireDate, interval, flags, order, _runLoopTimerWithBlockContext, &blockContext);
}
CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFAbsoluteTime, (NSTimer *)rlt, _cffireTime);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
CFAbsoluteTime at = 0.0;
__CFRunLoopTimerLock(rlt);
__CFRunLoopTimerFireTSRLock();
if (__CFIsValid(rlt)) {
at = rlt->_nextFireDate;
}
__CFRunLoopTimerFireTSRUnlock();
__CFRunLoopTimerUnlock(rlt);
return at;
}
void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
CHECK_FOR_FORK();
if (!__CFIsValid(rlt)) return;
if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
uint64_t nextFireTSR = 0ULL;
uint64_t now2 = mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
if (fireDate < now1) {
nextFireTSR = now2;
} else if (TIMER_INTERVAL_LIMIT < fireDate - now1) {
nextFireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
} else {
nextFireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
}
__CFRunLoopTimerLock(rlt);
if (NULL != rlt->_runLoop) {
CFIndex cnt = CFSetGetCount(rlt->_rlModes);
STACK_BUFFER_DECL(CFTypeRef, modes, cnt);
CFSetGetValues(rlt->_rlModes, (const void **)modes);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRetain(modes[idx]);
}
CFRunLoopRef rl = (CFRunLoopRef)CFRetain(rlt->_runLoop);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopLock(rl);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFStringRef name = (CFStringRef)modes[idx];
modes[idx] = __CFRunLoopFindMode(rl, name, false);
CFRelease(name);
}
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = fireDate;
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx];
if (rlm) {
__CFRepositionTimerInMode(rlm, rlt, true);
}
}
__CFRunLoopTimerFireTSRUnlock();
for (CFIndex idx = 0; idx < cnt; idx++) {
__CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]);
}
__CFRunLoopUnlock(rl);
if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
CFRelease(rl);
} else {
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = fireDate;
__CFRunLoopTimerFireTSRUnlock();
__CFRunLoopTimerUnlock(rlt);
}
}
CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFTimeInterval, (NSTimer *)rlt, timeInterval);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
return rlt->_interval;
}
Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
return (0.0 < rlt->_interval);
}
CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
return rlt->_order;
}
void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), void, (NSTimer *)rlt, invalidate);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
__CFRunLoopTimerLock(rlt);
if (!__CFRunLoopTimerIsDeallocating(rlt)) {
CFRetain(rlt);
}
if (__CFIsValid(rlt)) {
CFRunLoopRef rl = rlt->_runLoop;
void *info = rlt->_context.info;
rlt->_context.info = NULL;
__CFUnsetValid(rlt);
if (NULL != rl) {
CFIndex cnt = CFSetGetCount(rlt->_rlModes);
STACK_BUFFER_DECL(CFStringRef, modes, cnt);
CFSetGetValues(rlt->_rlModes, (const void **)modes);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRetain(modes[idx]);
}
CFRetain(rl);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopLock(rl);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopRemoveTimer(rl, rlt, modes[idx]);
}
CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
__CFRunLoopUnlock(rl);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRelease(modes[idx]);
}
CFRelease(rl);
__CFRunLoopTimerLock(rlt);
}
if (NULL != rlt->_context.release) {
rlt->_context.release(info);
}
}
__CFRunLoopTimerUnlock(rlt);
if (!__CFRunLoopTimerIsDeallocating(rlt)) {
CFRelease(rlt);
}
}
Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), Boolean, (NSTimer *)rlt, isValid);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
return __CFIsValid(rlt);
}
void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
CHECK_FOR_FORK();
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
*context = rlt->_context;
}
CFTimeInterval CFRunLoopTimerGetTolerance(CFRunLoopTimerRef rlt) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), CFTimeInterval, (NSTimer *)rlt, tolerance);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
return rlt->_tolerance;
#else
return 0.0;
#endif
}
void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef rlt, CFTimeInterval tolerance) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
CHECK_FOR_FORK();
CF_OBJC_FUNCDISPATCHV(CFRunLoopTimerGetTypeID(), void, (NSTimer *)rlt, setTolerance:tolerance);
__CFGenericValidateType(rlt, CFRunLoopTimerGetTypeID());
if (rlt->_interval > 0) {
rlt->_tolerance = MIN(tolerance, rlt->_interval / 2);
} else {
if (tolerance < 0) tolerance = 0.0;
rlt->_tolerance = tolerance;
}
#endif
}