AI分析RunLoop.c下的__CFRunLoopRun方法

7 阅读13分钟

以下内容分析自AI。

源代码在这里:github.com/swiftlang/s…

// =========================
// 核心运行过程 __CFRunLoopRun
// =========================
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { // 主运行函数:在指定模式下运行并等待消息/定时器
    uint64_t startTSR = mach_absolute_time(); // 记录开始时间(TSR 单位)

    if (__CFRunLoopIsStopped(rl)) { // 如果 run loop 已请求停止
        __CFRunLoopUnsetStopped(rl); // 清除停止标记(消费一次)
	    return kCFRunLoopRunStopped; // 返回“已停止”
    } else if (rlm->_stopped) { // 如果当前模式被停止
	    rlm->_stopped = false; // 清除模式停止标记
	    return kCFRunLoopRunStopped; // 返回“已停止”
    }
    
#if __HAS_DISPATCH__
    __CFPort dispatchPort = CFPORT_NULL; // 记录可能监听的主队列端口
    Boolean libdispatchQSafe = (pthread_main_np() == 1) && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ))); // 判断是否在主线程且当前不在 GCD 主队列回调中
    if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF(); // 主 run loop 的公共模式代表主队列,取其端口
#endif
    
#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

    uint64_t termTSR = 0ULL; // 计算超时截止时间(TSR)
#if __HAS_DISPATCH__
    dispatch_source_t timeout_timer = NULL; // 如果需要精确超时,创建 dispatch 定时器触发唤醒
#endif
    if (seconds <= 0.0) { // instant timeout // 如果要求“立刻超时”
        seconds = 0.0; // 规范化为 0
        termTSR = 0ULL; // 截止时间为当前(不等待)
    } else if (seconds <= TIMER_INTERVAL_LIMIT) { // 合理范围的超时值
        termTSR = startTSR + __CFTimeIntervalToTSR(seconds); // 将秒转为 TSR 并加到开始时间
#if __HAS_DISPATCH__
	    dispatch_queue_t queue = (pthread_main_np() == 1) ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground(); // 主线程用主队列,其它线程用后台队列
	    timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 创建一个一次性定时器源

        CFRetain(rl); // 为定时器回调持有 rl(避免回调期间被释放)
        dispatch_source_set_event_handler(timeout_timer, ^{ // 超时回调:唤醒 run loop
            CFRUNLOOP_WAKEUP_FOR_TIMEOUT(); // 标记唤醒原因(超时)
            cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_TIMEOUT, rl, 0, 0, 0); // 跟踪记录
            CFRunLoopWakeUp(rl); // 唤醒 run loop
            // The interval is DISPATCH_TIME_FOREVER, so this won't fire again
        }); // 结束设置事件处理
        dispatch_source_set_cancel_handler(timeout_timer, ^{ // 取消处理:释放 rl
            CFRelease(rl); // 释放引用
        }); // 结束取消处理

        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); // 设置一次性触发,leeway 为 1000ns
        dispatch_resume(timeout_timer); // 启动定时器源
