RunLoop源码解析(一)

作者: 大鹏鸟 | 来源:发表于2018-01-04 16:22 被阅读137次

    CFRuntimeClass动态创建一个类所需要的信息

    enum {
        _kCFRuntimeNotATypeID = 0
    };
    //和CFRuntimeClass的version做位与操作,用来定义动态创建的类需要的一些可选函数指针,如果不符合要求,程序会报错,并返回,具体的操作可一查看后面的动态注册类的函数_CFRuntimeRegisterClass,_kCFRuntimeNotATypeID,表示注册失败
    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; // 类名,必须要有,否则会终止程序
        void (*init)(CFTypeRef cf); //初始化,会在函数_CFRuntimeCreateInstance和_CFRuntimeInitInstance里调用
        CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf);  //拷贝,应该一直为空,因为一般的CF对象不会被拷贝
        void (*finalize)(CFTypeRef cf);  //最后的,用来释放资源
        Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2);  //判断是否相等
        CFHashCode (*hash)(CFTypeRef cf);  //该类所代表的哈希码
    //hash和equal函数必须满足条件: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动态注册一个类,并返回该类在注册列表中的索引位置

    CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) {
    // className must be pure ASCII string, non-null
        //如果version和枚举_kCFRuntimeCustomRefCount按位于得到的是真,但是函数指针refcount却为空,则不满足动态注册的条件
        if ((cls->version & _kCFRuntimeCustomRefCount) && !cls->refcount) {
           CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'.  Program will crash soon."), cls->className);
           return _kCFRuntimeNotATypeID;
        }
        __CFLock(&__CFBigRuntimeFunnel);
        //如果已经注册了的类型的个数大于了CoreFoundation允许的最大可注册类型个数,则不允许注册该类
        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其实就是该类在动态注册列表中的索引位置
        __CFUnlock(&__CFBigRuntimeFunnel);
        return typeID;
    }
    

    CFRunLoopGetTypeID,获取每个类的唯一编号,该编号是该类在注册列表中的索引位置

    //单例,只会运行一次
    CFTypeID CFRunLoopGetTypeID(void) {
        static dispatch_once_t initOnce;
        dispatch_once(&initOnce, ^{
            __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass);  //注册runloop类,类名为CFRunLoop,并返回该类型的typeID
            __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); //注册runloop的mode,类名为CFRunLoopMode,并返回其typeID
        });
        return __kCFRunLoopTypeID;
    }
    

    _CFRuntimeCreateInstance根据传入的typeID,开辟内存空间,并返回其开始位置指针

    CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) {
        if (__CFRuntimeClassTableSize <= typeID) HALT; //如果该typeID超过了注册列表的最大尺寸,则退出程序
        CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); //判断输入的typeID是有效的
        CFRuntimeClass *cls = __CFRuntimeClassTable[typeID]; //根据typeID这个索引获取到之前注册的类
        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; //保证所占用的位数是16的倍数 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;              // 每次运行的一些状态数据reset for runs of the run loop
        pthread_t _pthread;   //当前创建runloop时的线程
        uint32_t _winthread;
        CFMutableSetRef _commonModes;  //存放mode状态,默认会添加一个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;  //创建一个临时的mode,用于查找
        memset(&srlm, 0, sizeof(srlm));
        _CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
        srlm._name = modeName;
        rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);  //查找当前runloop中是否存在srlm的mode
        if (NULL != rlm) { //如果找到了,则直接返回找到的,否则继续后面的,对前面的rlm进行创建
        __CFRunLoopModeLock(rlm);
        return rlm;
        }
        if (!create) {
        return NULL;
        }
        rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
        if (NULL == rlm) {
        return NULL;
        }
        __CFRunLoopLockInit(&rlm->_lock);
        rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
        rlm->_stopped = false;
        rlm->_portToV1SourceMap = NULL;
        rlm->_sources0 = NULL;
        rlm->_sources1 = NULL;
        rlm->_observers = NULL;
        rlm->_timers = NULL;
        rlm->_observerMask = 0;
        rlm->_portSet = __CFPortSetAllocate();
        rlm->_timerSoftDeadline = UINT64_MAX;
        rlm->_timerHardDeadline = UINT64_MAX;
        
        kern_return_t ret = KERN_SUCCESS;
    #if USE_DISPATCH_SOURCE_FOR_TIMERS
        rlm->_timerFired = false;
        rlm->_queue = _dispatch_runloop_root_queue_create_4CF("Run Loop Mode Queue", 0);
        mach_port_t queuePort = _dispatch_runloop_root_queue_get_port_4CF(rlm->_queue);
        if (queuePort == MACH_PORT_NULL) CRASH("*** Unable to create run loop mode queue port. (%d) ***", -1);
        rlm->_timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, rlm->_queue);
        
        __block Boolean *timerFiredPointer = &(rlm->_timerFired);
        dispatch_source_set_event_handler(rlm->_timerSource, ^{
            *timerFiredPointer = true;
        });
        
        // 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创建runloop

    //根据线程创建runloop
    static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
        CFRunLoopRef loop = NULL;
        CFRunLoopModeRef rlm;
        //用整个runloop所要占用的内存的大小减去减去结构体CFRuntimeBase的大小,为什么要减去呢?这样不就少了吗?其实在后面的方法_CFRuntimeCreateInstance中又加回来了:CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef));
        uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
        //创建runloop,并设置同一个typeID,方法_CFRuntimeCreateInstance返回的是CFRuntimeBase类型的指针
        loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL);
        if (NULL == loop) {
        return NULL;
        }
        (void)__CFRunLoopPushPerRunData(loop); //初始化每次循环时的数据
        __CFRunLoopLockInit(&loop->_lock);
        loop->_wakeUpPort = __CFPortAllocate();  //创建唤醒监听端口
        if (CFPORT_NULL == loop->_wakeUpPort) HALT; //如果没有唤醒端口,则程序退出
        __CFRunLoopSetIgnoreWakeUps(loop);  //不忽略唤醒
        loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
        CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);  //默认添加一个运行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)) {  //判断当前线程是否为空,如果为空,则获取主线程传入
        t = pthread_main_thread_np();
        }
        __CFLock(&loopsLock);
        if (!__CFRunLoops) {  //如果当前储存runloop的字典不存在,则创建
            __CFUnlock(&loopsLock);
            CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); //创建字典
            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);
        }
        //在当前runloop中,以当前线程为key查找runloop
        CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
        __CFUnlock(&loopsLock);
        if (!loop) { //如果没找到,则创建
            CFRunLoopRef newLoop = __CFRunLoopCreate(t);
            __CFLock(&loopsLock);
            //再次查找(为什么呢?)
            loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
            if (!loop) {
                CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); //以线程为key,runloop为value储存
                loop = newLoop;
            }
                // don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
            __CFUnlock(&loopsLock);
            CFRelease(newLoop);
        }
    //注册销毁回调
        if (pthread_equal(t, pthread_self())) {  //如果传入的线程和当前线程是相同的(一般是相同的)
            _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);  //将创建的runloop储存在__CFTSDTable的data数据中,__CFTSDKeyRunLoop为索引,其类型为__CFTSDKeyAutoreleaseData1
            if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
                _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
            }
        }
        return loop;
    }
    

    _CFGetTSD和_CFSetTSD(在CFPlatform.c文件中)

    这部分是和线程相关的操作,以及变量的释放回调处理,其他的表示看不懂了

    // 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获取当前线程的runloop

    CFRunLoopRef CFRunLoopGetCurrent(void) {
        CHECK_FOR_FORK();
        CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
        if (rl) return rl;
        return _CFRunLoopGet0(pthread_self());
    }
    

    根据上面的分析,会做如下操作:

    • 通过_CFGetTSD先在__CFTSDTable表中查找,如果存在,则直接返回;
    • 通过方法_CFRunLoopGet0传入当前线程查找。如果存储线程和runloop的字典__CFRunLoops不存在,则创建;然后调用方法__CFRunLoopCreate传入主线程创建属于主线程的runloop,以线程为key,runloop为value储存在字典中;
    • 如果字典__CFRunLoops存在,或者已经创建了,则在字典中以当前线程为key进行查找
    • 如果该runloop不存在,则创建。注意,接着会再次查找自带呢中是否存在属于该线程的runloop,如果不存在,才会保存下来;
    • 判断当前线程和所传入的线程是否相同,如果相同,则保存在__CFTSDTable中,并注册回调释放函数__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;
    }
    

    和获取当前线程不同的地方在于刚开始,获取主线程的runloop并不会去__CFTSDTable结构体的相关数组中查找,因为主线程的runloop是个静态static变量,如果该静态变量为空,则开始调用_CFRunLoopGet0方法,传入主线程查找,紧接着的和获取当前线程相同,不再赘述。

    __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); //创建一个新的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);  //执行source的perform函数,并把info当作参数传入
                        CHECK_FOR_FORK();
                        sourceHandled = true;
                    } else {
                        __CFRunLoopSourceUnlock(rls);
                    }
                } else {
                    __CFRunLoopSourceUnlock(rls);
                }
            } else {
                CFIndex cnt = CFArrayGetCount((CFArrayRef)sources);
                //排序
                CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
                for (CFIndex idx = 0; idx < cnt; idx++) {
                    CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx);
                    __CFRunLoopSourceLock(rls);
                    if (__CFRunLoopSourceIsSignaled(rls)) {
                            __CFRunLoopSourceUnsetSignaled(rls);
                            if (__CFIsValid(rls)) {
                                __CFRunLoopSourceUnlock(rls);
                                __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);//执行source的perform函数,并把info当作参数传入
                                CHECK_FOR_FORK();
                                sourceHandled = true;
                            } else {
                                __CFRunLoopSourceUnlock(rls);
                            }
                        } else {
                            __CFRunLoopSourceUnlock(rls);
                        }
                    if (stopAfterHandle && sourceHandled) {。//处理完一个事儿就返回
                        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();  //获取当前时间
    
        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;
         };
         */
        //开辟一个结构体__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
            //获取主线程,如果能获取到,则获取主队列,否则获取一个后台运行队列
            dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
            //创建一个时间源,并启动
            timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
                dispatch_retain(timeout_timer);
            timeout_context->ds = timeout_timer;
            timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
            timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
            dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
            dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
            dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
            //因为dispatch_time函数的第二个参数单位是纳秒,所以这里是转换单位,创建开始时间
            uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
            //(timer, 开始时间, 循环间隔, 精度),这里允许的误差为1000纳秒,循环间隔为永久,即永不循环
            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;
        }
        //以上说明,如果时间范围(相对于目前时间来说)大于0但是小于最大时间,则会默认启动一个定时器,时间间隔为(循环周期)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);
            //发送通知
            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;
            //发送将要进入等待状态通知
            if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
            //进入等待,开始睡眠
            __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);
            //发送通知,表示将要开始处理事件了
            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的执行情况

    SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {     /* DOES CALLOUT */
        CHECK_FOR_FORK();
        if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;  //runloop判断是否该runloop已经被标记为准备释放,如果是,则返回runloop运行状态为完成
        __CFRunLoopLock(rl);
        //通过runloop的modeName查找当前mode,在该过程中,如果找到了,则会直接返回,否则会新创建一个返回
        CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
        //判断当前模式下的runloop里的source1、source0、timer等事件是否为空,如果为空,则返回运行状态为完成
        if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
            Boolean did = false;
            if (currentMode) __CFRunLoopModeUnlock(currentMode);
            __CFRunLoopUnlock(rl);
            return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
        }
        volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
        CFRunLoopModeRef previousMode = rl->_currentMode;
        rl->_currentMode = currentMode;
        int32_t result = kCFRunLoopRunFinished;  //默认的运行状态是完成
        //根据注册的观察选项和不同的状态做位与,用来查看是否注册了该状态的通知,如果注册了,则发送通知
        if (currentMode->_observerMask & kCFRunLoopEntry )
            __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);  //发送进入runloop通知
        //正式处理事件
        result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
        if (currentMode->_observerMask & kCFRunLoopExit )
            __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);  //发送退出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);
    }
    

    两个的区别仅仅在于后者只调用一次,并返回结果,而前者是多次调用,直到不满足循环条件。

    相关文章

      网友评论

        本文标题:RunLoop源码解析(一)

        本文链接:https://www.haomeiwen.com/subject/wlimgxtx.html