CFRunLoop

数据结构

__CFRunLoopMode

 struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;  /* must have the run loop locked before locking 
    this */
//mode名
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
//source0 源
    CFMutableSetRef _sources0;
//source1 源
    CFMutableSetRef _sources1;
//observer 源
    CFMutableArrayRef _observers;
//timer 源
    CFMutableArrayRef _timers;
 
//mach port 到 mode的映射,为了在runloop主逻辑中过滤runloop自己的port消息。
    CFMutableDictionaryRef _portToV1SourceMap;
 
//记录了所有当前mode中需要监听的port,作为调用监听消息函数的参数。
    __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
//使用 mk timer, 用到的mach port,和source1类似,都依赖于mach port
    mach_port_t _timerPort;
    Boolean _mkTimerArmed;
#endif
//timer触发的理想时间
    uint64_t _timerSoftDeadline; /* TSR */
//timer触发的实际时间,理想时间加上tolerance(偏差)
    uint64_t _timerHardDeadline; /* TSR */
};

__CFRunLoop

struct __CFRunLoop {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;          /* locked for accessing mode list */
 
//用于手动将当前runloop线程唤醒,通过调用CFRunLoopWakeUp完成,
//CFRunLoopWakeUp会向_wakeUpPort发送一条消息
    __CFPort _wakeUpPort;           // used for CFRunLoopWakeUp 
    Boolean _unused;
    volatile _per_run_data *_perRunData; // reset for runs of the run loop
    pthread_t _pthread;
    uint32_t _winthread;
//记录了当前runloop中所有的mode名
    CFMutableSetRef _commonModes;
//记录了当前runloop中所有注册到commonMode中的源
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
//记录了添加到runloop中的block,它也可以像其他源一样被runloop处理,
//通过CFRunLoopPerformBlock可向runloop中添加block任务。
    struct _block_item *_blocks_head;
    struct _block_item *_blocks_tail;
    CFTypeRef _counterpart;
};

__CFRunLoops

//全局字典,保存线程和对应runloop之间的关系
static CFMutableDictionaryRef __CFRunLoops = NULL;

函数:

__CFRunLoopRun

static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, 
    CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef 
    previousMode) {
    //获取系统启动之后cpu嘀嗒数
    uint64_t startTSR = mach_absolute_time();
    if (__CFRunLoopIsStopped(rl)) {
        __CFRunLoopUnsetStopped(rl);
    return kCFRunLoopRunStopped;
    } else if (rlm->_stopped) {
    rlm->_stopped = false;
    return kCFRunLoopRunStopped;
    }
     
    //mach 端口, 线程之间通信的对象
    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();
     
    //使用GCD实现runloop超时功能
    dispatch_source_t timeout_timer = NULL;
    struct __timeout_context *timeout_context = (struct __timeout_context *)
    malloc(sizeof(*timeout_context));
    //seconds是设置的runloop超时时间
    if (seconds <= 0.0) { // instant timeout
        seconds = 0.0;
        timeout_context->termTSR = 0ULL;
    } else if (seconds <= TIMER_INTERVAL_LIMIT) {
    dispatch_queue_t queue = dispatch_get_global_queue(
        DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_OVERCOMMIT);
    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);
        uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds)
         * 1000000000ULL);
        dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), 
        DISPATCH_TIME_FOREVER, 1000ULL);
        dispatch_resume(timeout_timer);
    } else { // infinite timeout
        seconds = 9999999999.0;
        timeout_context->termTSR = UINT64_MAX;
    }
    Boolean didDispatchPortLastTime = true;
    int32_t retVal = 0;
    do {
        uint8_t msg_buffer[3 * 1024];
        mach_msg_header_t *msg = NULL;
        mach_port_t livePort = MACH_PORT_NULL;
    __CFPortSet waitSet = rlm->_portSet;
        __CFRunLoopUnsetIgnoreWakeUps(rl);
        //rl->_perRunData->ignoreWakeUps = 0x0;
        if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers
        (rl, rlm, kCFRunLoopBeforeTimers);
        if (rlm->_observerMask & kCFRunLoopBeforeSources) 
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
//Perform blocks queued by CFRunLoopPerformBlock;
    __CFRunLoopDoBlocks(rl, rlm);
        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, 
            stopAfterHandle);
        //如果rl中有source0消息
        if (sourceHandledThisLoop) {
            //处理block  Perform blocks newly queued by CFRunLoopPerformBlock;
            __CFRunLoopDoBlocks(rl, rlm);
       }
