CFRuntimeClass動(dòng)態(tài)創(chuàng)建一個(gè)類所需要的信息
enum {
_kCFRuntimeNotATypeID = 0
};
//和CFRuntimeClass的version做位與操作,用來定義動(dòng)態(tài)創(chuàng)建的類需要的一些可選函數(shù)指針赊琳,如果不符合要求晨抡,程序會(huì)報(bào)錯(cuò)刃唐,并返回筋现,具體的操作可一查看后面的動(dòng)態(tài)注冊(cè)類的函數(shù)_CFRuntimeRegisterClass,_kCFRuntimeNotATypeID,表示注冊(cè)失敗
enum { // Version field constants
_kCFRuntimeScannedObject = (1UL << 0),
_kCFRuntimeResourcefulObject = (1UL << 2), // tells CFRuntime to make use of the reclaim field
_kCFRuntimeCustomRefCount = (1UL << 3), // tells CFRuntime to make use of the refcount field
_kCFRuntimeRequiresAlignment = (1UL << 4), // tells CFRuntime to make use of the requiredAlignment field
};
typedef struct __CFRuntimeClass {
CFIndex version;
const char *className; // 類名,必須要有惨篱,否則會(huì)終止程序
void (*init)(CFTypeRef cf); //初始化,會(huì)在函數(shù)_CFRuntimeCreateInstance和_CFRuntimeInitInstance里調(diào)用
CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf); //拷貝围俘,應(yīng)該一直為空砸讳,因?yàn)橐话愕腃F對(duì)象不會(huì)被拷貝
void (*finalize)(CFTypeRef cf); //最后的琢融,用來釋放資源
Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2); //判斷是否相等
CFHashCode (*hash)(CFTypeRef cf); //該類所代表的哈希碼
//hash和equal函數(shù)必須滿足條件:equal(A,B)相等意味著hash(A) == hash(B)
CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // return str with retain
CFStringRef (*copyDebugDesc)(CFTypeRef cf); // return str with retain
#define CF_RECLAIM_AVAILABLE 1
void (*reclaim)(CFTypeRef cf); // Or in _kCFRuntimeResourcefulObject in the .version to indicate this field should be used
#define CF_REFCOUNT_AVAILABLE 1
uint32_t (*refcount)(intptr_t op, CFTypeRef cf); // Or in _kCFRuntimeCustomRefCount in the .version to indicate this field should be used
// this field must be non-NULL when _kCFRuntimeCustomRefCount is in the .version field
// - if the callback is passed 1 in 'op' it should increment the 'cf's reference count and return 0
// - if the callback is passed 0 in 'op' it should return the 'cf's reference count, up to 32 bits
// - if the callback is passed -1 in 'op' it should decrement the 'cf's reference count; if it is now zero, 'cf' should be cleaned up and deallocated (the finalize callback above will NOT be called unless the process is running under GC, and CF does not deallocate the memory for you; if running under GC, finalize should do the object tear-down and free the object memory); then return 0
// remember to use saturation arithmetic logic and stop incrementing and decrementing when the ref count hits UINT32_MAX, or you will have a security bug
// remember that reference count incrementing/decrementing must be done thread-safely/atomically
// objects should be created/initialized with a custom ref-count of 1 by the class creation functions
// do not attempt to use any bits within the CFRuntimeBase for your reference count; store that in some additional field in your CF object
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#define CF_REQUIRED_ALIGNMENT_AVAILABLE 1
uintptr_t requiredAlignment; // Or in _kCFRuntimeRequiresAlignment in the .version field to indicate this field should be used; the allocator to _CFRuntimeCreateInstance() will be ignored in this case; if this is less than the minimum alignment the system supports, you'll get higher alignment; if this is not an alignment the system supports (e.g., most systems will only support powers of two, or if it is too high), the result (consequences) will be up to CF or the system to decide
} CFRuntimeClass;
_CFRuntimeRegisterClass動(dòng)態(tài)注冊(cè)一個(gè)類,并返回該類在注冊(cè)列表中的索引位置
CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) {
// className must be pure ASCII string, non-null
//如果version和枚舉_kCFRuntimeCustomRefCount按位于得到的是真簿寂,但是函數(shù)指針refcount卻為空漾抬,則不滿足動(dòng)態(tài)注冊(cè)的條件
if ((cls->version & _kCFRuntimeCustomRefCount) && !cls->refcount) {
CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls->className);
return _kCFRuntimeNotATypeID;
}
__CFLock(&__CFBigRuntimeFunnel);
//如果已經(jīng)注冊(cè)了的類型的個(gè)數(shù)大于了CoreFoundation允許的最大可注冊(cè)類型個(gè)數(shù),則不允許注冊(cè)該類
if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) {
CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className);
__CFUnlock(&__CFBigRuntimeFunnel);
return _kCFRuntimeNotATypeID;
}
//__CFRuntimeClassTableSize貌似是1024
if (__CFRuntimeClassTableSize <= __CFRuntimeClassTableCount) {
CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className);
__CFUnlock(&__CFBigRuntimeFunnel);
return _kCFRuntimeNotATypeID;
}
__CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
CFTypeID typeID = __CFRuntimeClassTableCount - 1; //typeID其實(shí)就是該類在動(dòng)態(tài)注冊(cè)列表中的索引位置
__CFUnlock(&__CFBigRuntimeFunnel);
return typeID;
}
CFRunLoopGetTypeID陶耍,獲取每個(gè)類的唯一編號(hào)奋蔚,該編號(hào)是該類在注冊(cè)列表中的索引位置
//單例,只會(huì)運(yùn)行一次
CFTypeID CFRunLoopGetTypeID(void) {
static dispatch_once_t initOnce;
dispatch_once(&initOnce, ^{
__kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass); //注冊(cè)runloop類烈钞,類名為CFRunLoop泊碑,并返回該類型的typeID
__kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); //注冊(cè)runloop的mode,類名為CFRunLoopMode毯欣,并返回其typeID
});
return __kCFRunLoopTypeID;
}
_CFRuntimeCreateInstance根據(jù)傳入的typeID馒过,開辟內(nèi)存空間,并返回其開始位置指針
CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) {
if (__CFRuntimeClassTableSize <= typeID) HALT; //如果該typeID超過了注冊(cè)列表的最大尺寸酗钞,則退出程序
CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); //判斷輸入的typeID是有效的
CFRuntimeClass *cls = __CFRuntimeClassTable[typeID]; //根據(jù)typeID這個(gè)索引獲取到之前注冊(cè)的類
if (NULL == cls) {
return NULL;
}
if (cls->version & _kCFRuntimeRequiresAlignment) {
allocator = kCFAllocatorSystemDefault;
}
Boolean customRC = !!(cls->version & _kCFRuntimeCustomRefCount);
if (customRC && !cls->refcount) {
CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls->className);
return NULL;
}
CFAllocatorRef realAllocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
if (kCFAllocatorNull == realAllocator) {
return NULL;
}
Boolean usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(realAllocator);
size_t align = (cls->version & _kCFRuntimeRequiresAlignment) ? cls->requiredAlignment : 16;
CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef));
size = (size + 0xF) & ~0xF; //保證所占用的位數(shù)是16的倍數(shù) CF objects are multiples of 16 in size
// CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
// CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
CFRuntimeBase *memory = NULL;
if (cls->version & _kCFRuntimeRequiresAlignment) {
memory = malloc_zone_memalign(malloc_default_zone(), align, size);
} else {
memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(cls));
}
if (NULL == memory) {
return NULL;
}
if (!kCFUseCollectableAllocator || !CF_IS_COLLECTABLE_ALLOCATOR(allocator) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls) & __kCFAllocatorGCScannedMemory)) {
memset(memory, 0, size);
}
if (__CFOASafe && category) {
__CFSetLastAllocationEventName(memory, (char *)category);
} else if (__CFOASafe) {
__CFSetLastAllocationEventName(memory, (char *)cls->className);
}
if (!usesSystemDefaultAllocator) {
// add space to hold allocator ref for non-standard allocators.
// (this screws up 8 byte alignment but seems to work)
*(CFAllocatorRef *)((char *)memory) = (CFAllocatorRef)CFRetain(realAllocator);
memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef));
}
uint32_t rc = 0;
#if __LP64__
if (!kCFUseCollectableAllocator || (1 && 1)) {
memory->_rc = 1;
}
if (customRC) {
memory->_rc = 0xFFFFFFFFU;
rc = 0xFF;
}
#else
if (!kCFUseCollectableAllocator || (1 && 1)) {
rc = 1;
}
if (customRC) {
rc = 0xFF;
}
#endif
uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
*cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00));
memory->_cfisa = 0;
if (NULL != cls->init) { //runloop的init是空
(cls->init)(memory);
}
return memory;
}
__CFRunLoop
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* 互斥鎖腹忽,locked for accessing mode list */
__CFPort _wakeUpPort; //喚醒端口 used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // 每次運(yùn)行的一些狀態(tài)數(shù)據(jù)reset for runs of the run loop
pthread_t _pthread; //當(dāng)前創(chuàng)建runloop時(shí)的線程
uint32_t _winthread;
CFMutableSetRef _commonModes; //存放mode狀態(tài),默認(rèn)會(huì)添加一個(gè)kCFRunLoopDefaultMode
CFMutableSetRef _commonModeItems;
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
__CFRunLoopMode
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name; //mode名字
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0; //source0事件集合
CFMutableSetRef _sources1; //source1事件集合
CFMutableArrayRef _observers; //添加的觀察者集合
CFMutableArrayRef _timers; //添加的timer集合
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
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; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
__CFRunLoopFindMode查找
static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm; //__CFRunLoopMode的指針;
struct __CFRunLoopMode srlm; //創(chuàng)建一個(gè)臨時(shí)的mode砚作,用于查找
memset(&srlm, 0, sizeof(srlm));
_CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
srlm._name = modeName;
rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm); //查找當(dāng)前runloop中是否存在srlm的mode
if (NULL != rlm) { //如果找到了窘奏,則直接返回找到的,否則繼續(xù)后面的葫录,對(duì)前面的rlm進(jìn)行創(chuàng)建
__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;
});
// Set timer to far out there. The unique leeway makes this timer easy to spot in debug output.
_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); //添加該mode到runloop的modes中
CFRelease(rlm);
__CFRunLoopModeLock(rlm); /* return mode locked */
return rlm;
}
__CFRunLoopCreate創(chuàng)建runloop
//根據(jù)線程創(chuàng)建runloop
static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
//用整個(gè)runloop所要占用的內(nèi)存的大小減去減去結(jié)構(gòu)體CFRuntimeBase的大小着裹,為什么要減去呢?這樣不就少了嗎米同?其實(shí)在后面的方法_CFRuntimeCreateInstance中又加回來了:CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef));
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
//創(chuàng)建runloop骇扇,并設(shè)置同一個(gè)typeID,方法_CFRuntimeCreateInstance返回的是CFRuntimeBase類型的指針
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL);
if (NULL == loop) {
return NULL;
}
(void)__CFRunLoopPushPerRunData(loop); //初始化每次循環(huán)時(shí)的數(shù)據(jù)
__CFRunLoopLockInit(&loop->_lock);
loop->_wakeUpPort = __CFPortAllocate(); //創(chuàng)建喚醒監(jiān)聽端口
if (CFPORT_NULL == loop->_wakeUpPort) HALT; //如果沒有喚醒端口面粮,則程序退出
__CFRunLoopSetIgnoreWakeUps(loop); //不忽略喚醒
loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode); //默認(rèn)添加一個(gè)運(yùn)行mode
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;
}
OSAtomicCompareAndSwapPtrBarrier
如果theValue和oldValue的指針相等少孝,則把newValue賦值給theValue
bool OSAtomicCompareAndSwapPtrBarrier( void *__oldValue, void *__newValue, void * volatile *__theValue );
一些常量
// Foundation uses 20-40
// Foundation knows about the value of __CFTSDKeyAutoreleaseData1
enum {
__CFTSDKeyAllocator = 1,
__CFTSDKeyIsInCFLog = 2,
__CFTSDKeyIsInNSCache = 3,
__CFTSDKeyIsInGCDMainQ = 4,
__CFTSDKeyICUConverter = 7,
__CFTSDKeyCollatorLocale = 8,
__CFTSDKeyCollatorUCollator = 9,
__CFTSDKeyRunLoop = 10,
__CFTSDKeyRunLoopCntr = 11,
__CFTSDKeyMachMessageBoost = 12, // valid only in the context of a CFMachPort callout
__CFTSDKeyMachMessageHasVoucher = 13,
// autorelease pool stuff must be higher than run loop constants
__CFTSDKeyAutoreleaseData2 = 61,
__CFTSDKeyAutoreleaseData1 = 62,
__CFTSDKeyExceptionData = 63,
};
_CFRunLoopGet0
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFLock_t loopsLock = CFLockInit;
// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
if (pthread_equal(t, kNilPthreadT)) { //判斷當(dāng)前線程是否為空,如果為空熬苍,則獲取主線程傳入
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
if (!__CFRunLoops) { //如果當(dāng)前儲(chǔ)存runloop的字典不存在稍走,則創(chuàng)建
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); //創(chuàng)建字典
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np()); //穿件主線程的runloop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop); //以線程作為key值,runloop作為value值存起來
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { //賦值
CFRelease(dict);
}
CFRelease(mainLoop);
__CFLock(&loopsLock);
}
//在當(dāng)前runloop中柴底,以當(dāng)前線程為key查找runloop
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFUnlock(&loopsLock);
if (!loop) { //如果沒找到钱磅,則創(chuàng)建
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
//再次查找(為什么呢?)
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); //以線程為key似枕,runloop為value儲(chǔ)存
loop = newLoop;
}
// don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
__CFUnlock(&loopsLock);
CFRelease(newLoop);
}
//注冊(cè)銷毀回調(diào)
if (pthread_equal(t, pthread_self())) { //如果傳入的線程和當(dāng)前線程是相同的(一般是相同的)
_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL); //將創(chuàng)建的runloop儲(chǔ)存在__CFTSDTable的data數(shù)據(jù)中,__CFTSDKeyRunLoop為索引年柠,其類型為__CFTSDKeyAutoreleaseData1
if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
}
}
return loop;
}
_CFGetTSD和_CFSetTSD(在CFPlatform.c文件中)
這部分是和線程相關(guān)的操作凿歼,以及變量的釋放回調(diào)處理褪迟,其他的表示看不懂了
// If slot >= CF_TSD_MAX_SLOTS, the SPI functions will crash at NULL + slot address.
// If thread data has been torn down, these functions should crash on CF_TSD_BAD_PTR + slot address.
#define CF_TSD_MAX_SLOTS 70
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
static const unsigned long CF_TSD_KEY = __PTK_FRAMEWORK_COREFOUNDATION_KEY5;
#endif
// Windows and Linux, not sure how many times the destructor could get called; CF_TSD_MAX_DESTRUCTOR_CALLS could be 1
#define CF_TSD_BAD_PTR ((void *)0x1000)
typedef void (*tsdDestructor)(void *);
// Data structure to hold TSD data, cleanup functions for each
typedef struct __CFTSDTable {
uint32_t destructorCount;
uintptr_t data[CF_TSD_MAX_SLOTS];
tsdDestructor destructors[CF_TSD_MAX_SLOTS];
} __CFTSDTable;
// Get or initialize a thread local storage. It is created on demand.
static __CFTSDTable *__CFTSDGetTable() {
__CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific();
// Make sure we're not setting data again after destruction.
if (table == CF_TSD_BAD_PTR) {
return NULL;
}
// Create table on demand
if (!table) {
// This memory is freed in the finalize function
table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable));
// Windows and Linux have created the table already, we need to initialize it here for other platforms. On Windows, the cleanup function is called by DllMain when a thread exits. On Linux the destructor is set at init time.
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize);
#endif
__CFTSDSetSpecific(table);
}
return table;
}
// For the use of CF and Foundation only
CF_EXPORT void *_CFGetTSD(uint32_t slot) {
if (slot > CF_TSD_MAX_SLOTS) {
_CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot);
HALT;
}
__CFTSDTable *table = __CFTSDGetTable();
if (!table) {
// Someone is getting TSD during thread destruction. The table is gone, so we can't get any data anymore.
_CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot);
return NULL;
}
uintptr_t *slots = (uintptr_t *)(table->data);
return (void *)slots[slot];
}
// For the use of CF and Foundation only
CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) {
if (slot > CF_TSD_MAX_SLOTS) {
_CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot);
HALT;
}
__CFTSDTable *table = __CFTSDGetTable();
if (!table) {
// Someone is setting TSD during thread destruction. The table is gone, so we can't get any data anymore.
_CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot);
return NULL;
}
void *oldVal = (void *)table->data[slot];
table->data[slot] = (uintptr_t)newVal;
table->destructors[slot] = destructor;
return oldVal;
}
CFRunLoopGetCurrent獲取當(dāng)前線程的runloop
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
根據(jù)上面的分析,會(huì)做如下操作:
- 通過_CFGetTSD先在__CFTSDTable表中查找答憔,如果存在味赃,則直接返回;
- 通過方法_CFRunLoopGet0傳入當(dāng)前線程查找虐拓。如果存儲(chǔ)線程和runloop的字典__CFRunLoops不存在心俗,則創(chuàng)建;然后調(diào)用方法__CFRunLoopCreate傳入主線程創(chuàng)建屬于主線程的runloop蓉驹,以線程為key城榛,runloop為value儲(chǔ)存在字典中;
- 如果字典__CFRunLoops存在态兴,或者已經(jīng)創(chuàng)建了狠持,則在字典中以當(dāng)前線程為key進(jìn)行查找
- 如果該runloop不存在,則創(chuàng)建瞻润。注意喘垂,接著會(huì)再次查找自帶呢中是否存在屬于該線程的runloop,如果不存在绍撞,才會(huì)保存下來正勒;
- 判斷當(dāng)前線程和所傳入的線程是否相同,如果相同傻铣,則保存在__CFTSDTable中章贞,并注冊(cè)回調(diào)釋放函數(shù)__CFFinalizeRunLoop
- 返回查找到的runloop
CFRunLoopGetMain獲取主線程的runloop
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
和獲取當(dāng)前線程不同的地方在于剛開始,獲取主線程的runloop并不會(huì)去__CFTSDTable結(jié)構(gòu)體的相關(guān)數(shù)組中查找矾柜,因?yàn)橹骶€程的runloop是個(gè)靜態(tài)static變量阱驾,如果該靜態(tài)變量為空,則開始調(diào)用_CFRunLoopGet0方法怪蔑,傳入主線程查找里覆,緊接著的和獲取當(dāng)前線程相同,不再贅述缆瓣。
__CFRunLoopDoSources0
/* rl is locked, rlm is locked on entrance and exit */
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) __attribute__((noinline));
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */
CHECK_FOR_FORK();
CFTypeRef sources = NULL;
Boolean sourceHandled = false;
/* Fire the version 0 sources */
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) {
CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources); //創(chuàng)建一個(gè)新的sources喧枷,并把runloop中mode里的source0事件添加到該set中
}
if (NULL != sources) {
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
// sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
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); //執(zhí)行source的perform函數(shù),并把info當(dāng)作參數(shù)傳入
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);//執(zhí)行source的perform函數(shù)弓坞,并把info當(dāng)作參數(shù)傳入
CHECK_FOR_FORK();
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
if (stopAfterHandle && sourceHandled) {隧甚。//處理完一個(gè)事兒就返回
break;
}
}
}
CFRelease(sources);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
}
return sourceHandled;
}
__CFRunLoopRun
/* rl, rlm are locked on entrance and exit */
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
uint64_t startTSR = mach_absolute_time(); //獲取當(dāng)前時(shí)間
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 {
dispatch_source_t ds;
CFRunLoopRef rl;
uint64_t termTSR;
};
*/
//開辟一個(gè)結(jié)構(gòu)體__timeout_context大小的空間
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
if (seconds <= 0.0) { // instant timeout
seconds = 0.0;
timeout_context->termTSR = 0ULL;
} else if (seconds <= TIMER_INTERVAL_LIMIT) { //#define TIMER_DATE_LIMIT 4039289856.0
//#define TIMER_INTERVAL_LIMIT 504911232.0
//獲取主線程,如果能獲取到渡冻,則獲取主隊(duì)列戚扳,否則獲取一個(gè)后臺(tái)運(yùn)行隊(duì)列
dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
//創(chuàng)建一個(gè)時(shí)間源,并啟動(dòng)
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); // source gets ownership of context
dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
//因?yàn)閐ispatch_time函數(shù)的第二個(gè)參數(shù)單位是納秒族吻,所以這里是轉(zhuǎn)換單位,創(chuàng)建開始時(shí)間
uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
//(timer, 開始時(shí)間帽借, 循環(huán)間隔珠增, 精度)奕删,這里允許的誤差為1000納秒挟秤,循環(huán)間隔為永久,即永不循環(huán)
dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
dispatch_resume(timeout_timer);
} else { // infinite timeout
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
//以上說明畴嘶,如果時(shí)間范圍(相對(duì)于目前時(shí)間來說)大于0但是小于最大時(shí)間脆荷,則會(huì)默認(rèn)啟動(dòng)一個(gè)定時(shí)器凝垛,時(shí)間間隔為(循環(huán)周期)DISPATCH_TIME_FOREVER
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);
//發(fā)送通知
if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
__CFRunLoopDoBlocks(rl, rlm);//(???)
//處理source0事件
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;
}
#endif
}
didDispatchPortLastTime = false;
//發(fā)送將要進(jìn)入等待狀態(tài)通知
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
//進(jìn)入等待,開始睡眠
__CFRunLoopSetSleeping(rl);
// do not do any user callouts after this point (after notifying of sleeping)
// Must push the local-to-this-activation ports in on every loop
// iteration, as this mode could be run re-entrantly and we don't
// want these ports to get serviced.
__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) {
// objc_clear_stack(0);
// <rdar://problem/16393959>
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) {
// Drain the internal queue. If one of the callout blocks sets the timerFired flag, break out and service the timer.
while (_dispatch_runloop_root_queue_perform_4CF(rlm->_queue));
if (rlm->_timerFired) {
// Leave livePort as the queue port, and service timers below
rlm->_timerFired = false;
break;
} else {
if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
}
} else {
// Go ahead and leave the inner loop.
break;
}
} while (1);
#else
if (kCFUseCollectableAllocator) {
// objc_clear_stack(0);
// <rdar://problem/16393959>
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
#endif
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart));
// Must remove the local-to-this-activation ports in on every loop
// iteration, as this mode could be run re-entrantly and we don't
// want these ports to get serviced. Also, we don't want them left
// in there if this function returns.
__CFPortSetRemove(dispatchPort, waitSet);
__CFRunLoopSetIgnoreWakeUps(rl);
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
//發(fā)送通知蜓谋,表示將要開始處理事件了
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting))
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:;
__CFRunLoopSetIgnoreWakeUps(rl);
if (MACH_PORT_NULL == livePort) { //如果livePort為空梦皮,什么也不做
CFRUNLOOP_WAKEUP_FOR_NOTHING(); //#define CFRUNLOOP_WAKEUP_FOR_NOTHING() do { } while (0)
// handle nothing
} else if (livePort == rl->_wakeUpPort) { //如果livePort和runloop的喚醒port是相同的,什么也不做
CFRUNLOOP_WAKEUP_FOR_WAKEUP(); //#define CFRUNLOOP_WAKEUP_FOR_WAKEUP() do { } while (0)
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
CFRUNLOOP_WAKEUP_FOR_TIMER(); //#define CFRUNLOOP_WAKEUP_FOR_TIMER() do { } while (0)
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer, because we apparently fired early
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
#if USE_MK_TIMER_TOO
else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
CFRUNLOOP_WAKEUP_FOR_TIMER(); //#define CFRUNLOOP_WAKEUP_FOR_TIMER() do { } while (0)
// On Windows, we have observed an issue where the timer port is set before the time which we requested it to be set. For example, we set the fire time to be TSR 167646765860, but it is actually observed firing at TSR 167646764145, which is 1715 ticks early. The result is that, when __CFRunLoopDoTimers checks to see if any of the run loop timers should be firing, it appears to be 'too early' for the next timer, and no timers are handled.
// In this case, the timer port has been automatically reset (since it was returned from MsgWaitForMultipleObjectsEx), and if we do not re-arm it, then no timers will ever be serviced again unless something adjusts the timer list (e.g. adding or removing timers). The fix for the issue is to reset the timer here if CFRunLoopDoTimers did not handle a timer itself. 9308754
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
else if (livePort == dispatchPort) {
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
__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();
// If we received a voucher from this mach_msg, then put a copy of the new voucher into TSD. CFMachPortBoost will look in the TSD for the voucher. By using the value in the TSD we tie the CFMachPortBoost to this received mach_msg explicitly without a chance for anything in between the two pieces of code to set the voucher again.
voucher_t previousVoucher = _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, (void *)voucherCopy, os_release);
// Despite the name, this works for windows handles as well
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);
}
}
// Restore the previous voucher
_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);
//釋放timer資源
if (timeout_timer) {
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
} else {
free(timeout_context);
}
return retVal;
}
CFRunLoopRunSpecific單次runloop的執(zhí)行情況
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished; //runloop判斷是否該runloop已經(jīng)被標(biāo)記為準(zhǔn)備釋放孤澎,如果是届氢,則返回runloop運(yùn)行狀態(tài)為完成
__CFRunLoopLock(rl);
//通過runloop的modeName查找當(dāng)前mode,在該過程中覆旭,如果找到了退子,則會(huì)直接返回,否則會(huì)新創(chuàng)建一個(gè)返回
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
//判斷當(dāng)前模式下的runloop里的source1型将、source0寂祥、timer等事件是否為空,如果為空七兜,則返回運(yùn)行狀態(tài)為完成
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; //默認(rèn)的運(yùn)行狀態(tài)是完成
//根據(jù)注冊(cè)的觀察選項(xiàng)和不同的狀態(tài)做位與丸凭,用來查看是否注冊(cè)了該狀態(tài)的通知,如果注冊(cè)了腕铸,則發(fā)送通知
if (currentMode->_observerMask & kCFRunLoopEntry )
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); //發(fā)送進(jìn)入runloop通知
//正式處理事件
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
if (currentMode->_observerMask & kCFRunLoopExit )
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); //發(fā)送退出runloop的通知
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopPopPerRunData(rl, previousPerRun);
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
CFRunLoopRun和CFRunLoopRunInMode
void CFRunLoopRun(void) { /* DOES CALLOUT */
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) { /* DOES CALLOUT */
CHECK_FOR_FORK();
return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);
}
兩個(gè)的區(qū)別僅僅在于后者只調(diào)用一次惜犀,并返回結(jié)果,而前者是多次調(diào)用狠裹,直到不滿足循環(huán)條件虽界。