#endif
    } else { // infinite timeout // 如果为超大或无限等待
        seconds = 9999999999.0; // 规范化为极大值
        termTSR = UINT64_MAX; // 截止时间设为最大
    }

    Boolean didDispatchPortLastTime = true; // 记录上一次是否处理了 dispatchPort(避免饥饿)
    int32_t retVal = 0; // 返回值(循环结束条件)
    do { // 单次迭代;实际只有一次,内部根据条件决定是否退出
#if TARGET_OS_MAC
        voucher_mach_msg_state_t voucherState = VOUCHER_MACH_MSG_STATE_UNCHANGED; // 记录 mach voucher 状态
        voucher_t voucherCopy = NULL; // 可选拷贝的 voucher
#endif
        uint8_t msg_buffer[3 * 1024]; // 收取消息的临时缓冲
#if TARGET_OS_MAC
        mach_msg_header_t *msg = NULL; // 指向消息头
        mach_port_t livePort = MACH_PORT_NULL; // 被唤醒的端口(最终决定处理路径)
#elif TARGET_OS_WIN32 || TARGET_OS_CYGWIN
        HANDLE livePort = NULL; // Windows/Cygwin 下为 HANDLE
        Boolean windowsMessageReceived = false; // 标记是否收到 Windows 消息
#elif TARGET_OS_LINUX
        int livePort = -1; // Linux 下用 fd 表示
#else
        __CFPort livePort = CFPORT_NULL; // 其他平台的通用端口类型
#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); // 在进入等待前先处理一次积压的 block

        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle); // 运行 Source0(立即调用型源),返回是否处理过
        if (sourceHandledThisLoop) { // 如果处理过源
            __CFRunLoopDoBlocks(rl, rlm); // 再处理一次可能因此加入的 block
        }

        Boolean poll = sourceHandledThisLoop || (0ULL == termTSR); // 若刚处理过源或不等待则使用“轮询”方式

#if __HAS_DISPATCH__
        if (CFPORT_NULL != dispatchPort && !didDispatchPortLastTime) { // 若本次优先尝试主队列端口且上次没处理它
#if TARGET_OS_MAC
            msg = (mach_msg_header_t *)msg_buffer; // 将缓冲视为消息
            if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL, rl, rlm)) { // 非阻塞收取主队列端口
                goto handle_msg; // 若收到,跳到统一处理
            }
#elif TARGET_OS_LINUX && !TARGET_OS_CYGWIN
            if (__CFRunLoopServiceFileDescriptors(CFPORTSET_NULL, dispatchPort, 0, &livePort)) { // Linux 非阻塞 poll 主队列 fd
                goto handle_msg; // 若收到,跳到统一处理
            }
#elif TARGET_OS_WIN32 || TARGET_OS_CYGWIN
            if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) { // Windows 非阻塞等待主队列句柄
                goto handle_msg; // 若收到,跳到统一处理
            }
#elif TARGET_OS_BSD
            if (__CFRunLoopServiceFileDescriptors(CFPORTSET_NULL, dispatchPort, 0, &livePort)) { // BSD 非阻塞 poll 主队列 fd
                goto handle_msg; // 若收到,跳到统一处理
            }
#else
#error "invoking the port select implementation is required" // 其他平台需要实现对应等待逻辑
#endif
        }
#endif

        didDispatchPortLastTime = false; // 先重置为 false,若稍后处理了主队列再置回 true

	    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. // 每次迭代都要插入本次激活相关端口,防止重入时被服务
#if __HAS_DISPATCH__
        __CFPortSetInsert(dispatchPort, waitSet); // 将主队列端口插入等待集合
#endif
        
	    __CFRunLoopModeUnlock(rlm); // 释放模式锁以便阻塞等待
	    __CFRunLoopUnlock(rl); // 释放 run loop 锁

        CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent(); // 记录睡眠开始时间(轮询则记 0)

#if TARGET_OS_MAC
#if USE_DISPATCH_SOURCE_FOR_TIMERS
        do { // 如果使用 dispatch 源驱动定时器,需要循环排队队列直到没有任务或定时器触发
            msg = (mach_msg_header_t *)msg_buffer; // 准备消息缓冲
            
            __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); // 持续直到 break
#else
        msg = (mach_msg_header_t *)msg_buffer; // 准备消息缓冲
        __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy, rl, rlm); // 阻塞或非阻塞等待端口消息
#endif
        
        
#elif TARGET_OS_WIN32
        // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages. // Windows:使用模式中的消息掩码
        __CFRunLoopWaitForMultipleObjects(waitSet, NULL, poll ? 0 : TIMEOUT_INFINITY, rlm->_msgQMask, &livePort, &windowsMessageReceived); // 等待句柄或消息
#elif TARGET_OS_LINUX
        __CFRunLoopServiceFileDescriptors(waitSet, CFPORT_NULL, poll ? 0 : TIMEOUT_INFINITY, &livePort); // Linux:poll/epoll 等待
