CFRunLoop源码分析笔记

    xiaoxiao2021-03-25  61

      之前看过不少别人博客里对CFRunLoop源码的分析,但自己一直没有去看过,今天回顾相关知识时,决定自己去看看相关的源码实现,确实又有了一些新的认识与收获.

    CFRunLoopRun、CFRunLoopRunInMode

    首先是两个简单的入口函数

    //两个函数分别是让runloop跑在kCFRunLoopDefaultMode下,与让runloop跑在指定mode下 //两个函数区别不大,最终都调用CFRunLoopRunSpecific /*runloop同时只能跑在一个mode下,切换mode,要退出当前runloop 什么叫退出当前runloop?所谓的退出,通过源码有了更直观的认识,其实就是传递不同的modeName, 一遍一遍的跑CFRunLoopRunSpecific->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); }

    CFRunLoopRunSpecific

    /* 参数1:传入runloop对象,实际传入的都是CFRunLoopGetCurrent 参数2:传入当前要运行的mode名称 参数3:runloop的超时时间 参数4:主要__CFRunLoopRun会用到,后面说 */ SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ //得到当前的mode对象 CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false); //看看是不是一个空mode,后面会简单分析__CFRunLoopModeIsEmpty实现 if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) //通知进入kCFRunLoopEntry状态,,后面会简单看看__CFRunLoopDoObservers实现 if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); //进入关键函数,__CFRunLoopRun result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode); //通知进入kCFRunLoopExit状态 if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); return result; }

    看看几个重要相关函数

    __CFRunLoopModeIsEmpty

    //就是看看这个mode里有没有source0、source1、timer,只要存在source0或source1或timer就不是空的.同时看看这个mode是不是属于当前的runloop static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) { if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false; if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false; if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false; struct _block_item *item = rl->_blocks_head; while (item) { struct _block_item *curr = item; item = item->_next; Boolean doit = false; if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) { doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name)); } else { doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name)); } if (doit) return false; } return true; }

    __CFRunLoopDoObservers

    //调用observer回调 //原来用过添加obserber监听runloop状态,在特定状态下执行相关逻辑,现在通过源码,看到了相关的具体实现 static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */ //遍历rlm->_observers,放到collectedObservers数组中 for (CFIndex idx = 0; idx < cnt; idx++) { CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx); if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo); } } //遍历collectedObservers,调用rlo->_callout,外部设置好的CFRunLoopObserverRef回调函数 /*回顾一下添加obserber监听runloop状态的代码,两部分就对应上了 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFStringRef runLoopMode = kCFRunLoopDefaultMode; //此处传入的block应该就是赋值给rlo->_callout CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity _) { }); //observer被放到了rlm->_observers数组中 CFRunLoopAddObserver(runLoop, observer, runLoopMode); */ for (CFIndex idx = 0; idx < obs_cnt; idx++) { CFRunLoopObserverRef rlo = collectedObservers[idx]; __CFRunLoopObserverLock(rlo); if (__CFIsValid(rlo)) { //调用rlo->_callout,外部设置好的CFRunLoopObserverRef回调函数 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info); } else { } } }

    __CFRunLoopServiceMachPort

    static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_port_t *livePort, mach_msg_timeout_t timeout, voucher_mach_msg_state_t *voucherState, voucher_t *voucherCopy, CFRunLoopRef rl, CFRunLoopModeRef rlm)

    这个函数可以监听Mach ports,  soure1、timer、CGD都是借助Mach ports与runloop通信的。

    当timeout参数为0时,立刻返回当前是否存在未处理的soure1、timer或GCD任务,通过livePort返回

    当timeout参数不为0时,会一直处于监听状态,直到产生一个任务

    __CFRunLoopRun

    static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { uint64_t startTSR = mach_absolute_time(); //依赖GCDtimer实现超时机制 dispatch_source_t timeout_timer = NULL; struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context)); //参数CFTimeInterval seconds就是外部设置的超时时间 if (seconds <= 0.0) { // instant timeout seconds = 0.0; timeout_context->termTSR = 0ULL; } else if (seconds <= TIMER_INTERVAL_LIMIT) { 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; 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; //retVal只要为0,runloop就一直在当前mode下循环 int32_t retVal = 0; //进入runloop循环 do { __CFPortSet waitSet = rlm->_portSet; __CFRunLoopUnsetIgnoreWakeUps(rl); //通知observer kCFRunLoopBeforeTimers kCFRunLoopBeforeSources if (rlm->_observerMask & kCFRunLoopBeforeTimers) { __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); } if (rlm->_observerMask & kCFRunLoopBeforeSources) { __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); } __CFRunLoopDoBlocks(rl, rlm); //处理source0,如果有source0被处理,sourceHandledThisLoop = true /*returnAfterSourceHandled(stopAfterHandle)参数作用:看了一下__CFRunLoopDoSources0的实现 好像是如果有一组source0要处理时,如果stopAfterHandle设置为true,则只处理第一个 */ Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle); if (sourceHandledThisLoop) { __CFRunLoopDoBlocks(rl, rlm); } Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR); if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) { msg = (mach_msg_header_t *)msg_buffer; //是否有source1或timer或mainDispatch if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL, rl, rlm)) { //goto label:handle_msg //有source1或timer或mainDispatch goto handle_msg; } } didDispatchPortLastTime = false; //根据poll决定是否通知kCFRunLoopBeforeWaiting if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent(); //进入循环等待 do { msg = (mach_msg_header_t *)msg_buffer; //是否有source1或timer或mainDispatch //注意poll对timeout参数影响 __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy, rl, rlm); 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); //循环等待 rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart)); //根据poll决定是否通知kCFRunLoopAfterWaiting if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); //上面,如果有source1/timer/mainDispatch直接跳转到这里,label:handle_msg handle_msg handle_msg:; __CFRunLoopSetIgnoreWakeUps(rl); if (MACH_PORT_NULL == livePort) { CFRUNLOOP_WAKEUP_FOR_NOTHING(); cf_trace(KDEBUG_EVENT_CFRL_WAKEUP_FOR_NOTHING, rl, rlm, livePort, 0); // handle nothing } else if (livePort == rl->_wakeUpPort) { CFRUNLOOP_WAKEUP_FOR_WAKEUP(); cf_trace(KDEBUG_EVENT_CFRL_WAKEUP_FOR_WAKEUP, rl, rlm, livePort, 0); // do nothing on Mac OS } //有timer要处理 else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); cf_trace(KDEBUG_EVENT_CFRL_WAKEUP_FOR_TIMER, rl, rlm, livePort, 0); if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) { // Re-arm the next timer, because we apparently fired early __CFArmNextTimerInMode(rlm, rl); //有timer要处理 } } else if (livePort == dispatchPort) { //有dispatch_main_queue任务要处理 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); } else { //处理soure1 CFRUNLOOP_WAKEUP_FOR_SOURCE(); cf_trace(KDEBUG_EVENT_CFRL_WAKEUP_FOR_SOURCE, rl, rlm, 0, 0); // Despite the name, this works for windows handles as well CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort); } /* --- BLOCKS --- */ #if TARGET_OS_MAC if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg); #endif __CFRunLoopDoBlocks(rl, rlm); //stopAfterHandle设置为true时,有source0/1被处理了,就退出当前runloop 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)) { //mode中都没有source0、source1、timer了,runloop完成 retVal = kCFRunLoopRunFinished; } } while (0 == retVal); /*retVal != kCFRunLoopRunHandledSource/kCFRunLoopRunTimedOut/ __CFRunLoopUnsetStopped/kCFRunLoopRunFinished runloop就一直在当前mode状态下循环*/ return retVal; }

    Mark:

    __CFRunLoopDoBlocks: 可以使用 ​CFRunLoopPerformBlock​ 函数往 run loop 中添加 blocks mach_port机制不仅限于source1唤醒runloop, dispatch_main_queue、timer、CFRunLoopWakeUp等都有对应的port唤醒runloop __CFRunLoopServiceMachPort函数用于监听port,内部依赖mach_msg函数(MACH_RCV_MSG接收消息)

    static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_port_t *livePort, mach_msg_timeout_t timeout, voucher_mach_msg_state_t *voucherState, voucher_t *voucherCopy, CFRunLoopRef rl, CFRunLoopModeRef rlm)

    mach_port_name_t  port: 要监听的ports

    mach_port_t  livePort: 接收将要处理的msg对应的port

    mach_msg_timeout_t  timeout: 在 timeout 之前如果没有读到 msg,当前线程会一直处于休眠状态.传0时不进入睡眠.

    CFRunLoopRef rl: runloop对象

    CFRunLoopModeRef rlm: mode对象

     

    逻辑流程图

      逻辑执行都是在beforeSource或afterWating之后的以下两种情况下,runloop会跳过Waiting状态 在一次runloop循环开始是有source0被处理了,poll变量为true .当poll为true时,不会通知before(after)Waiting,同时第二次__CFRunLoopServiceMachPort的timeout为0,也就是立即返回,不睡眠在处理source0后,通过mach port发现存在mainDispatch任务,会goto直接到最后的处理阶段beforeWaiting及afterWaiting之前是“睡眠”状态,属于空闲timer/mainDispatch/souce1任务每次循环只执行其中一种
    转载请注明原文地址: https://ju.6miu.com/read-32311.html

    最新回复(0)