关于RunLoop部分源码的注释

Posted SSIrreplaceable

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于RunLoop部分源码的注释相关的知识,希望对你有一定的参考价值。

RunLoop源代码是开发的,是Core Fundation框架的一部分,可以在线查看和或者下载。本篇博文是对RunLoop部分源码进行注释,因本人知识有限,如有注释不妥的地方请指教。

#if DEPLOYMENT_TARGET_WINDOWS

// kNilPthreadT 为空的线程
static pthread_t kNilPthreadT =  nil, nil ;
#define pthreadPointer(a) a.p
typedef int kern_return_t;
#define KERN_SUCCESS 0

#else

// kNilPthreadT 为空的线程
static pthread_t kNilPthreadT = (pthread_t)0;
#define pthreadPointer(a) a
#define lockCount(a) a
#endif


/************************** RunLoop的获取相关代码 ****************************/

// 声明一个全局的可变字典 __CFRunLoops 用于存储每一条线程和对应的RunLoop ,
// __CFRunLoops的键key存储线程pthread_t,键对应的值value存储RunLoop
static CFMutableDictionaryRef __CFRunLoops = NULL;

// loopsLock 用于访问 __CFRunLoops 时加锁,锁的目的是:考虑线程安全问题,防止多条线程同时访问__CFRunLoops对应的内存空间
static CFLock_t loopsLock = CFLockInit;


/**
 * 这个函数中的作用是获取RunLoop,RunLoop是懒加载的
 */
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) 

    // 1. 判断t所指向的线程是否为空,如果为空,就获取当前的主线程进行赋值
    if (pthread_equal(t, kNilPthreadT)) 
        // 1.1 获取当前的主线程进行赋值
        t = pthread_main_thread_np();
    


    // 2. 处理线程安全,即加锁
    __CFLock(&loopsLock);


    // 3. 判断全局的可变字典 __CFRunLoops 是否为空
    if (!__CFRunLoops) 

        // 3.1 解锁
        __CFUnlock(&loopsLock);

        // 3.2 定义一个局部可变字典dict
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);

        // 3.3 创建一个与主线程对应的RunLoop对象mainLoop
        CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());

        // 3.4 把主线程和主运行循环mainLoop存储于字典dict
        CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);

        // 3.5 把局部创建的字典dict赋值给全局字典__CFRunLoops
        if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) 

            // 3.5.1 赋值成功后,release局部变量
            CFRelease(dict);
        

        // 3.6 存储mainLoop到字典以后撤销一次引用,即release一次mainLoop
        // 原因:mainLoop存储到字典后会自动retain
        CFRelease(mainLoop);

        // 3.7 加锁
        __CFLock(&loopsLock);
    


    // 4. 从全局的字典__CFRunLoops中获取对应于当前线程的RunLoop
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));


    // 5. 解锁
    __CFUnlock(&loopsLock);


    // 6. 如果获取不到RunLoop就创建并存储
    // 注意:在子线程中第一次获取RunLoop是获取不到的,获取不到时才去创建,这个if语句一般在子线程中第一次获取的时候才会执行
    if (!loop) 

        // 6.1 根据当前线程创建一个RunLoop
        CFRunLoopRef newLoop = __CFRunLoopCreate(t);

        // 6.2 加锁
        __CFLock(&loopsLock);

        // 6.3 再一次从全局的字典__CFRunLoops中获取对应于当前线程的RunLoop
        loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));

        // 6.4 如果还是获取不到RunLoop,就存储当前线程和刚创建的RunLoop到全局字典__CFRunLoops中
        if (!loop) 

            // 6.4.1 存储当前线程和对应的RunLoop到全局字典__CFRunLoops中
            CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);

            // 6.4.2 赋值,用于返回值
            loop = newLoop;
        


        // 6.4.3 解锁
        __CFUnlock(&loopsLock);

        // 6.4.4 release局部的newLoop
        CFRelease(newLoop);
    


    // 7. 判断是否为当前线程,如果是就注册一个回调,当线程销毁时,也销毁其对应的 RunLoop
    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);
        
    

    // 8. 返回当前线程对应的RunLoop
    return loop;



