#include <CoreFoundation/CFRunLoop.h>
#include <CoreFoundation/CFSet.h>
#include <CoreFoundation/CFBag.h>
#include "CFRunLoopPriv.h"
#include "CFInternal.h"
#include <math.h>
#include <stdio.h>
#include <limits.h>
#if defined(__MACH__)
#include <mach/mach.h>
#include <mach/clock_types.h>
#include <mach/clock.h>
#else
#if !defined(__MINGW32__) && !defined(__CYGWIN__)
#undef __STDC__
#endif
#include <windows.h>
#include <process.h>
#if !defined(__MINGW32__) && !defined(__CYGWIN__)
#define __STDC__
#endif
#endif
extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey);
#if defined(__MACH__)
typedef mach_port_t __CFPort;
#define CFPORT_NULL MACH_PORT_NULL
typedef mach_port_t __CFPortSet;
static __CFPort __CFPortAllocate(void) {
__CFPort result;
kern_return_t ret;
ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result);
if (KERN_SUCCESS == ret) {
ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND);
}
if (KERN_SUCCESS == 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);
}
return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
}
CF_INLINE void __CFPortFree(__CFPort port) {
mach_port_destroy(mach_task_self(), port);
}
CF_INLINE __CFPortSet __CFPortSetAllocate(void) {
__CFPortSet result;
kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result);
return (KERN_SUCCESS == ret) ? result : CFPORT_NULL;
}
CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet);
return (KERN_SUCCESS == ret);
}
CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet);
return (KERN_SUCCESS == ret);
}
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 defined(__WIN32__)
typedef HANDLE __CFPort;
#define CFPORT_NULL NULL
typedef struct ___CFPortSet {
uint16_t used;
uint16_t size;
HANDLE *handles;
CFSpinLock_t lock; } *__CFPortSet;
CF_INLINE __CFPort __CFPortAllocate(void) {
return CreateEvent(NULL, true, false, NULL);
}
CF_INLINE void __CFPortFree(__CFPort port) {
CloseHandle(port);
}
static __CFPortSet __CFPortSetAllocate(void) {
__CFPortSet result = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0);
result->used = 0;
result->size = 4;
result->handles = CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0);
result->lock = 0;
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) {
__CFSpinLock(&(portSet->lock));
__CFPort *result = portBuf;
if (bufSize > portSet->used)
result = CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0);
memmove(result, portSet->handles, portSet->used * sizeof(HANDLE));
*portsUsed = portSet->used;
__CFSpinUnlock(&(portSet->lock));
return result;
}
static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) {
__CFSpinLock(&(portSet->lock));
if (portSet->used >= portSet->size) {
portSet->size += 4;
portSet->handles = CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0);
}
if (portSet->used >= MAXIMUM_WAIT_OBJECTS)
CFLog(0, 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;
__CFSpinUnlock(&(portSet->lock));
return true;
}
static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) {
int i, j;
__CFSpinLock(&(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--;
__CFSpinUnlock(&(portSet->lock));
return true;
}
}
__CFSpinUnlock(&(portSet->lock));
return false;
}
#endif
#if defined(__MACH__)
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(int64_t x) {
AbsoluteTime a;
a.hi = x >> 32;
a.lo = x & (int64_t)0xFFFFFFFF;
return a;
}
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;
}
#endif
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;
CFSpinLock_t _lock;
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources;
CFMutableSetRef _observers;
CFMutableSetRef _timers;
CFMutableArrayRef _submodes; __CFPortSet _portSet;
#if defined(__MACH__)
int _kq;
#endif
#if defined(__WIN32__)
DWORD _msgQMask;
#endif
};
static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm);
CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
__CFSpinLock(&(rlm->_lock));
}
CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) {
__CFSpinUnlock(&(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 = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, rlm->_lock ? "true" : "false");
#if defined(__MACH__)
CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet);
#endif
#if defined(__WIN32__)
CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p,"), rlm->_msgQMask);
#endif
CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers);
return result;
}
static void __CFRunLoopModeDeallocate(CFTypeRef cf) {
CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
if (NULL != rlm->_sources) CFRelease(rlm->_sources);
if (NULL != rlm->_observers) CFRelease(rlm->_observers);
if (NULL != rlm->_timers) CFRelease(rlm->_timers);
if (NULL != rlm->_submodes) CFRelease(rlm->_submodes);
CFRelease(rlm->_name);
__CFPortSetFree(rlm->_portSet);
#if defined(__MACH__)
if (-1 != rlm->_kq) close(rlm->_kq);
#endif
}
struct __CFRunLoop {
CFRuntimeBase _base;
CFSpinLock_t _lock;
__CFPort _wakeUpPort; volatile CFIndex *_stopped;
CFMutableSetRef _commonModes;
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
};
CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
return (rl->_stopped && rl->_stopped[2]) ? true : false;
}
CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
if (rl->_stopped) rl->_stopped[2] = 0x53544F50; }
CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
if (rl->_stopped) rl->_stopped[2] = 0x0;
}
CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 1, 1);
}
CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 1);
}
CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 0);
}
CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 2, 2);
}
CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) {
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 2, 2, 1);
}
CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) {
__CFSpinLock(&(((CFRunLoopRef)rl)->_lock));
}
CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) {
__CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock));
}
static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) {
CFRunLoopRef rl = (CFRunLoopRef)cf;
CFMutableStringRef result;
result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), rl->_lock ? "true" : "false", rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)"));
CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes);
return result;
}
static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
CFRunLoopModeRef rlm;
struct __CFRunLoopMode srlm;
srlm._base._isa = __CFISAForTypeID(__kCFRunLoopModeTypeID);
srlm._base._info = 0;
_CFRuntimeSetInstanceTypeID(&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(CFGetAllocator(rl), __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
if (NULL == rlm) {
return NULL;
}
rlm->_lock = 0;
rlm->_name = CFStringCreateCopy(CFGetAllocator(rlm), modeName);
rlm->_stopped = false;
rlm->_sources = NULL;
rlm->_observers = NULL;
rlm->_timers = NULL;
rlm->_submodes = NULL;
rlm->_portSet = __CFPortSetAllocate();
if (CFPORT_NULL == rlm->_portSet) HALT;
if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT;
#if defined(__MACH__)
rlm->_kq = -1;
#endif
#if defined(__WIN32__)
rlm->_msgQMask = 0;
#endif
CFSetAddValue(rl->_modes, rlm);
CFRelease(rlm);
__CFRunLoopModeLock(rlm);
return rlm;
}
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
if (NULL == rlm) return true;
#if defined(__WIN32__)
if (0 != rlm->_msgQMask) return false;
#endif
if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false;
if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false;
if (NULL != rlm->_submodes) {
CFIndex idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
Boolean subIsEmpty;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm) : true;
if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm);
if (!subIsEmpty) return false;
}
}
return true;
}
#if defined(__WIN32__)
DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) {
CFRunLoopModeRef rlm;
DWORD result = 0;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (rlm) {
result = rlm->_msgQMask;
__CFRunLoopModeUnlock(rlm);
}
__CFRunLoopUnlock(rl);
return result;
}
void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) {
CFRunLoopModeRef rlm;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, true);
rlm->_msgQMask = mask;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
}
#endif
CF_INLINE Boolean __CFIsValid(const void *cf) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 3);
}
CF_INLINE void __CFSetValid(void *cf) {
__CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 1);
}
CF_INLINE void __CFUnsetValid(void *cf) {
__CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 0);
}
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
CFSpinLock_t _lock;
CFIndex _order;
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0;
CFRunLoopSourceContext1 version1;
CFRunLoopSourceContext2 version2;
} _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) {
__CFSpinLock(&(rls->_lock));
}
CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) {
__CFSpinUnlock(&(rls->_lock));
}
static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
__CFRunLoopSourceLock(rls);
if (NULL == rls->_runLoops) {
rls->_runLoops = CFBagCreateMutable(CF_USING_COLLECTABLE_MEMORY ? kCFAllocatorMallocZone : CFGetAllocator(rls), 0, NULL);
}
CFBagAddValue(rls->_runLoops, rl);
__CFRunLoopSourceUnlock(rls); if (0 == rls->_context.version0.version) {
if (NULL != rls->_context.version0.schedule) {
rls->_context.version0.schedule(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) {
__CFPortSetInsert(port, rlm->_portSet);
}
} else if (2 == rls->_context.version0.version) {
#if defined(__MACH__)
if (-1 == rlm->_kq) {
rlm->_kq = kqueue_from_portset_np(rlm->_portSet);
}
rls->_context.version2.event.flags |= EV_ADD;
int ret = kevent(rlm->_kq, &(rls->_context.version2.event), 1, NULL, 0, NULL);
rls->_context.version2.event.flags &= ~EV_ADD;
if (ret < 0) {
CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #1"));
}
#endif
}
}
static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
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);
}
} else if (2 == rls->_context.version0.version) {
#if defined(__MACH__)
if (-1 == rlm->_kq) {
rlm->_kq = kqueue_from_portset_np(rlm->_portSet);
}
rls->_context.version2.event.flags |= EV_DELETE;
int ret = kevent(rlm->_kq, &(rls->_context.version2.event), 1, NULL, 0, NULL);
rls->_context.version2.event.flags &= ~EV_DELETE;
if (ret < 0) {
CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #2"));
}
#endif
}
__CFRunLoopSourceLock(rls);
if (NULL != rls->_runLoops) {
CFBagRemoveValue(rls->_runLoops, rl);
}
__CFRunLoopSourceUnlock(rls);
}
struct __CFRunLoopObserver {
CFRuntimeBase _base;
CFSpinLock_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)->_info, 0, 0);
}
CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 1);
}
CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 0);
}
CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_info, 1, 1);
}
CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 1);
}
CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 0);
}
CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) {
__CFSpinLock(&(rlo->_lock));
}
CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) {
__CFSpinUnlock(&(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);
}
struct __CFRunLoopTimer {
CFRuntimeBase _base;
CFSpinLock_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
#if defined(__MACH__)
mach_port_name_t _port;
#endif
CFIndex _order;
int64_t _fireTSR;
int64_t _intervalTSR;
CFRunLoopTimerCallBack _callout;
CFRunLoopTimerContext _context;
};
CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_info, 0, 0);
}
CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 1);
}
CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 0);
}
CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_info, 1, 1);
}
CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 1, 1, 1);
}
CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) {
__CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 1, 1, 0);
}
CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) {
__CFSpinLock(&(rlt->_lock));
}
CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) {
__CFSpinUnlock(&(rlt->_lock));
}
static CFSpinLock_t __CFRLTFireTSRLock = 0;
CF_INLINE void __CFRunLoopTimerFireTSRLock(void) {
__CFSpinLock(&__CFRLTFireTSRLock);
}
CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) {
__CFSpinUnlock(&__CFRLTFireTSRLock);
}
#if defined(__MACH__)
static CFMutableDictionaryRef __CFRLTPortMap = NULL;
static CFSpinLock_t __CFRLTPortMapLock = 0;
CF_INLINE void __CFRunLoopTimerPortMapLock(void) {
__CFSpinLock(&__CFRLTPortMapLock);
}
CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) {
__CFSpinUnlock(&__CFRLTPortMapLock);
}
#endif
static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
#if defined(__MACH__)
__CFRunLoopTimerLock(rlt);
if (0 == rlt->_rlCount) {
rlt->_runLoop = rl;
if (MACH_PORT_NULL == rlt->_port) {
rlt->_port = mk_timer_create();
}
__CFRunLoopTimerPortMapLock();
if (NULL == __CFRLTPortMap) {
__CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
}
CFDictionarySetValue(__CFRLTPortMap, (void *)rlt->_port, rlt);
__CFRunLoopTimerPortMapUnlock();
}
rlt->_rlCount++;
mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet);
mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
__CFRunLoopTimerUnlock(rlt);
#endif
}
static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
#if defined(__MACH__)
__CFRunLoopTimerLock(rlt);
__CFPortSetRemove(rlt->_port, rlm->_portSet);
rlt->_rlCount--;
if (0 == rlt->_rlCount) {
__CFRunLoopTimerPortMapLock();
if (NULL != __CFRLTPortMap) {
CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port);
}
__CFRunLoopTimerPortMapUnlock();
rlt->_runLoop = NULL;
mk_timer_cancel(rlt->_port, NULL);
}
__CFRunLoopTimerUnlock(rlt);
#endif
}
static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt, CFRunLoopRef rl) {
#if defined(__MACH__)
mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR));
#endif
}
#if defined(__WIN32__)
struct _collectTimersContext {
CFMutableArrayRef results;
int64_t cutoffTSR;
};
static void __CFRunLoopCollectTimers(const void *value, void *ctx) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
struct _collectTimersContext *context = ctx;
if (rlt->_fireTSR <= context->cutoffTSR) {
if (NULL == context->results)
context->results = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(context->results, rlt);
}
}
static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl, CFRunLoopModeRef rlm, struct _collectTimersContext *ctxt) {
if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
__CFRunLoopTimerFireTSRLock();
CFSetApplyFunction(rlm->_timers, __CFRunLoopCollectTimers, ctxt);
__CFRunLoopTimerFireTSRUnlock();
}
if (NULL != rlm->_submodes) {
CFIndex idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != subrlm) {
__CFRunLoopTimersToFireRecursive(rl, subrlm, ctxt);
__CFRunLoopModeUnlock(subrlm);
}
}
}
}
static CFArrayRef __CFRunLoopTimersToFire(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
struct _collectTimersContext ctxt = {NULL, __CFReadTSR()};
__CFRunLoopTimersToFireRecursive(rl, rlm, &ctxt);
return ctxt.results;
}
#endif
CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode")
CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes")
struct _findsource {
__CFPort port;
CFRunLoopSourceRef result;
};
static void __CFRunLoopFindSource(const void *value, void *ctx) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
struct _findsource *context = (struct _findsource *)ctx;
__CFPort port;
if (NULL != context->result) return;
if (1 != rls->_context.version0.version) return;
__CFRunLoopSourceLock(rls);
port = rls->_context.version1.getPort(rls->_context.version1.info);
if (port == context->port) {
context->result = rls;
}
__CFRunLoopSourceUnlock(rls);
}
static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) {
struct _findsource context = {port, NULL};
if (NULL != rlm->_sources) {
CFSetApplyFunction(rlm->_sources, (__CFRunLoopFindSource), &context);
}
if (NULL == context.result && NULL != rlm->_submodes) {
CFIndex idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
CFRunLoopSourceRef source = NULL;
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != subrlm) {
source = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port);
__CFRunLoopModeUnlock(subrlm);
}
if (NULL != source) {
context.result = source;
break;
}
}
}
return context.result;
}
#if defined(__MACH__)
static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) {
CFRunLoopTimerRef result = NULL;
__CFRunLoopTimerPortMapLock();
if (NULL != __CFRLTPortMap) {
result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)port);
}
__CFRunLoopTimerPortMapUnlock();
return result;
}
#endif
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->_sources) return;
cnt = CFSetGetCount(rlm->_sources);
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
CFSetGetValues(rlm->_sources, list);
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
CFSetRemoveAllValues(rlm->_sources);
for (idx = 0; idx < cnt; idx++) {
__CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm);
CFRelease(list[idx]);
}
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 = CFSetGetCount(rlm->_observers);
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
CFSetGetValues(rlm->_observers, list);
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
CFSetRemoveAllValues(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;
CFRunLoopRef rl = (CFRunLoopRef)context;
CFIndex idx, cnt;
const void **list, *buffer[256];
if (NULL == rlm->_timers) return;
cnt = CFSetGetCount(rlm->_timers);
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
CFSetGetValues(rlm->_timers, list);
for (idx = 0; idx < cnt; idx++) {
CFRetain(list[idx]);
}
CFSetRemoveAllValues(rlm->_timers);
for (idx = 0; idx < cnt; idx++) {
__CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm);
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
static void __CFRunLoopDeallocate(CFTypeRef cf) {
CFRunLoopRef rl = (CFRunLoopRef)cf;
__CFRunLoopSetDeallocating(rl);
if (NULL != rl->_modes) {
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
}
__CFRunLoopLock(rl);
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;
__CFRunLoopUnlock(rl);
}
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
};
__private_extern__ void __CFRunLoopInitialize(void) {
__kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);
__kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass);
}
CFTypeID CFRunLoopGetTypeID(void) {
return __kCFRunLoopTypeID;
}
static CFRunLoopRef __CFRunLoopCreate(void) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL);
if (NULL == loop) {
return NULL;
}
loop->_stopped = NULL;
loop->_lock = 0;
loop->_wakeUpPort = __CFPortAllocate();
if (CFPORT_NULL == loop->_wakeUpPort) HALT;
loop->_commonModes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
loop->_commonModeItems = NULL;
loop->_currentMode = NULL;
loop->_modes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks);
_CFSetSetCapacity(loop->_modes, 10);
rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true);
if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
return loop;
}
#if defined(__MACH__)
static CFRunLoopRef mainLoop = NULL;
static int mainLoopPid = 0;
static CFSpinLock_t mainLoopLock = 0;
CFRunLoopRef CFRunLoopGetMain(void) {
__CFSpinLock(&mainLoopLock);
if (mainLoopPid != getpid()) {
mainLoop = NULL;
}
if (!mainLoop) {
mainLoop = __CFRunLoopCreate();
mainLoopPid = getpid();
}
__CFSpinUnlock(&mainLoopLock);
return mainLoop;
}
static void _CFRunLoopSetMain(CFRunLoopRef rl) {
if (rl != mainLoop) {
if (rl) CFRetain(rl);
mainLoop = rl;
}
}
#endif
CFRunLoopRef CFRunLoopGetCurrent(void) {
#if defined(__MACH__)
if (pthread_main_np()) {
return CFRunLoopGetMain();
}
#endif
CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop;
int currentLoopPid = __CFGetThreadSpecificData_inline()->_runLoop_pid;
if (currentLoopPid != getpid()) {
currentLoop = NULL;
}
if (!currentLoop) {
currentLoop = __CFRunLoopCreate();
__CFGetThreadSpecificData_inline()->_runLoop = currentLoop;
__CFGetThreadSpecificData_inline()->_runLoop_pid = getpid();
}
return currentLoop;
}
void _CFRunLoopSetCurrent(CFRunLoopRef rl) {
#if defined(__MACH__)
if (pthread_main_np()) {
return _CFRunLoopSetMain(rl);
}
#endif
CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop;
if (rl != currentLoop) {
if (rl) CFRetain(rl);
__CFGetThreadSpecificData_inline()->_runLoop = rl;
__CFGetThreadSpecificData_inline()->_runLoop_pid = getpid();
}
}
CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) {
CFStringRef result = NULL;
__CFRunLoopLock(rl);
if (NULL != rl->_currentMode) {
result = 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) {
CFMutableArrayRef array;
__CFRunLoopLock(rl);
array = CFArrayCreateMutable(kCFAllocatorDefault, 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) == __kCFRunLoopSourceTypeID) {
CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
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) == __kCFRunLoopSourceTypeID) {
CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
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) == __kCFRunLoopSourceTypeID) {
CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) {
CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
} else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) {
CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
}
}
void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) {
if (__CFRunLoopIsDeallocating(rl)) return;
__CFRunLoopLock(rl);
if (!CFSetContainsValue(rl->_commonModes, modeName)) {
CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL;
CFSetAddValue(rl->_commonModes, modeName);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, modeName};
CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context);
CFRelease(set);
}
} else {
__CFRunLoopUnlock(rl);
}
}
static CFComparisonResult __CFRunLoopObserverComparator(const void *val1, const void *val2, void *context) {
CFRunLoopObserverRef o1 = (CFRunLoopObserverRef)val1;
CFRunLoopObserverRef o2 = (CFRunLoopObserverRef)val2;
if (o1->_order < o2->_order) return kCFCompareLessThan;
if (o2->_order < o1->_order) return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
struct _collectobs {
CFRunLoopActivity activity;
CFMutableArrayRef array;
};
static void __CFRunLoopCollectObservers(const void *value, void *context) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)value;
struct _collectobs *info = (struct _collectobs *)context;
if (0 != (rlo->_activities & info->activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
CFArrayAppendValue(info->array, rlo);
}
}
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) {
CFIndex idx, cnt;
CFMutableArrayRef array;
CFArrayRef submodes;
struct _collectobs info;
submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
if (NULL != rlm->_observers) {
array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rlm->_observers), &kCFTypeArrayCallBacks);
info.array = array;
info.activity = activity;
CFSetApplyFunction(rlm->_observers, (__CFRunLoopCollectObservers), &info);
cnt = CFArrayGetCount(array);
if (0 < cnt) {
__CFRunLoopModeUnlock(rlm);
CFArraySortValues(array, CFRangeMake(0, cnt), (__CFRunLoopObserverComparator), NULL);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(array, idx);
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
__CFRunLoopObserverUnlock(rlo);
__CFRunLoopObserverSetFiring(rlo);
rlo->_callout(rlo, activity, rlo->_context.info);
__CFRunLoopObserverUnsetFiring(rlo);
if (!__CFRunLoopObserverRepeats(rlo)) {
CFRunLoopObserverInvalidate(rlo);
}
} else {
__CFRunLoopObserverUnlock(rlo);
}
}
__CFRunLoopModeLock(rlm);
}
CFRelease(array);
}
if (NULL != submodes) {
__CFRunLoopModeUnlock(rlm);
for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
CFRunLoopModeRef subrlm;
__CFRunLoopLock(rl);
subrlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != subrlm) {
__CFRunLoopDoObservers(rl, subrlm, activity);
__CFRunLoopModeUnlock(subrlm);
}
}
CFRelease(submodes);
__CFRunLoopModeLock(rlm);
}
}
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) == __kCFRunLoopSourceTypeID) {
CFTypeRef oldrls = *sources;
*sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls);
CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
CFRelease(oldrls);
} else {
CFArrayAppendValue((CFMutableArrayRef)*sources, rls);
}
}
}
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) {
CFTypeRef sources = NULL;
Boolean sourceHandled = false;
CFIndex idx, cnt;
__CFRunLoopModeUnlock(rlm); __CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) {
CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources);
}
for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != subrlm) {
if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) {
CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources);
}
__CFRunLoopModeUnlock(subrlm);
}
}
__CFRunLoopUnlock(rl);
if (NULL != sources) {
__CFRunLoopModeUnlock(rlm);
if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
__CFRunLoopSourceLock(rls);
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
if (NULL != rls->_context.version0.perform) {
rls->_context.version0.perform(rls->_context.version0.info);
}
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
cnt = CFArrayGetCount(sources);
CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, idx);
__CFRunLoopSourceLock(rls);
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
if (NULL != rls->_context.version0.perform) {
rls->_context.version0.perform(rls->_context.version0.info);
}
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
if (stopAfterHandle && sourceHandled) {
break;
}
}
}
CFRelease(sources);
__CFRunLoopModeLock(rlm);
}
return sourceHandled;
}
static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls
#if defined(__MACH__)
, mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply
#endif
) {
Boolean sourceHandled = false;
CFRetain(rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
__CFRunLoopSourceUnlock(rls);
if (NULL != rls->_context.version1.perform) {
#if defined(__MACH__)
*reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info);
#else
rls->_context.version1.perform(rls->_context.version1.info);
#endif
}
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
CFRelease(rls);
__CFRunLoopModeLock(rlm);
return sourceHandled;
}
static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) {
Boolean timerHandled = false;
int64_t oldFireTSR = 0;
CFRetain(rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopTimerLock(rlt);
if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) {
__CFRunLoopTimerUnsetDidFire(rlt);
__CFRunLoopTimerSetFiring(rlt);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
oldFireTSR = rlt->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
rlt->_callout(rlt, rlt->_context.info);
__CFRunLoopTimerUnsetFiring(rlt);
timerHandled = true;
} else {
if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt);
__CFRunLoopTimerUnlock(rlt);
}
if (__CFIsValid(rlt) && timerHandled) {
if (0 == rlt->_intervalTSR) {
CFRunLoopTimerInvalidate(rlt);
} else {
int64_t currentFireTSR;
__CFRunLoopTimerFireTSRLock();
currentFireTSR = rlt->_fireTSR;
if (oldFireTSR < currentFireTSR) {
if (__CFRunLoopTimerDidFire(rlt)) {
__CFRunLoopTimerRescheduleWithAllModes(rlt, rl);
__CFRunLoopTimerUnsetDidFire(rlt);
}
} else {
if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) {
currentFireTSR = LLONG_MAX;
} else {
int64_t currentTSR = (int64_t)__CFReadTSR();
currentFireTSR = oldFireTSR;
while (currentFireTSR <= currentTSR) {
currentFireTSR += rlt->_intervalTSR;
}
}
rlt->_fireTSR = currentFireTSR;
__CFRunLoopTimerRescheduleWithAllModes(rlt, rl);
}
__CFRunLoopTimerFireTSRUnlock();
}
}
CFRelease(rlt);
__CFRunLoopModeLock(rlm);
return timerHandled;
}
CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) {
CFRunLoopModeRef rlm;
Boolean result = false;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm)) {
result = true;
}
__CFRunLoopUnlock(rl);
if (rlm) __CFRunLoopModeUnlock(rlm);
return result;
}
static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) {
CFIndex idx, cnt;
const void **list, *buffer[256];
if (NULL != rlm->_sources) {
cnt = CFSetGetCount(rlm->_sources);
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
CFSetGetValues(rlm->_sources, list);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
if (1 == rls->_context.version0.version) {
__CFPort port = rls->_context.version1.getPort(rls->_context.version1.info);
if (CFPORT_NULL != port) {
__CFPortSetInsert(port, portSet);
}
} else if (2 == rls->_context.version0.version) {
#if defined(__MACH__)
int kq = kqueue_from_portset_np(portSet);
rls->_context.version2.event.flags |= EV_ADD;
int ret = kevent(kq, &(rls->_context.version2.event), 1, NULL, 0, NULL);
rls->_context.version2.event.flags &= ~EV_ADD;
close(kq);
if (ret < 0) {
CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #3"));
}
#endif
}
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
#if defined(__MACH__)
if (NULL != rlm->_timers) {
cnt = CFSetGetCount(rlm->_timers);
list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0);
CFSetGetValues(rlm->_timers, list);
for (idx = 0; idx < cnt; idx++) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx];
if (MACH_PORT_NULL != rlt->_port) {
mach_port_insert_member(mach_task_self(), rlt->_port, portSet);
}
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
#endif
for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != subrlm) {
__CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet);
__CFRunLoopModeUnlock(subrlm);
}
}
}
static __CFPortSet _LastMainWaitSet = NULL;
int _CFRunLoopInputsReady(void) {
#if defined(__MACH__)
if (!pthread_main_np()) return true;
#endif
if (_LastMainWaitSet == MACH_PORT_NULL) return false;
mach_msg_header_t msg;
msg.msgh_size = sizeof(msg); msg.msgh_local_port = _LastMainWaitSet;
msg.msgh_remote_port = MACH_PORT_NULL;
msg.msgh_id = 0;
kern_return_t ret = mach_msg(&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, 0, msg.msgh_size, _LastMainWaitSet, 0, MACH_PORT_NULL);
return (MACH_RCV_TOO_LARGE == ret);
}
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, Boolean waitIfEmpty) {
int64_t termTSR;
#if defined(__MACH__)
mach_port_name_t timeoutPort = MACH_PORT_NULL;
Boolean timeoutPortAdded = false;
#endif
Boolean poll = false;
Boolean firstPass = true;
if (__CFRunLoopIsStopped(rl)) {
return kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
return kCFRunLoopRunStopped;
}
if (seconds <= 0.0) {
termTSR = 0;
} else if (__CFTSRToTimeInterval(LLONG_MAX) < seconds) {
termTSR = LLONG_MAX;
} else if ((uint64_t)LLONG_MAX <= __CFReadTSR() + (uint64_t)__CFTimeIntervalToTSR(seconds)) {
termTSR = LLONG_MAX;
} else {
termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds);
#if defined(__MACH__)
timeoutPort = mk_timer_create();
mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR));
#endif
}
if (seconds <= 0.0) {
poll = true;
}
if (rl == mainLoop) _LastMainWaitSet = CFPORT_NULL;
for (;;) {
__CFPortSet waitSet = CFPORT_NULL;
waitSet = CFPORT_NULL;
Boolean destroyWaitSet = false;
CFRunLoopSourceRef rls;
#if defined(__MACH__)
mach_msg_header_t *msg;
kern_return_t ret;
uint8_t buffer[1024 + 80]; #else
CFArrayRef timersToCall = NULL;
#endif
int32_t returnValue = 0;
Boolean sourceHandledThisLoop = false;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
poll = true;
}
if (!poll) {
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
}
if (NULL != rlm->_submodes) {
waitSet = __CFPortSetAllocate();
if (CFPORT_NULL == waitSet) HALT;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet);
__CFRunLoopUnlock(rl);
#if defined(__MACH__)
if (CFPORT_NULL != timeoutPort) {
__CFPortSetInsert(timeoutPort, waitSet);
}
#endif
destroyWaitSet = true;
} else {
waitSet = rlm->_portSet;
#if defined(__MACH__)
if (!timeoutPortAdded && CFPORT_NULL != timeoutPort) {
__CFPortSetInsert(timeoutPort, waitSet);
timeoutPortAdded = true;
}
#endif
}
if (rl == mainLoop) _LastMainWaitSet = waitSet;
__CFRunLoopModeUnlock(rlm);
#if defined(__MACH__)
msg = (mach_msg_header_t *)buffer;
msg->msgh_size = sizeof(buffer);
try_receive:
msg->msgh_bits = 0;
msg->msgh_local_port = waitSet;
msg->msgh_remote_port = MACH_PORT_NULL;
msg->msgh_id = 0;
ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|(poll ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL);
if (MACH_RCV_TOO_LARGE == ret) {
uint32_t newSize = round_msg(msg->msgh_size) + sizeof(mach_msg_audit_trailer_t);
if (msg == (mach_msg_header_t *)buffer) msg = NULL;
msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0);
msg->msgh_size = newSize;
goto try_receive;
} else if (MACH_RCV_TIMED_OUT == ret) {
if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
msg = NULL;
} else if (MACH_MSG_SUCCESS != ret) {
HALT;
}
#elif defined(__WIN32__)
__CFRunLoopModeUnlock(rlm);
DWORD waitResult = WAIT_TIMEOUT;
HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS];
HANDLE *handles;
uint32_t handleCount;
Boolean freeHandles;
if (destroyWaitSet) {
handles = waitSet->handles;
handleCount = waitSet->used;
freeHandles = FALSE;
} else {
handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount);
freeHandles = (handles != handleBuf);
}
if (0 == GetQueueStatus(rlm->_msgQMask)) {
DWORD timeout;
if (poll)
timeout = 0;
else {
int64_t nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm);
if (nextStop <= 0)
nextStop = termTSR;
else if (nextStop > termTSR)
nextStop = termTSR;
int64_t timeoutTSR = nextStop - __CFReadTSR();
if (timeoutTSR < 0)
timeout = 0;
else {
CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000;
if (timeoutCF > MAXDWORD)
timeout = INFINITE;
else
timeout = timeoutCF;
}
}
waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout, rlm->_msgQMask);
}
ResetEvent(rl->_wakeUpPort);
#endif
if (destroyWaitSet) {
__CFPortSetFree(waitSet);
if (rl == mainLoop) _LastMainWaitSet = NULL;
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFRunLoopUnlock(rl);
if (!poll) {
__CFRunLoopUnsetSleeping(rl);
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
}
poll = false;
__CFRunLoopModeUnlock(rlm);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFPort livePort = CFPORT_NULL;
#if defined(__MACH__)
if (NULL != msg) {
livePort = msg->msgh_local_port;
}
#elif defined(__WIN32__)
CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError());
if (waitResult == WAIT_TIMEOUT) {
} else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) {
livePort = handles[waitResult-WAIT_OBJECT_0];
} else if (waitResult == WAIT_OBJECT_0+handleCount) {
} else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) {
livePort = handles[waitResult-WAIT_ABANDONED_0];
} else {
CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult);
}
if (freeHandles)
CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles);
timersToCall = __CFRunLoopTimersToFire(rl, rlm);
#endif
if (CFPORT_NULL == livePort) {
__CFRunLoopUnlock(rl);
#if defined(__MACH__)
if (NULL != msg) {
struct kevent *kev = (void *)msg + sizeof(mach_msg_header_t) + ((msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) ? (sizeof(mach_msg_body_t) + sizeof(mach_msg_descriptor_t) * ((mach_msg_base_t *)msg)->body.msgh_descriptor_count) : 0);
rls = kev->udata;
kev->udata = NULL;
CFRetain(rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
__CFRunLoopSourceUnlock(rls);
if (NULL != rls->_context.version2.perform) {
rls->_context.version2.perform(kev, rls->_context.version2.info);
}
sourceHandledThisLoop = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
CFRelease(rls);
__CFRunLoopModeLock(rlm);
}
#endif
} else if (livePort == rl->_wakeUpPort) {
__CFRunLoopUnlock(rl);
}
#if defined(__MACH__)
else if (livePort == timeoutPort) {
returnValue = kCFRunLoopRunTimedOut;
__CFRunLoopUnlock(rl);
} else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
mach_msg_header_t *reply = NULL;
__CFRunLoopUnlock(rl);
if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) {
sourceHandledThisLoop = true;
}
if (NULL != reply) {
ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
}
} else {
CFRunLoopTimerRef rlt;
rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort);
__CFRunLoopUnlock(rl);
if (NULL != rlt) {
__CFRunLoopDoTimer(rl, rlm, rlt);
}
}
if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg);
#else
else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) {
__CFRunLoopUnlock(rl);
if (__CFRunLoopDoSource1(rl, rlm, rls)) {
sourceHandledThisLoop = true;
}
}
#endif
#if defined(__WIN32__)
if (NULL != timersToCall) {
int i;
for (i = CFArrayGetCount(timersToCall)-1; i >= 0; i--)
__CFRunLoopDoTimer(rl, rlm, (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timersToCall, i));
CFRelease(timersToCall);
}
#endif
__CFRunLoopModeUnlock(rlm); __CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (sourceHandledThisLoop && stopAfterHandle) {
returnValue = kCFRunLoopRunHandledSource;
} else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) {
returnValue = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
returnValue = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
returnValue = kCFRunLoopRunStopped;
} else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm)) {
returnValue = kCFRunLoopRunFinished;
}
__CFRunLoopUnlock(rl);
if (0 != returnValue) {
#if defined(__MACH__)
if (MACH_PORT_NULL != timeoutPort) {
if (!destroyWaitSet) __CFPortSetRemove(timeoutPort, waitSet);
mk_timer_destroy(timeoutPort);
}
#endif
return returnValue;
}
firstPass = false;
}
}
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {
CFRunLoopModeRef currentMode, previousMode;
CFIndex *previousStopped;
int32_t result;
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
currentMode = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode)) {
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
return kCFRunLoopRunFinished;
}
previousStopped = (CFIndex *)rl->_stopped;
rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 16, 0);
rl->_stopped[0] = 0x4346524C;
rl->_stopped[1] = 0x4346524C; rl->_stopped[2] = 0x00000000; rl->_stopped[3] = 0x4346524C;
previousMode = rl->_currentMode;
rl->_currentMode = currentMode;
__CFRunLoopUnlock(rl);
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, false);
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopLock(rl);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, (CFIndex *)rl->_stopped);
rl->_stopped = previousStopped;
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
void CFRunLoopRun(void) {
int32_t result;
do {
result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
static void __CFRunLoopFindMinTimer(const void *value, void *ctx) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value;
if (__CFIsValid(rlt)) {
CFRunLoopTimerRef *result = ctx;
if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) {
*result = rlt;
}
}
}
static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) {
CFRunLoopTimerRef result = NULL;
int64_t fireTime = 0;
if (rlm) {
if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) {
__CFRunLoopTimerFireTSRLock();
CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result);
if (result)
fireTime = result->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
}
if (NULL != rlm->_submodes) {
CFIndex idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx);
CFRunLoopModeRef subrlm;
subrlm = __CFRunLoopFindMode(rl, modeName, false);
if (NULL != subrlm) {
int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm);
__CFRunLoopModeUnlock(subrlm);
if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime))
fireTime = newFireTime;
}
}
}
__CFRunLoopModeUnlock(rlm);
}
return fireTime;
}
CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) {
CFRunLoopModeRef rlm;
int64_t fireTSR;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
fireTSR = __CFRunLoopGetNextTimerFireTSR(rl, rlm);
int64_t now2 = (int64_t)mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
return (0 == fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(fireTSR - now2));
}
Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) {
return __CFRunLoopIsSleeping(rl);
}
void CFRunLoopWakeUp(CFRunLoopRef rl) {
#if defined(__MACH__)
kern_return_t ret;
ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0);
if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) {
HALT;
}
#else
SetEvent(rl->_wakeUpPort);
#endif
}
void CFRunLoopStop(CFRunLoopRef rl) {
__CFRunLoopLock(rl);
__CFRunLoopSetStopped(rl);
__CFRunLoopUnlock(rl);
CFRunLoopWakeUp(rl);
}
CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) {
CFRunLoopModeRef rlm;
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm) {
rlm->_stopped = true;
__CFRunLoopModeUnlock(rlm);
}
CFRunLoopWakeUp(rl);
}
CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) {
CFRunLoopModeRef rlm;
if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) {
return false;
} else if (CFEqual(modeName, candidateContainedName)) {
return true;
}
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, modeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm) {
CFArrayRef submodes;
if (NULL == rlm->_submodes) {
__CFRunLoopModeUnlock(rlm);
return false;
}
if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) {
__CFRunLoopModeUnlock(rlm);
return true;
}
submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL;
__CFRunLoopModeUnlock(rlm);
if (NULL != submodes) {
CFIndex idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) {
CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx);
if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) {
CFRelease(submodes);
return true;
}
}
CFRelease(submodes);
}
}
return false;
}
CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) {
CFRunLoopModeRef rlm;
if (__CFRunLoopIsDeallocating(rl)) return;
if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) {
return;
} else {
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, toModeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm) {
if (NULL == rlm->_submodes) {
rlm->_submodes = CFArrayCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeArrayCallBacks);
}
if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) {
CFArrayAppendValue(rlm->_submodes, modeName);
}
__CFRunLoopModeUnlock(rlm);
}
}
}
CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) {
CFRunLoopModeRef rlm;
if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) {
return;
} else {
__CFRunLoopLock(rl);
rlm = __CFRunLoopFindMode(rl, fromModeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm) {
if (NULL != rlm->_submodes) {
CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes);
idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName);
if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx);
}
__CFRunLoopModeUnlock(rlm);
}
}
}
Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CFRunLoopModeRef rlm;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rls);
}
__CFRunLoopUnlock(rl);
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_sources) {
hasValue = CFSetContainsValue(rlm->_sources, rls);
__CFRunLoopModeUnlock(rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
return hasValue;
}
void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CFRunLoopModeRef rlm;
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rls)) return;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
_CFSetSetCapacity(rl->_commonModeItems, 20);
}
CFSetAddValue(rl->_commonModeItems, rls);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rls};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL == rlm->_sources) {
rlm->_sources = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
_CFSetSetCapacity(rlm->_sources, 10);
}
if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) {
CFSetAddValue(rlm->_sources, rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopSourceSchedule(rls, rl, rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {
CFRunLoopModeRef rlm;
__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);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rls};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
__CFRunLoopUnlock(rl);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) {
CFRetain(rls);
CFSetRemoveValue(rlm->_sources, rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopSourceCancel(rls, rl, rlm);
CFRelease(rls);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CFRunLoopModeRef rlm;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rlo);
}
__CFRunLoopUnlock(rl);
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_observers) {
hasValue = CFSetContainsValue(rlm->_observers, rlo);
__CFRunLoopModeUnlock(rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
return hasValue;
}
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
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(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlo);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL == rlm->_observers) {
rlm->_observers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
}
if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) {
CFSetAddValue(rlm->_observers, rlo);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopObserverSchedule(rlo, rl, rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
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);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
__CFRunLoopUnlock(rl);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) {
CFRetain(rlo);
CFSetRemoveValue(rlm->_observers, rlo);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopObserverCancel(rlo, rl, rlm);
CFRelease(rlo);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CFRunLoopModeRef rlm;
Boolean hasValue = false;
__CFRunLoopLock(rl);
if (modeName == kCFRunLoopCommonModes) {
if (NULL != rl->_commonModeItems) {
hasValue = CFSetContainsValue(rl->_commonModeItems, rlt);
}
__CFRunLoopUnlock(rl);
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_timers) {
hasValue = CFSetContainsValue(rlm->_timers, rlt);
__CFRunLoopModeUnlock(rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
return hasValue;
}
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CFRunLoopModeRef rlm;
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(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlt);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlt};
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, true);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL == rlm->_timers) {
rlm->_timers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks);
}
if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) {
CFSetAddValue(rlm->_timers, rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopTimerSchedule(rlt, rl, rlm);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CFRunLoopModeRef rlm;
__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);
__CFRunLoopUnlock(rl);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlt};
CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
CFRelease(set);
}
} else {
__CFRunLoopUnlock(rl);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, false);
__CFRunLoopUnlock(rl);
if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) {
CFRetain(rlt);
CFSetRemoveValue(rlm->_timers, rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopTimerCancel(rlt, rl, rlm);
CFRelease(rlt);
} else if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
}
static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) {
CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1;
CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2;
if (rls1 == rls2) return true;
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 (2 == rls1->_context.version0.version && rls1->_context.version2.perform != rls2->_context.version2.perform) return false;
if (2 == rls1->_context.version0.version && !(rls1->_context.version2.event.ident == rls2->_context.version2.event.ident && rls1->_context.version2.event.filter == rls2->_context.version2.event.filter)) 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) {
contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource context %p>"), rls->_context.version0.info);
}
result = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signaled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), rls->_lock ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc);
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);
}
}
static const CFRuntimeClass __CFRunLoopSourceClass = {
_kCFRuntimeScannedObject,
"CFRunLoopSource",
NULL, NULL, __CFRunLoopSourceDeallocate,
__CFRunLoopSourceEqual,
__CFRunLoopSourceHash,
NULL, __CFRunLoopSourceCopyDescription
};
__private_extern__ void __CFRunLoopSourceInitialize(void) {
__kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass);
}
CFTypeID CFRunLoopSourceGetTypeID(void) {
return __kCFRunLoopSourceTypeID;
}
CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
CFRunLoopSourceRef memory;
uint32_t size;
if (NULL == context) HALT;
size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopSourceUnsetSignaled(memory);
memory->_lock = 0;
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;
case 2:
size = sizeof(CFRunLoopSourceContext2);
break;
}
CF_WRITE_BARRIER_MEMMOVE(&memory->_context, context, size);
if (2 == memory->_context.version0.version) {
memory->_context.version2.event.udata = memory;
memory->_context.version2.event.flags &= ~(EV_SYSFLAGS | 0xFF0F); }
if (context->retain) {
memory->_context.version0.info = (void *)context->retain(context->info);
}
return memory;
}
CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) {
__CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
return rls->_order;
}
static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) {
CFRunLoopRef rl = (CFRunLoopRef)value;
CFTypeRef *params = context;
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0];
CFArrayRef array;
CFIndex idx;
if (rl == params[1]) return;
array = CFRunLoopCopyAllModes(rl);
for (idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
CFRunLoopRemoveSource(rl, rls, modeName);
}
CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes);
CFRelease(array);
params[1] = rl;
}
void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) {
__CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
CFRetain(rls);
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFUnsetValid(rls);
if (NULL != rls->_runLoops) {
CFTypeRef params[2] = {rls, NULL};
CFBagRef bag = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops);
CFRelease(rls->_runLoops);
rls->_runLoops = NULL;
__CFRunLoopSourceUnlock(rls);
CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params);
CFRelease(bag);
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
CFRelease(rls);
}
Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) {
__CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
return __CFIsValid(rls);
}
void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) {
__CFGenericValidateType(rls, __kCFRunLoopSourceTypeID);
CFAssert1(0 == context->version || 1 == context->version || 2 == 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;
case 2:
size = sizeof(CFRunLoopSourceContext2);
break;
}
memmove(context, &rls->_context, size);
}
void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) {
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceSetSignaled(rls);
}
__CFRunLoopSourceUnlock(rls);
}
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(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info);
}
result = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), rlo->_lock ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc);
CFRelease(contextDesc);
return result;
}
static void __CFRunLoopObserverDeallocate(CFTypeRef cf) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf;
CFRunLoopObserverInvalidate(rlo);
}
static const CFRuntimeClass __CFRunLoopObserverClass = {
0,
"CFRunLoopObserver",
NULL, NULL, __CFRunLoopObserverDeallocate,
NULL,
NULL,
NULL, __CFRunLoopObserverCopyDescription
};
__private_extern__ void __CFRunLoopObserverInitialize(void) {
__kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass);
}
CFTypeID CFRunLoopObserverGetTypeID(void) {
return __kCFRunLoopObserverTypeID;
}
CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
CFRunLoopObserverRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopObserverUnsetFiring(memory);
if (repeats) {
__CFRunLoopObserverSetRepeats(memory);
} else {
__CFRunLoopObserverUnsetRepeats(memory);
}
memory->_lock = 0;
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;
}
CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) {
__CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
return rlo->_activities;
}
CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) {
__CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
return rlo->_order;
}
Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) {
__CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
return __CFRunLoopObserverRepeats(rlo);
}
void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) {
__CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
CFRetain(rlo);
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
CFRunLoopRef rl = rlo->_runLoop;
__CFUnsetValid(rlo);
__CFRunLoopObserverUnlock(rlo);
if (NULL != rl) {
CFArrayRef array;
CFIndex idx;
array = CFRunLoopCopyAllModes(rl);
for (idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
CFRunLoopRemoveObserver(rl, rlo, modeName);
}
CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes);
CFRelease(array);
}
if (rlo->_context.release)
rlo->_context.release(rlo->_context.info);
rlo->_context.info = NULL;
} else {
__CFRunLoopObserverUnlock(rlo);
}
CFRelease(rlo);
}
Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) {
return __CFIsValid(rlo);
}
void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) {
__CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID);
CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
*context = rlo->_context;
}
static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
CFStringRef result;
CFStringRef contextDesc = NULL;
int64_t fireTime;
__CFRunLoopTimerFireTSRLock();
fireTime = rlt->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
if (NULL != rlt->_context.copyDescription) {
contextDesc = rlt->_context.copyDescription(rlt->_context.info);
}
if (NULL == contextDesc) {
contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info);
}
int64_t now2 = (int64_t)mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
result = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer %x [%x]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), rlt->_lock ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, rlt->_callout, contextDesc);
CFRelease(contextDesc);
return result;
}
static void __CFRunLoopTimerDeallocate(CFTypeRef cf) {
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf;
CFRunLoopTimerInvalidate(rlt);
}
static const CFRuntimeClass __CFRunLoopTimerClass = {
0,
"CFRunLoopTimer",
NULL, NULL, __CFRunLoopTimerDeallocate,
NULL, NULL,
NULL, __CFRunLoopTimerCopyDescription
};
__private_extern__ void __CFRunLoopTimerInitialize(void) {
__kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass);
}
CFTypeID CFRunLoopTimerGetTypeID(void) {
return __kCFRunLoopTimerTypeID;
}
CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
CFRunLoopTimerRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopTimerUnsetFiring(memory);
__CFRunLoopTimerUnsetDidFire(memory);
memory->_lock = 0;
memory->_runLoop = NULL;
memory->_rlCount = 0;
#if defined(__MACH__)
memory->_port = MACH_PORT_NULL;
#endif
memory->_order = order;
int64_t now2 = (int64_t)mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
if (fireDate < now1) {
memory->_fireTSR = now2;
} else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
memory->_fireTSR = LLONG_MAX;
} else {
memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
}
if (interval <= 0.0) {
memory->_intervalTSR = 0;
} else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) {
memory->_intervalTSR = LLONG_MAX;
} else {
memory->_intervalTSR = __CFTimeIntervalToTSR(interval);
}
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;
}
CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) {
int64_t fireTime, result = 0;
CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime");
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
__CFRunLoopTimerFireTSRLock();
fireTime = rlt->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
__CFRunLoopTimerLock(rlt);
if (__CFIsValid(rlt)) {
result = fireTime;
}
__CFRunLoopTimerUnlock(rlt);
int64_t now2 = (int64_t)mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2);
}
void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) {
__CFRunLoopTimerFireTSRLock();
int64_t now2 = (int64_t)mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
if (fireDate < now1) {
rlt->_fireTSR = now2;
} else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) {
rlt->_fireTSR = LLONG_MAX;
} else {
rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
}
if (rlt->_runLoop != NULL) {
__CFRunLoopTimerRescheduleWithAllModes(rlt, rlt->_runLoop);
}
__CFRunLoopTimerFireTSRUnlock();
}
CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) {
CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval");
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
return __CFTSRToTimeInterval(rlt->_intervalTSR);
}
Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) {
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
return (0 != rlt->_intervalTSR);
}
CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) {
CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order");
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
return rlt->_order;
}
void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) {
CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate");
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
CFRetain(rlt);
__CFRunLoopTimerLock(rlt);
if (__CFIsValid(rlt)) {
CFRunLoopRef rl = rlt->_runLoop;
void *info = rlt->_context.info;
__CFUnsetValid(rlt);
#if defined(__MACH__)
__CFRunLoopTimerPortMapLock();
if (NULL != __CFRLTPortMap) {
CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port);
}
__CFRunLoopTimerPortMapUnlock();
mk_timer_destroy(rlt->_port);
rlt->_port = MACH_PORT_NULL;
#endif
rlt->_context.info = NULL;
__CFRunLoopTimerUnlock(rlt);
if (NULL != rl) {
CFArrayRef array;
CFIndex idx;
array = CFRunLoopCopyAllModes(rl);
for (idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = CFArrayGetValueAtIndex(array, idx);
CFRunLoopRemoveTimer(rl, rlt, modeName);
}
CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes);
CFRelease(array);
}
if (NULL != rlt->_context.release) {
rlt->_context.release(info);
}
} else {
__CFRunLoopTimerUnlock(rlt);
}
CFRelease(rlt);
}
Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) {
CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid");
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
return __CFIsValid(rlt);
}
void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) {
__CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID);
CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
*context = rlt->_context;
}
struct rlpair {
CFRunLoopRef rl; CFStringRef mode; };
static Boolean __CFRLPKeyEqual(const void *value1, const void *value2) {
const struct rlpair *s1 = value1;
const struct rlpair *s2 = value2;
return (s1->rl == s2->rl) && CFEqual(s1->mode, s2->mode);
}
static CFHashCode __CFRLPKeyHash(const void *value) {
const struct rlpair *s = value;
return (CFHashCode)s->rl + CFHash(s->mode);
}
static CFSpinLock_t __CFRunLoopPerformLock = 0;
static CFMutableDictionaryRef __CFRunLoopPerformSources = NULL;
struct performentry {
CFRunLoopPerformCallBack callout;
void *info;
};
struct performinfo {
CFSpinLock_t lock;
CFRunLoopSourceRef source;
CFRunLoopRef rl;
CFStringRef mode;
CFIndex count;
CFIndex size;
struct performentry *entries;
};
static void __CFRunLoopPerformCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
struct rlpair key, *pair;
struct performinfo *pinfo = info;
__CFSpinLock(&__CFRunLoopPerformLock);
key.rl = rl;
key.mode = mode;
if (CFDictionaryGetKeyIfPresent(__CFRunLoopPerformSources, &key, (const void **)&pair)) {
CFDictionaryRemoveValue(__CFRunLoopPerformSources, pair);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, pair);
}
CFRunLoopSourceInvalidate(pinfo->source);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo->entries);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo);
__CFSpinUnlock(&__CFRunLoopPerformLock);
}
static void __CFRunLoopPerformPerform(void *info) {
struct performinfo *pinfo = info;
struct performentry *entries;
CFIndex idx, cnt;
__CFSpinLock(&(pinfo->lock));
entries = pinfo->entries;
cnt = pinfo->count;
pinfo->entries = NULL;
pinfo->count = 0;
pinfo->size = 0;
__CFSpinUnlock(&(pinfo->lock));
for (idx = 0; idx < cnt; idx++) {
entries[idx].callout(entries[idx].info);
}
CFAllocatorDeallocate(kCFAllocatorSystemDefault, entries);
}
void _CFRunLoopPerformEnqueue(CFRunLoopRef rl, CFStringRef mode, CFRunLoopPerformCallBack callout, void *info) {
CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
CFRunLoopSourceRef source;
struct rlpair key;
struct performinfo *pinfo;
__CFSpinLock(&__CFRunLoopPerformLock);
if (!__CFRunLoopPerformSources) {
CFDictionaryKeyCallBacks kcb = {0, NULL, NULL, NULL, __CFRLPKeyEqual, __CFRLPKeyHash};
__CFRunLoopPerformSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kcb, &kCFTypeDictionaryValueCallBacks);
}
key.rl = rl;
key.mode = mode;
if (!CFDictionaryGetValueIfPresent(__CFRunLoopPerformSources, &key, (const void **)&source)) {
struct rlpair *pair;
context.info = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct performinfo), 0);
pinfo = context.info;
pinfo->lock = 0;
pinfo->rl = rl;
pinfo->mode = mode;
pinfo->count = 0;
pinfo->size = 0;
pinfo->entries = NULL;
context.cancel = __CFRunLoopPerformCancel;
context.perform = __CFRunLoopPerformPerform;
source = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &context);
pair = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(*pair), 0);
*pair = key;
CFDictionarySetValue(__CFRunLoopPerformSources, pair, source);
pinfo->source = source;
CFRunLoopAddSource(rl, source, mode);
} else {
CFRetain(source);
CFRunLoopSourceGetContext(source, &context);
pinfo = context.info;
}
__CFSpinLock(&(pinfo->lock));
__CFSpinUnlock(&__CFRunLoopPerformLock);
if (pinfo->count == pinfo->size) {
pinfo->size = (0 == pinfo->size ? 3 : 2 * pinfo->size);
pinfo->entries = CFAllocatorReallocate(kCFAllocatorSystemDefault, pinfo->entries, pinfo->size * sizeof(struct performentry), 0);
}
pinfo->entries[pinfo->count].callout = callout;
pinfo->entries[pinfo->count].info = info;
pinfo->count++;
__CFSpinUnlock(&(pinfo->lock));
CFRunLoopSourceSignal(source);
CFRunLoopWakeUp(rl);
CFRelease(source);
}