//poll标志着有没有处理source0的消息,如果没有则为false,反之为true
        Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->
            termTSR);
        //第一次进来不走这个逻辑,didDispatchPortLastTime是true
        if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) {
            msg = (mach_msg_header_t *)msg_buffer;
            //__CFRunLoopServiceMachPort用于接受指定端口(一个也可以是多个)
            //的消息,最后一个参数代表当端口无消息的时候是否休眠,0是立刻返回不休眠,
            //TIMEOUT_INFINITY代表休眠
            //处理通过GCD派发到主线程的任务,这些任务优先级最高会被最先处理
            if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(
                msg_buffer), &livePort, 0)) {
                goto handle_msg;
            }
        }
        didDispatchPortLastTime = false;
//根据之前有没有处理过source0消息,来判断如果也没有source1消息的时候是否让线程进入睡眠,这里处
//理observer源,如果睡眠则通知Observer进入睡眠。
    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);
    if (kCFUseCollectableAllocator) {
        objc_clear_stack(0);
        memset(msg_buffer, 0, sizeof(msg_buffer));
    }
    msg = (mach_msg_header_t *)msg_buffer;
    //如果poll为null,且waitset中无port有消息,线程进入休眠
    __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, 
    poll ? 0 : TIMEOUT_INFINITY);
     
    __CFRunLoopLock(rl);
    __CFRunLoopModeLock(rlm);
    // 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);
    //处理observer源,线程醒来
    if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) 
    __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
        handle_msg:;
        __CFRunLoopSetIgnoreWakeUps(rl);
        if (MACH_PORT_NULL == livePort) {
            CFRUNLOOP_WAKEUP_FOR_NOTHING();
            // handle nothing
//通过CFRunloopWake将当前线程唤醒
        } else if (livePort == rl->_wakeUpPort) {
            CFRUNLOOP_WAKEUP_FOR_WAKEUP();
            // do nothing on Mac OS
        }
//处理timer源
        else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->
            _timerPort) {
            CFRUNLOOP_WAKEUP_FOR_TIMER();
            if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
                // Re-arm the next timer
                __CFArmNextTimerInMode(rlm, rl);
            }
        }
//通过GCD派发给主线程的任务
        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 {
//通过macPort给当前线程派发消息,处理source1
            CFRUNLOOP_WAKEUP_FOR_SOURCE();
            // Despite the name, this works for windows handles as well
            //过滤macPort消息,有一些消息不一定是runloop中注册的,这里只处理runloop中注册的
            //消息,在rlm->_portToV1SourceMap通过macPort找有没有对应的runloopMode
            CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, 
                rlm, livePort);
            if (rls) {
                mach_msg_header_t *reply = NULL;
                sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg,
                 msg->msgh_size, &reply) || sourceHandledThisLoop;
                if (NULL != reply) {
                    //当前线程处理完source1,给发消息的线程反馈消息, 
                    //MACH_SEND_MSG表示给replay端口发送消息
                    (void)mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, 
                        MACH_PORT_NULL, 0, MACH_PORT_NULL);
                    CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply);
                }
           }
        }
    if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
         
    __CFRunLoopDoBlocks(rl, rlm);
    if (sourceHandledThisLoop && stopAfterHandle) {
        retVal = kCFRunLoopRunHandledSource;
    } else if (timeout_context->termTSR < mach_absolute_time()) {
        //runloop超时时间到
            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;
    }
    } while (0 == retVal);
    if (timeout_timer) {
        dispatch_source_cancel(timeout_timer);
        dispatch_release(timeout_timer);
    } else {
        free(timeout_context);
    }
    return retVal;
}