#elif TARGET_OS_BSD
        __CFRunLoopServiceFileDescriptors(waitSet, CFPORT_NULL, poll ? 0 : TIMEOUT_INFINITY, &livePort); // BSD:kqueue 等待
#else
#error "invoking the port set select implementation is required" // 其他平台需实现等待机制
#endif
        
        __CFRunLoopLock(rl); // 被唤醒后重新加 run loop 锁
        __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. // 每次迭代都要移除本次激活端口,避免重入或函数返回后仍服务
#if __HAS_DISPATCH__
        __CFPortSetRemove(dispatchPort, waitSet); // 从等待集合移除主队列端口
#endif
        
        __CFRunLoopSetIgnoreWakeUps(rl); // 再次设置忽略唤醒(进入处理阶段,避免无效唤醒)

        // user callouts now OK again // 从此点开始允许用户回调
	    __CFRunLoopUnsetSleeping(rl); // 清除睡眠标记
	    if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); // 若非轮询,触发“等待之后”观察者

        handle_msg:; // 统一消息处理入口标签
        __CFRunLoopSetIgnoreWakeUps(rl); // 再次设置忽略唤醒(确保处理一致性)

#if TARGET_OS_WIN32
        if (windowsMessageReceived) { // 如果此次唤醒来源为 Windows 消息
            // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after // 调用 Win32 API 会产生回调,需在未持锁下调用
            __CFRunLoopModeUnlock(rlm); // 释放模式锁
	        __CFRunLoopUnlock(rl); // 释放 run loop 锁

            if (rlm->_msgPump) { // 若提供自定义消息泵
                rlm->_msgPump(); // 运行消息泵
            } else { // 否则使用默认处理
                MSG msg; // Windows 消息结构
                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. // 此次检查忽略 Windows 消息,且使用 0 超时仅作“是否已就绪”的检查
            // 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); // 解 run loop 锁
            
            __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 (CFPORT_NULL == livePort) { // 如果没有任何唤醒事件
            CFRUNLOOP_WAKEUP_FOR_NOTHING(); // 标记“无事可做”的唤醒
            cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_NOTHING, rl, rlm, livePort, 0); // 跟踪记录
            // handle nothing // 无需处理
        } else if (livePort == rl->_wakeUpPort) { // 如果唤醒源为 run loop 的唤醒端口
            CFRUNLOOP_WAKEUP_FOR_WAKEUP(); // 标记“外部唤醒”
            cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_WAKEUP, rl, rlm, livePort, 0); // 跟踪记录
            // do nothing on Mac OS // macOS 上无需特殊处理(端口队列长度为 1)
#if TARGET_OS_WIN32
            // Always reset the wake up port, or risk spinning forever // Windows 上必须重置事件,避免自旋
            ResetEvent(rl->_wakeUpPort); // 重置事件对象
#endif
        }
#if USE_DISPATCH_SOURCE_FOR_TIMERS
        else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) { // 如果来自模式队列(意味着可能是定时器触发)
            CFRUNLOOP_WAKEUP_FOR_TIMER(); // 标记“定时器唤醒”
            cf_trace(KDEBUG_EVENT_CFRL_DID_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); // 重新设置下一次触发
            }
        }
#endif
        else if (rlm->_timerPort != CFPORT_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... // 注释:Windows 定时器可能提前唤醒,需重置以免后续不再触发
            if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) { // 若本次未处理任何定时器
                // Re-arm the next timer // 重新武装下一个定时器
                // Since we'll be resetting the same timer as before
                // with the same deadlines, we need to reset these
                // values so that the arm next timer code can
                // correctly find the next timer in the list and arm
                // the underlying timer. // 复位软/硬截止时间,让算法正确找到下一计时器
                rlm->_timerSoftDeadline = UINT64_MAX; // 复位软截止
                rlm->_timerHardDeadline = UINT64_MAX; // 复位硬截止
                __CFArmNextTimerInMode(rlm, rl); // 重新安排下一个触发
            }
        }
        
        /* --- DISPATCHES  --- */ // 处理 libdispatch 主队列回调(仅主 run loop 公共模式)
        
