CFRunLoop 源码学习笔记(CF-1151.16)
1、CFRunLoopModeRef 什么时候创建的?
__CFRunLoopRun 源码, 去掉windows、disaptch_timer 支持
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { uint64_t startTSR = mach_absolute_time(); /* 首先判断 CFRunLoopRef 是否停止,停止的话,重置停止状态并且返回停止状态 */ if (__CFRunLoopIsStopped(rl)) { /* 是否设置了停止位 */ __CFRunLoopUnsetStopped(rl); /* 重置停止位、并返回停止状态 */ return kCFRunLoopRunStopped; } else if (rlm->_stopped) { /* 这个模式下是否停止了、并且重置模式停止状态 */ rlm->_stopped = false; /* 返回停止 */ return kCFRunLoopRunStopped; } mach_port_name_t dispatchPort = MACH_PORT_NULL; /* 主线程端口或者空 */ Boolean libdispatchQSafe = pthread_main_np() && ( (HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)) ); if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF(); /* libDispatch -> private.h */ /* 定义一个 dispatch_source_t 为了CFRunLoopRunInMode 自定义时间时存在,为了做唤醒使用 */ dispatch_source_t timeout_timer = NULL; struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context)); if (seconds <= 0.0) { // instant timeout seconds = 0.0; timeout_context->termTSR = 0ULL; } else if (seconds <= TIMER_INTERVAL_LIMIT/* TIMER_INTERVAL_LIMIT 504911232.0*/) { /* 尝试超时后唤醒,如果当前线程出于等待状态的情况下 */ dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground(); /* 创建source */ timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_retain(timeout_timer); /* 写入source 的 上下文中 */ timeout_context->ds = timeout_timer; timeout_context->rl = (CFRunLoopRef)CFRetain(rl); timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds); /* 设置source的上下文 */ dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context /* 设置时间事件的回调函数,调用了CFRunLoopWakeUp, 这个函数向等待端口发送了一个消息, 用来激活循环 */ 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); /* 设置source的timer, 仅仅延迟执行一次 */ dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at)/* start */, DISPATCH_TIME_FOREVER/* interval */, 1000ULL); /* 只执行一次 */ /* 唤醒source */ dispatch_resume(timeout_timer); } else { // infinite timeout seconds = 9999999999.0; timeout_context->termTSR = UINT64_MAX; } Boolean didDispatchPortLastTime = true; int32_t retVal = 0; do { voucher_mach_msg_state_t voucherState = VOUCHER_MACH_MSG_STATE_UNCHANGED; voucher_t voucherCopy = NULL; /* 定义mach接收 msg 缓冲区 3k 大小 */ uint8_t msg_buffer[3 * 1024]; /* 3K */ mach_msg_header_t *msg = NULL; mach_port_t livePort = MACH_PORT_NULL; /* CFRunLoopModeRef->_portSet 实际上就是 mach_port_t -->>> __CFPort OR __CFPortSet */ __CFPortSet waitSet = rlm->_portSet; /* mac 下 就是 mach_port_t 等待端口集合 */ /* 重置 CFRunLoopRef->_perRunData->ignoreWakeUps = 0x57414B45; WAKUP 标识 */ __CFRunLoopUnsetIgnoreWakeUps(rl); /* 回调 Before Timer && Source */ if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); /* 回调block, 只能回到一次block? */ __CFRunLoopDoBlocks(rl, rlm); /* source0 是否handled(回调) */ Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle/* __CFRunLoopRun 参数 */); //source 0 必须signed if (sourceHandledThisLoop) { /* 回调了Source0 */ __CFRunLoopDoBlocks(rl, rlm); //source 0 } /* 确定端口集合接收消息是否设置永远超时,如果poll为真,则立即返回,否则无限等待直到有消息过来 */ Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR); /* 从CFRunLoopRun 过来的话 timeout_context->termTSR 永远不等于0*/ if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) { /* 首次循环不执行,因为外部定义 didDispatchPortLastTime 为 true */ msg = (mach_msg_header_t *)msg_buffer; if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0/*timeout == 0*/, &voucherState, NULL)) { /* 主队列接收消息,接收消息成功则跳转到处理消息过程source1 */ goto handle_msg; } } /* 执行到这里意味着 dispatchPort 没有成功接收到 mach message */ didDispatchPortLastTime = false; /* do while 循环外定义,初始化值 true */ /* 没有回调并且timerTSR 大于 0 的情况下 并且 有等待掩码, poll 定义为 -> source0 处理了 或者 定义唤醒时间为0 */ if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); /* 设置CFRunLoopRef 睡眠标志位。因为后面有进行一个 mach_msg 的等待操作 */ __CFRunLoopSetSleeping(rl); __CFPortSetInsert(dispatchPort, waitSet); /* 将主端口 插入等待集合中 */ __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent(); 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); __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart)); /* 从端口集合中移除 disaptchPort */ __CFPortSetRemove(dispatchPort, waitSet); __CFRunLoopSetIgnoreWakeUps(rl); // user callouts now OK again __CFRunLoopUnsetSleeping(rl); //重置睡眠状态 /* pool代表: 回调过 或者 触发时间为0, 根据掩码进行回调 */ if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); /* 处理 mach 消息成功的标签*/ handle_msg:; __CFRunLoopSetIgnoreWakeUps(rl); if (MACH_PORT_NULL == livePort) { CFRUNLOOP_WAKEUP_FOR_NOTHING(); } else if (livePort == rl->_wakeUpPort) { CFRUNLOOP_WAKEUP_FOR_WAKEUP(); } else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) { CFRUNLOOP_WAKEUP_FOR_TIMER(); if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) { // Re-arm the next timer __CFArmNextTimerInMode(rlm, rl); } } else if (livePort == dispatchPort) { CFRUNLOOP_WAKEUP_FOR_DISPATCH(); __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL); __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL); __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); sourceHandledThisLoop = true; didDispatchPortLastTime = true; } else { /* 接收端口不为空,并且没有满足 timer、主队列端口情况下,处理 source1 */ CFRUNLOOP_WAKEUP_FOR_SOURCE(); 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) { 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); } } // Restore the previous voucher _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, previousVoucher, os_release); } if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg); __CFRunLoopDoBlocks(rl, rlm); if (sourceHandledThisLoop && stopAfterHandle/* CFRunLoopRun ->false */) { 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)) { retVal = kCFRunLoopRunFinished; } voucher_mach_msg_revert(voucherState); os_release(voucherCopy); } while (0 == retVal); // 循环结束, retVal 等于 0 /* 释放超时timer */ if (timeout_timer) { dispatch_source_cancel(timeout_timer); dispatch_release(timeout_timer); } else { free(timeout_context); } return retVal; } //__CFRunLoopRun
无论遇到什么困难、一往直前