之前看过不少别人博客里对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任务每次循环只执行其中一种