CFRunLoopAddSource

void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, 
    CFStringRef modeName) {    /* DOES CALLOUT */
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    if (!__CFIsValid(rls)) return;
    Boolean doVer0Callout = false;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
        //par1 : 处理commonModeItmes的逻辑
/*rl->_commonModes的作用是记录了当前runloop中标记为commonMode的mode,rl->_commonModeI
tems记录了当前runloop中注册到commonMode中的源
两者用来处理跟commonMode相关的逻辑,比如当一个mode被标记为commonMode的时候,会将rl->_common
ModeItems中的源添加到新的mode当中去,在当前mode下这些源的消息就会被
监听并处理。例如一个timer被注册到commonMode中,那么在所有被标记为commonMode的mode中都会处理该timer的消息。
*/
    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault
        , rl->_commonModes) : NULL;
    if (NULL == rl->_commonModeItems) {
        rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
    }
    CFSetAddValue(rl->_commonModeItems, rls);
    if (NULL != set) {
        CFTypeRef context[2] = {rl, rls};
        /* add new item to all common-modes */
        //对每一个mode,调用part2的逻辑
        CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
        CFRelease(set);
    }
    } else {
    //part2 : 处理某个具体的mode中addSource的逻辑
    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
    if (NULL != rlm && NULL == rlm->_sources0) {
        rlm->_sources0 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &
            kCFTypeSetCallBacks);
        rlm->_sources1 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &
            kCFTypeSetCallBacks);
        rlm->_portToV1SourceMap = CFDictionaryCreateMutable(
            kCFAllocatorSystemDefault, 0, NULL, NULL);
    }
    if (NULL != rlm && !CFSetContainsValue(rlm->_sources0, rls) && !
    CFSetContainsValue(rlm->_sources1, rls)) {
        if (0 == rls->_context.version0.version) {
            CFSetAddValue(rlm->_sources0, rls);
        } else if (1 == rls->_context.version0.version) {
            CFSetAddValue(rlm->_sources1, rls);
        __CFPort src_port = rls->_context.version1.getPort(rls->_context.
            version1.info);
        if (CFPORT_NULL != src_port) {
        //rlm->_portToV1SourceMap是port到source1的映射,
        //为了在runloop主逻辑中过滤runloop自己的port消息。
            CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(
                uintptr_t)src_port, rls);
        //rml->_portSet记录了所有当前mode中需要监听的port,作为调用监听消息函数的参数。
            __CFPortSetInsert(src_port, rlm->_portSet);
            }
        }
        __CFRunLoopSourceLock(rls);
        if (NULL == rls->_runLoops) {
            rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &
            kCFTypeBagCallBacks); // sources retain run loops!
        }
        CFBagAddValue(rls->_runLoops, rl);
        __CFRunLoopSourceUnlock(rls);
        if (0 == rls->_context.version0.version) {
            if (NULL != rls->_context.version0.schedule) {
                doVer0Callout = true;
            }
        }
    }
        if (NULL != rlm) {
        __CFRunLoopModeUnlock(rlm);
    }
    }
    __CFRunLoopUnlock(rl);
    if (doVer0Callout) {
        // although it looses some protection for the source, we have no 
        //choice but
        // to do this after unlocking the run loop and mode locks, to avoid 
        //deadlocks
        // where the source wants to take a lock which is already held in 
        //another
        // thread which is itself waiting for a run loop/mode lock
    rls->_context.version0.schedule(rls->_context.version0.info, rl, modeName);   /* CALLOUT */
    }
}

CFRunLoopRemoveSource