/********************************** 获取RunLoop *******************************/


/**
 * 这个函数中的作用是获取主运行循环MainRunLoop
 */
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
 */
CFRunLoopRef CFRunLoopGetCurrent(void) 
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());



/**************************** RunLoop运行的核心代码 *******************************/


/**
 * RunLoop的运行核心
 */
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) 

    // 获取系统启动后的CPU运行时间,用于控制超时时间
    uint64_t startTSR = mach_absolute_time();


    // 判断RunLoop是否已经被终止,被终止就直接退出,并返回退出原因
    if (__CFRunLoopIsStopped(rl)) 
        __CFRunLoopUnsetStopped(rl);
        return kCFRunLoopRunStopped;
     else if (rlm->_stopped) 
        rlm->_stopped = false;
        return kCFRunLoopRunStopped;
    


    // 调度端口,用于消息的传递,初始为0
    mach_port_name_t dispatchPort = MACH_PORT_NULL;
    // 判断是否是第一次在主线程中启动RunLoop
    Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
    // 如果是第一次启动RunLoop且当前RunLoop为主线程的RunLoop,那么就给分发一个队列调度端口
    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) 
        // 给运行模式的调度端口分发一个关于RunLoop的主队列端口
        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 *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
    // 如果超时时间非常小就把超时时间设为0.0秒和期限设为0
    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;
        timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
        timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
        // 设置定时器的上下文
        dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
        // 设置source的活动
        dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
        // 设置source的取消
        dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
        // 根据seconds计算超时时间
        uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
        // 设置source的超时时间
        dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
        // 开始计时
        dispatch_resume(timeout_timer);
     else  // 如果超时时间不在系统可接受的范围,就认为是无限大,且期限是无限的
        seconds = 9999999999.0;
        timeout_context->termTSR = UINT64_MAX;
    


    // 标记已经运行结束
    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;

        // 系统是WINDOWS,运行下列代码
#elif DEPLOYMENT_TARGET_WINDOWS
        HANDLE livePort = NULL;
        Boolean windowsMessageReceived = false;
#endif


        // 获取RunLoop的运行模式的集合
        __CFPortSet waitSet = rlm->_portSet;
        // 设置RunLoop可以被唤醒
        __CFRunLoopUnsetIgnoreWakeUps(rl);

        // 判断是否即将要处理定时器源,如果是就通知观察者
        if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
        // 判断是否即将要处理非定时器源,如果是就通知观察者
        if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);

        // 根据运行模式设置RunLoop
        __CFRunLoopDoBlocks(rl, rlm);

        // 处理Sources0(非基于端口的源)
        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        // Sources0处理完后,根据运行模式设置RunLoop
        if (sourceHandledThisLoop) 
            __CFRunLoopDoBlocks(rl, rlm);
        

        // 是否轮询,如何刚刚有 Sources0事件处理 或者 时间超时 就在RunLoop的下一轮循环中继续检查
        Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);


        // 如果基于端口的源有消息且超时时,才执行下列代码,第一次RunLoop中不会执行下列代码,因为didDispatchPortLastTime初始为true
        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;
            

            // 在WINDOWS系统情况下
#elif DEPLOYMENT_TARGET_WINDOWS
            if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) 
                goto handle_msg;
            
#endif
        


        // 标记运行没有结束
        didDispatchPortLastTime = false;


        // 通知观察者线程进入休眠
        if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        // 设置线程进入休眠
        __CFRunLoopSetSleeping(rl);


        // 还原RunLoop的运行模式的集合
        __CFPortSetInsert(dispatchPort, waitSet);

        // RunLoop运行模式开锁
        __CFRunLoopModeUnlock(rlm);
        // RunLoop开锁
        __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


        // 定时源处于等待时,线程进入休眠,直到收到新消息才跳出该循环,继续执行RunLoop
        do 

            if (kCFUseCollectableAllocator) 

                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) 

            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

        // 如果是在WINDOWS下,运行下列代码
