以下内容分析自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; // 返回本次运行结果
}