void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, 
    CFStringRef modeName) { /* DOES CALLOUT */
    CHECK_FOR_FORK();
    Boolean doVer0Callout = false, doRLSRelease = false;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
        if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->
            _commonModeItems, rls)) {
            CFSetRef set = rl->_commonModes ? CFSetCreateCopy(
                kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
            CFSetRemoveValue(rl->_commonModeItems, rls);
            if (NULL != set) {
            CFTypeRef context[2] = {rl, rls};
            /* remove new item from all common-modes */
            CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (
                void *)context);
            CFRelease(set);
            }
        }
    } else {
    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
    if (NULL != rlm && ((NULL != rlm->_sources0 && CFSetContainsValue(rlm->
        _sources0, rls)) || (NULL != rlm->_sources1 && CFSetContainsValue(rlm->
            _sources1, rls)))) {
        //source0或者source1中的一种
        CFRetain(rls);
        if (1 == rls->_context.version0.version) {
        __CFPort src_port = rls->_context.version1.getPort(rls->_context.
            version1.info);
                if (CFPORT_NULL != src_port) {
            CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(
                uintptr_t)src_port);
                    __CFPortSetRemove(src_port, rlm->_portSet);
                }
        }
        CFSetRemoveValue(rlm->_sources0, rls);
        CFSetRemoveValue(rlm->_sources1, rls);
            __CFRunLoopSourceLock(rls);
            if (NULL != rls->_runLoops) {
                CFBagRemoveValue(rls->_runLoops, rl);
            }
            __CFRunLoopSourceUnlock(rls);
        if (0 == rls->_context.version0.version) {
            if (NULL != rls->_context.version0.cancel) {
                doVer0Callout = true;
            }
        }
        doRLSRelease = true;
    }
        if (NULL != rlm) {
        __CFRunLoopModeUnlock(rlm);
    }
    }
    __CFRunLoopUnlock(rl);
    if (doVer0Callout) {
        // although it looses some protection for the source, we have no choice but
        // to do this after unlocking the run loop and mode locks, to avoid deadlocks
        // where the source wants to take a lock which is already held in another
        // thread which is itself waiting for a run loop/mode lock
        rls->_context.version0.cancel(rls->_context.version0.info, rl, modeName); /* CALLOUT */
    }
    if (doRLSRelease) CFRelease(rls);
}

CFRunLoopAddTimer

void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef 
    modeName) {   
    CHECK_FOR_FORK();
    if (__CFRunLoopIsDeallocating(rl)) return;
    if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) 
    return;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault
        , rl->_commonModes) : NULL;
    if (NULL == rl->_commonModeItems) {
        rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0,
         &kCFTypeSetCallBacks);
    }
    CFSetAddValue(rl->_commonModeItems, rlt);
    if (NULL != set) {
        CFTypeRef context[2] = {rl, rlt};
        /* add new item to all common-modes */
        CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)
        context);
        CFRelease(set);
    }
    } else {
    CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
    if (NULL != rlm) {
            if (NULL == rlm->_timers) {
                CFArrayCallBacks cb = kCFTypeArrayCallBacks;
                cb.equal = NULL;
                rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 
                    0, &cb);
            }
    }
    if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
            __CFRunLoopTimerLock(rlt);
            if (NULL == rlt->_runLoop) {
        rlt->_runLoop = rl;
        } else if (rl != rlt->_runLoop) {
                __CFRunLoopTimerUnlock(rlt);
            __CFRunLoopModeUnlock(rlm);
                __CFRunLoopUnlock(rl);
        return;
        }
        CFSetAddValue(rlt->_rlModes, rlm->_name);
            __CFRunLoopTimerUnlock(rlt);
            __CFRunLoopTimerFireTSRLock();
            //__CFRepositionTimerInMode是添加或者删除timer,
            //这里是往rlm->_timers添加timer
            __CFRepositionTimerInMode(rlm, rlt, false);
            __CFRunLoopTimerFireTSRUnlock();
            if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
                // Normally we don't do this on behalf of clients, but for
                // backwards compatibility due to the change in timer handling...
                if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
            }
    }
        if (NULL != rlm) {
        __CFRunLoopModeUnlock(rlm);
    }
    }
    __CFRunLoopUnlock(rl);
}

__CFRunLoopFindMode

