RunLoop源碼解析(一)

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)條件虽界。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市涛菠,隨后出現(xiàn)的幾起案子莉御,更是在濱河造成了極大的恐慌,老刑警劉巖俗冻,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件礁叔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡迄薄,警方通過查閱死者的電腦和手機(jī)琅关,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讥蔽,“玉大人涣易,你說我怎么就攤上這事人乓。” “怎么了都毒?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)碰缔。 經(jīng)常有香客問我账劲,道長(zhǎng),這世上最難降的妖魔是什么金抡? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任瀑焦,我火速辦了婚禮,結(jié)果婚禮上梗肝,老公的妹妹穿的比我還像新娘榛瓮。我一直安慰自己,他們只是感情好巫击,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布禀晓。 她就那樣靜靜地躺著,像睡著了一般坝锰。 火紅的嫁衣襯著肌膚如雪粹懒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天顷级,我揣著相機(jī)與錄音凫乖,去河邊找鬼。 笑死弓颈,一個(gè)胖子當(dāng)著我的面吹牛帽芽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翔冀,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼导街,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了橘蜜?” 一聲冷哼從身側(cè)響起菊匿,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎计福,沒想到半個(gè)月后跌捆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡象颖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年佩厚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片说订。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抄瓦,死狀恐怖潮瓶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钙姊,我是刑警寧澤毯辅,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站煞额,受9級(jí)特大地震影響思恐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膊毁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一胀莹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧婚温,春花似錦描焰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嵌巷,卻和暖如春萄凤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搪哪。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工靡努, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晓折。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓惑朦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親漓概。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漾月,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 前言 最近離職了,可以盡情熬夜寫點(diǎn)總結(jié),不用擔(dān)心第二天上班爽并蛋疼著胃珍,這篇的主角 RunLoop 一座大山梁肿,涵蓋的...
    zerocc2014閱讀 12,378評(píng)論 13 67
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的,也是非常重要的觅彰, 在面試過程中是經(jīng)常會(huì)被問到的吩蔑, ...
    made_China閱讀 1,211評(píng)論 0 7
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的,也是非常重要的填抬, 在面試過程中是經(jīng)常會(huì)被問到的烛芬, ...
    SOI閱讀 21,821評(píng)論 3 63
  • RunLoop的定義與概念RunLoop的主要作用main函數(shù)中的RunLoopRunLoop與線程的關(guān)系RunL...
    __silhouette閱讀 1,014評(píng)論 0 6
  • 喵咪敏閱讀 183評(píng)論 0 0