#if __HAS_DISPATCH__
        else if (livePort == dispatchPort) { // 唤醒源为主队列端口
            CFRUNLOOP_WAKEUP_FOR_DISPATCH(); // 标记“主队列唤醒”
            cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_DISPATCH, rl, rlm, livePort, 0); // 跟踪
            __CFRunLoopModeUnlock(rlm); // 解模式锁以便执行回调
            __CFRunLoopUnlock(rl); // 解 run loop 锁
            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL); // 标记当前在主队列回调中

#if TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
            void *msg = 0; // 非 macOS 平台不使用 mach 消息
#endif
            CFRUNLOOP_ARP_BEGIN(NULL) // 如启用每回调 ARP,则建立池
            cf_trace(KDEBUG_EVENT_CFRL_IS_CALLING_DISPATCH | DBG_FUNC_START, rl, rlm, msg, livePort); // 跟踪开始
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); // 实际调用主队列回调派发函数
            cf_trace(KDEBUG_EVENT_CFRL_IS_CALLING_DISPATCH | DBG_FUNC_END, rl, rlm, msg, livePort); // 跟踪结束
            CFRUNLOOP_ARP_END() // 销毁 autorelease pool(如有)

            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL); // 清除主队列回调标记
            __CFRunLoopLock(rl); // 重新加锁
            __CFRunLoopModeLock(rlm); // 重新加模式锁
            sourceHandledThisLoop = true; // 标记本次循环处理了事件
            didDispatchPortLastTime = true; // 记录本次处理了主队列,避免下次优先
        }
#endif
        
        /* --- SOURCE1S  --- */ // 基于端口/句柄的 Source1 事件处理
        
        else { // 若来源是其他端口(非唤醒、非定时器、非主队列)
            CFRUNLOOP_WAKEUP_FOR_SOURCE(); // 标记“源唤醒”
            cf_trace(KDEBUG_EVENT_CFRL_DID_WAKEUP_FOR_SOURCE, rl, rlm, 0, 0); // 跟踪记录
            // Despite the name, this works for windows handles as well // 注:此函数同时适用于 Windows 句柄
            CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort); // 根据端口查找 Source1
            if (rls) { // 找到对应源
#if TARGET_OS_MAC
		        mach_msg_header_t *reply = NULL; // 可能需要发送的应答消息
		        sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop; // 处理 Source1(可能返回是否已处理)
		        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 TARGET_OS_WIN32 || (TARGET_OS_LINUX && !TARGET_OS_CYGWIN)
                sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop; // Windows/Linux 上的 Source1 执行
#endif
            } else { // 未找到对应源(异常情况)
                os_log_error(_CFOSLog(), "__CFRunLoopModeFindSourceForMachPort returned NULL for mode '%@' livePort: %u", rlm->_name, livePort); // 记录错误日志
            }
            
        }
        
        /* --- BLOCKS --- */ // 每轮最后再处理一次 block
        
#if TARGET_OS_MAC
        if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg); // 如果消息缓冲在堆上,释放之
#endif
        
	    __CFRunLoopDoBlocks(rl, rlm); // 处理待执行 block
        
	    if (sourceHandledThisLoop && stopAfterHandle) { // 若处理了源且要求处理一个后就返回
	        retVal = kCFRunLoopRunHandledSource; // 设置返回值为“已处理源”
        } else if (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; // 返回“已完成”
	    }

    } while (0 == retVal); // 单次循环,根据条件退出
#if __HAS_DISPATCH__
    if (timeout_timer) { // 如果创建了超时定时器源
        dispatch_source_cancel(timeout_timer); // 取消定时器
        dispatch_release(timeout_timer); // 释放源
    }
#endif
    
    return retVal; // 返回本次运行结果
}