static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef 
    modeName, Boolean create) {
    CHECK_FOR_FORK();
    CFRunLoopModeRef rlm;
    struct __CFRunLoopMode srlm;
    memset(&srlm, 0, sizeof(srlm));
    _CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
    srlm._name = modeName;
    rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
    if (NULL != rlm) {
    __CFRunLoopModeLock(rlm);
    return rlm;
    }
    if (!create) {
    return NULL;
    }
    rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault,
     __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(
        CFRuntimeBase), NULL);
    if (NULL == rlm) {
    return NULL;
    }
    __CFRunLoopLockInit(&rlm->_lock);
    rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
    rlm->_stopped = false;
    rlm->_portToV1SourceMap = NULL;
    rlm->_sources0 = NULL;
    rlm->_sources1 = NULL;
    rlm->_observers = NULL;
    rlm->_timers = NULL;
    rlm->_observerMask = 0;
    rlm->_portSet = __CFPortSetAllocate();
    rlm->_timerSoftDeadline = UINT64_MAX;
    rlm->_timerHardDeadline = UINT64_MAX;
     
    kern_return_t ret = KERN_SUCCESS;
    //1
#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
    //1
#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);
     
    CFSetAddValue(rl->_modes, rlm);
    CFRelease(rlm);
    __CFRunLoopModeLock(rlm);   /* return mode locked */
    return rlm;
}  ``return` `rlm;``}`

__CFRepositionTimerInMode

static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef 
    rlt, Boolean isInArray) {
    if (!rlt) return;
     
    CFMutableArrayRef timerArray = rlm->_timers;
    if (!timerArray) return;
    Boolean found = false;
     
    // If we know in advance that the timer is not in the array (just being added now) then we can skip this search
    if (isInArray) {
        CFIndex idx = CFArrayGetFirstIndexOfValue(timerArray, CFRangeMake(0, 
            CFArrayGetCount(timerArray)), rlt);
        if (kCFNotFound != idx) {
            CFRetain(rlt);
            CFArrayRemoveValueAtIndex(timerArray, idx);
            found = true;
        }
    }
    if (!found && isInArray) return;
    CFIndex newIdx = __CFRunLoopInsertionIndexInTimerArray(timerArray, rlt);
   //timer开始计时
    CFArrayInsertValueAtIndex(timerArray, newIdx, rlt);
    __CFArmNextTimerInMode(rlm, rlt->_runLoop);
    if (isInArray) CFRelease(rlt);
}

__CFArmNextTimerInMode

static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm, CFRunLoopRef rl) {   
    uint64_t nextHardDeadline = UINT64_MAX;
    uint64_t nextSoftDeadline = UINT64_MAX;
    if (rlm->_timers) {
        // Look at the list of timers. We will calculate two TSR values; the 
//next soft and next hard deadline.
        // The next soft deadline is the first time we can fire any timer. 
//This is the fire date of the first timer in our sorted list of timers.
        // The next hard deadline is the last time at which we can fire the 
//timer before we've moved out of the allowable tolerance of the timers in our list.
        for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; 
idx++) {
            CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm
    ->_timers , idx);
            // discount timers currently firing
            if (__CFRunLoopTimerIsFiring(t)) continue;
             
            int32_t err = CHECKINT_NO_ERROR;
            uint64_t oneTimerSoftDeadline = t->_fireTSR;
            uint64_t oneTimerHardDeadline = check_uint64_add(t->_fireTSR, 
    __CFTimeIntervalToTSR(t->_tolerance), &err);
            if (err != CHECKINT_NO_ERROR) oneTimerHardDeadline = UINT64_MAX;
             
            // We can stop searching if the soft deadline for this timer exceeds the current hard deadline. Otherwise, later timers with lower tolerance could still have earlier hard deadlines.
            if (oneTimerSoftDeadline > nextHardDeadline) {
                break;
            }
             
            if (oneTimerSoftDeadline < nextSoftDeadline) {
                nextSoftDeadline = oneTimerSoftDeadline;
            }
             
            if (oneTimerHardDeadline < nextHardDeadline) {
                nextHardDeadline = oneTimerHardDeadline;
            }
        }
         
        if (nextSoftDeadline < UINT64_MAX && (nextHardDeadline != rlm->
    _timerHardDeadline || nextSoftDeadline != rlm->_timerSoftDeadline)) {
            if (CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED()) {
                CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline - 
    mach_absolute_time()));
            }
#if USE_DISPATCH_SOURCE_FOR_TIMERS
            // We're going to hand off the range of allowable timer fire date 
//to dispatch and let it fire when appropriate for the system.
            uint64_t leeway = __CFTSRToNanoseconds(nextHardDeadline - 
    nextSoftDeadline);
            dispatch_time_t deadline = __CFTSRToDispatchTime(nextSoftDeadline);
#if USE_MK_TIMER_TOO
//leeway表示timer的偏差,如果_tolerance(>=0)为0,则leeway等于0
            if (leeway > 0) {
//GCD timer
                // Only use the dispatch timer if we have any leeway
                // <rdar://problem/14447675>
                 
                // Cancel the mk timer
                if (rlm->_mkTimerArmed && rlm->_timerPort) {
                    AbsoluteTime dummy;
                    mk_timer_cancel(rlm->_timerPort, &dummy);
                    rlm->_mkTimerArmed = false;
                }
                 
                // Arm the dispatch timer
                _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, 
    deadline, DISPATCH_TIME_FOREVER, leeway);
                rlm->_dispatchTimerArmed = true;
            } else {
//mk timer,实际中是这种情况
                // Cancel the dispatch timer
                if (rlm->_dispatchTimerArmed) {
                    // Cancel the dispatch timer
                    _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, 
    DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 888);
                    rlm->_dispatchTimerArmed = false;
                }
                 
                // Arm the mk timer
                if (rlm->_timerPort) {
//timer开始运行
                    mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(
    nextSoftDeadline));
                    rlm->_mkTimerArmed = true;
                }
            }
#else
            _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline,
 DISPATCH_TIME_FOREVER, leeway);
#endif
#else
            if (rlm->_timerPort) {
                mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(
    nextSoftDeadline));
            }
#endif
        } else if (nextSoftDeadline == UINT64_MAX) {
            // Disarm the timers - there is no timer scheduled
             
            if (rlm->_mkTimerArmed && rlm->_timerPort) {
                AbsoluteTime dummy;
                mk_timer_cancel(rlm->_timerPort, &dummy);
                rlm->_mkTimerArmed = false;
            }
             
#if USE_DISPATCH_SOURCE_FOR_TIMERS
            if (rlm->_dispatchTimerArmed) {
                _dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, 
    DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 333);
                rlm->_dispatchTimerArmed = false;
            }
#endif
        }
    }
    rlm->_timerHardDeadline = nextHardDeadline;
    rlm->_timerSoftDeadline = nextSoftDeadline;
}

_CFRunLoopGet0

CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    //判断t是否是传的空,如果是当成主线程处理
    if (pthread_equal(t, kNilPthreadT)) {
        t = pthread_main_thread_np();
    }
    __CFSpinLock(&loopsLock);
//__CFRunLoops是全局存储线程和runloop关系的字典
    if (!__CFRunLoops) {
//__CFRunLoop第一次初始化
        __CFSpinUnlock(&loopsLock);
//初始化__CFRunLoop
    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
        kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
//生成主线程对应runloop
    CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
//存储到__CFRunLoop字典中
    CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
    if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&
    __CFRunLoops)) {
        CFRelease(dict);
    }
    CFRelease(mainLoop);
        __CFSpinLock(&loopsLock);
    }
//找到线程t对应的runloop
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, 
        pthreadPointer(t));
    __CFSpinUnlock(&loopsLock);
    if (!loop) {
//没有找到,创建一个
    CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFSpinLock(&loopsLock);
//??????
    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    if (!loop) {
//保存到全局字典中
        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
        loop = newLoop;
    }
        // don't release run loops inside the loopsLock, because 
        //CFRunLoopDeallocate may end up taking it --> -->
        __CFSpinUnlock(&loopsLock);
    CFRelease(newLoop);
    }
    if (pthread_equal(t, pthread_self())) {
        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(
                PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))
                __CFFinalizeRunLoop);
        }
    }
    return loop;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容