#elif DEPLOYMENT_TARGET_WINDOWS
        // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages.
        __CFRunLoopWaitForMultipleObjects(waitSet, NULL, poll ? 0 : TIMEOUT_INFINITY, rlm->_msgQMask, &livePort, &windowsMessageReceived);
#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);

        // 如果是在WINDOWS下,运行下列代码
#if DEPLOYMENT_TARGET_WINDOWS
        if (windowsMessageReceived) 
            // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after
            __CFRunLoopModeUnlock(rlm);
            __CFRunLoopUnlock(rl);

            if (rlm->_msgPump) 
                rlm->_msgPump();
             else 
                MSG msg;
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) 
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                
            

            __CFRunLoopLock(rl);
            __CFRunLoopModeLock(rlm);
            sourceHandledThisLoop = true;

            // To prevent starvation of sources other than the message queue, we check again to see if any other sources need to be serviced
            // Use 0 for the mask so windows messages are ignored this time. Also use 0 for the timeout, because we're just checking to see if the things are signalled right now -- we will wait on them again later.
            // NOTE: Ignore the dispatch source (it's not in the wait set anymore) and also don't run the observers here since we are polling.
            __CFRunLoopSetSleeping(rl);
            __CFRunLoopModeUnlock(rlm);
            __CFRunLoopUnlock(rl);

            __CFRunLoopWaitForMultipleObjects(waitSet, NULL, 0, 0, &livePort, NULL);

            __CFRunLoopLock(rl);
            __CFRunLoopModeLock(rlm);
            __CFRunLoopUnsetSleeping(rl);
            // If we have a new live port then it will be handled below as normal
        


#endif


        if (MACH_PORT_NULL == livePort) 

            CFRUNLOOP_WAKEUP_FOR_NOTHING();
            // handle nothing
         else if (livePort == rl->_wakeUpPort) 

            CFRUNLOOP_WAKEUP_FOR_WAKEUP();
            // do nothing on Mac OS

#if DEPLOYMENT_TARGET_WINDOWS
            // Always reset the wake up port, or risk spinning forever
            ResetEvent(rl->_wakeUpPort);
#endif
        

        // 如果是定时器源
#if USE_DISPATCH_SOURCE_FOR_TIMERS
        // 如果运行模式的任务队列不为空,且处于活动状态
        else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) 
            CFRUNLOOP_WAKEUP_FOR_TIMER();

            // 处理定时器事件
            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();
            // 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) 

            // 唤醒RunLoop
            CFRUNLOOP_WAKEUP_FOR_DISPATCH();
            // RunLoop运行模式解锁
            __CFRunLoopModeUnlock(rlm);
            // RunLoop解锁
            __CFRunLoopUnlock(rl);

            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
#if DEPLOYMENT_TARGET_WINDOWS
            void *msg = 0;
#endif

            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);

            // RunLoop加锁
            __CFRunLoopLock(rl);
            // RunLoop运行模式加锁
            __CFRunLoopModeLock(rlm);

            // RunLoop处理完事件就退出
            sourceHandledThisLoop = true;
            // 标记已经运行结束
            didDispatchPortLastTime = true;

         else 
            // 唤醒RunLoop
            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;

                // 处理Source1(基于端口的源)
                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);
                
#elif DEPLOYMENT_TARGET_WINDOWS
                sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop;
