-
Notifications
You must be signed in to change notification settings - Fork 8
Open
Description
下面是 __CFRunLoopRun 的核心代码,这里为了理解方便已经简化了不必要的代码:
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
//.....
do {
//......
// 通知 observers: kCFRunLoopBeforeTimers, 即将处理 timers
if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 通知 observers: kCFRunLoopBeforeSources, 即将处理 sources
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 执行加入当前runloop的block
__CFRunLoopDoBlocks(rl, rlm);
// 处理 sources 0
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
// 如果实际处理了 sources 0,再一次处理blocks
__CFRunLoopDoBlocks(rl, rlm);
}
//.....
// 通知 observers: kCFRunLoopBeforeWaiting, 即将进入等待(睡眠)
// 注意到如果实际处理了 source 0 或者超时了,不会进入睡眠,所以不会通知
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
// 设置标志位,正在睡眠
__CFRunLoopSetSleeping(rl);
__CFRunLoopSetIgnoreWakeUps(rl);
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
// 通知 observers: kCFRunLoopAfterWaiting, 即停止等待(被唤醒)
// 注意实际处理过 source 0 或者已经超时的话,不会通知(因为没有睡)
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
// 被什么唤醒就处理什么:
handle_msg:;
__CFRunLoopSetIgnoreWakeUps(rl);
//// 不知道哪个端口唤醒的(或者根本没睡),啥也不干
if (MACH_PORT_NULL == livePort) {
CFRUNLOOP_WAKEUP_FOR_NOTHING();
// handle nothing
//// 被 CFRunLoopWakeUp 函数弄醒的,啥也不干
} else if (livePort == rl->_wakeUpPort) {
CFRUNLOOP_WAKEUP_FOR_WAKEUP();
// do nothing on Mac OS
}
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);
}
}
// 被 GCD 唤醒处理 GCD
else if (livePort == dispatchPort) {
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
//.....
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
//....
} else {
/// 被 sources 1 唤醒,处理 sources 1
CFRUNLOOP_WAKEUP_FOR_SOURCE();
//.......
}
//....
} while (0 == retVal);
//....
return retVal;
}- 通知将要进入Runloop
- 通知将要处理Timmer事件
- 通知将要处理Source事件
- 处理Source0事件,在处理Source0事件之前都会调用****__CFRunLoopDoBlocks****处理下block。
- 通知将要进入睡眠状态
- Runloop进入睡眠状态
- 当有事件源给Runloop发送消息,表示有事件处理的时候,就会唤醒Runloop。
- 唤醒Runloop。
- 通知Runloop已经唤醒。
- 根据事件源来调用不同的方法来执行处理,这里的事件源可以是Timmer,Source1,GCD事件。
- 是否退出,Runloop ? 如果NO则,继续上面循环,如果YES则进入下一步
- 通知将要退出Runloop
大致如下图所示:
Metadata
Metadata
Assignees
Labels
No labels