#endif
            

            // 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

        // 根据运行模式设置RunLoop
        __CFRunLoopDoBlocks(rl, rlm);

        // 判断是否要退出RunLoop
        if (sourceHandledThisLoop && stopAfterHandle) 
            // 处理完事件后退出
            retVal = kCFRunLoopRunHandledSource;
         else if (timeout_context->termTSR < mach_absolute_time()) 
            // 超时退出
            retVal = kCFRunLoopRunTimedOut;
         else if (__CFRunLoopIsStopped(rl)) 
            // 调用CFRunLoopStop()退出
            __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);


    // 退出RunLoop前处理超时定时器
    if (timeout_timer) 
        dispatch_source_cancel(timeout_timer);
        dispatch_release(timeout_timer);
     else 
        free(timeout_context);
    

    return retVal;



/**
 * RunLoop的运行细节
 */
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)


    CHECK_FOR_FORK();

    // 1. 判断RunLoop是否被销毁,已被销毁就返回退出原因kCFRunLoopRunFinished
    if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;

    // 2. 给加RunLoop锁
    __CFRunLoopLock(rl);

    // 3. 根据运行模式的名字modeName获取运行模式currentMode
    CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);

    // 4. 判断运行模式currentMode是否存在,或运行模式currentMode是否为空,即判断Mode中是否有source/timer/observer
    if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) 

        // 4.1 标记退出,如果运行模式不能正常使用,就以kCFRunLoopRunFinished方式退出RunLoop
        Boolean did = false;

        // 4.2 如果运行模式currentMode存在,就解锁运行模式currentMode
        if (currentMode)
            __CFRunLoopModeUnlock(currentMode);

        // 4.3 给RunLoop解锁
        __CFRunLoopUnlock(rl);

        // 4.4 根据标记为返回对应的退出原因
        return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
    

    // 5. 保存正在运行的RunLoop的运行模式,把相关数据压进栈
    volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);

    // 6. 保存正在运行的RunLoop的运行模式
    CFRunLoopModeRef previousMode = rl->_currentMode;

    // 7. 修改当前RunLoop的运行模式
    rl->_currentMode = currentMode;

    // 声明一个RunLoop的运行结果
    int32_t result = kCFRunLoopRunFinished;

    // 8. 判断当前运行模式是否可以运行RunLoop
    // &运算符的运算规律:0 & 0 => 0, 0 & 1 => 0, 1 & 0 => 0, 1 & 1 => 1
    if (currentMode->_observerMask & kCFRunLoopEntry )
        // 8.1 通知观察者Observer,即将运行RunLoop
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);

    // 9. 运行RunLoop
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);

    // 10. 判断当前运行模式是否要退出RunLoop
    if (currentMode->_observerMask & kCFRunLoopExit )
        // 10.1 通知观察者Observer,RunLoop即将退出
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

    // 11. 解锁运行模式currentMode
    __CFRunLoopModeUnlock(currentMode);

    // 12. 还原上一个运行模式的运行数据
    __CFRunLoopPopPerRunData(rl, previousPerRun);

    // 13. 还原RunLoop的上一个运行模式
    rl->_currentMode = previousMode;

    // 14. 解锁RunLoop
    __CFRunLoopUnlock(rl);

    return result;



/**
 * 根据默认的运行模式kCFRunLoopDefaultMode运行RunLoop
 */
void CFRunLoopRun(void) 

    // result: 记录退出原因
    int32_t result;
    do 
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK();

        // 当调用 CFRunLoopStop(); 或 所有的 Sources 都被移除时退出
     while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);



/**
 * 根据指定运行模式mode运行RunLoop
 */
SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) 

    CHECK_FOR_FORK();
    return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled);

以上是关于关于RunLoop部分源码的注释的主要内容,如果未能解决你的问题,请参考以下文章

深入研究 Runloop 与线程保活

RunLoop 总结:RunLoop的应用场景

iOS 模块分解—「Runloop 面试工作」看我就 🐒 了 ^_^.

Runloop

iOS开发RunLoop学习:四:RunLoop的应用和RunLoop的面试题

runloop的source