RunLoop 源码阅读

  1. 获取runloop的函数
// 获取主线程的runloop
CFRunLoopRef CFRunLoopGetMain(void) {
    CHECK_FOR_FORK();
    static CFRunLoopRef __main = NULL; // no retain needed
    if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
    return __main;
}

// 获取子线程的runloop
CFRunLoopRef CFRunLoopGetCurrent(void) {
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());
}
  1. 创建runloop的函数
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    // 判断t所指向的线程是否为空,如果为空,就获取当前的主线程进行赋值
    if (pthread_equal(t, kNilPthreadT)) {
        t = pthread_main_thread_np();
    }
    __CFLock(&loopsLock);

    // 全局__CFRunLoops,它是一个字典,用来存储所有线程的runloop
    if (!__CFRunLoops) {
        __CFUnlock(&loopsLock);
        CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
        // 由于主线程默认就有runloop,所以再创建__CFRunLoops,要默认添加一个主线程的runloop
        CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
        CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
        if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
            CFRelease(dict);
        }
        CFRelease(mainLoop);
        __CFLock(&loopsLock);
    }

    // 从__CFRunLoops中获取对应于当前线程的RunLoop
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    __CFUnlock(&loopsLock);
    if (!loop) {
        // 如果没有取到,说明是第一次,则创建一个runloop加入到全局字典中
        CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFLock(&loopsLock);
        loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
        if (!loop) {
            // 存储当前线程和对应的RunLoop到全局字典__CFRunLoops中
            CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
            loop = newLoop;
        }
        __CFUnlock(&loopsLock);
        CFRelease(newLoop);
    }

    // 判断是否为当前线程,如果是就注册一个回调,当线程销毁时,也销毁其对应的 RunLoop
    if (pthread_equal(t, pthread_self())) {
        _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
        if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
            _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);
        }
    }
    return loop;
}
  1. 运行runloop的函数
void CFRunLoopRun(void) {
    // 只有运行完成或主动退出时,才会真正的退出
    int32_t result;
    do {
        result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false);
        CHECK_FOR_FORK();
    } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result);
}

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) {  
    CHECK_FOR_FORK();
    // 判断RunLoop是否正在被销毁,已被销毁就退出原因
    if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;

    __CFRunLoopLock(rl);

    // 获取当前 mode
    CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
    if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
        // 如果当前 mode 和 runloop 的 mode 都为 nil,则退出
        Boolean did = false;
        if (currentMode) __CFRunLoopModeUnlock(currentMode);
        __CFRunLoopUnlock(rl);
        return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
    }

    // 保存正在运行的RunLoop,把相关数据压进栈
    volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
    CFRunLoopModeRef previousMode = rl->_currentMode;
    rl->_currentMode = currentMode;
    int32_t result = kCFRunLoopRunFinished;

    // 判断是否可以运行runloop,并通知观察者Observer,即将运行RunLoop
    if (currentMode->_observerMask & kCFRunLoopEntry ) 
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);

    // 运行RunLoop
    result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);

    // 判断是否要退出runloop,并通知观察者Observer,即将退出RunLoop
    if (currentMode->_observerMask & kCFRunLoopExit ) 
        __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

    __CFRunLoopModeUnlock(currentMode);
    __CFRunLoopPopPerRunData(rl, previousPerRun);
    rl->_currentMode = previousMode;
    __CFRunLoopUnlock(rl);
    return result;
}

/* rl, rlm are locked on entrance and exit 
   rl: runloop 
   rlm: runloop mode 
   seconds: 超时时间
   stopAfterHandle: 完成后是否停止 runloop
   previousMode: 前一次的 mode (主要因为 runloop 可以嵌套调用)
*/
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
    // 当前内核时间
    uint64_t startTSR = mach_absolute_time();

    // 判断本次 runloop 或 mode 状态是否已经停止了
    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)));
    // 在主线程中 && 是主线程的runloop && mode类型为common
    if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) 
        // 获取GCD端口(4CF 表示 for Core Foundation)
        dispatchPort = _dispatch_get_main_queue_port_4CF();
    
// 是否使用了GCD timer
#if USE_DISPATCH_SOURCE_FOR_TIMERS
    // GCD timer 消息端口
    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
    
    // 超时定时器
    dispatch_source_t timeout_timer = NULL;
    // 超时定时器的上下文
    struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
    if (seconds <= 0.0) { 
        // 如果超时时间<=0.0,立即就超时了,此时不需要定时器了
        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;
        timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
        timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
        // 设置GCD的计时器上下文为当前超时计时器的上下文
        dispatch_set_context(timeout_timer, timeout_context); 
        // 设置超时source
        dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
        // 设置超时取消source
        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 { 
        // 如果超时时间很大,则认为是无限时间,即永远也不可能超时(这里的seconds值大概相当于317年)
        seconds = 9999999999.0;
        timeout_context->termTSR = UINT64_MAX;
    }

    Boolean didDispatchPortLastTime = true;
    // 函数的返回值 (return value),默认为0
    int32_t retVal = 0;
    // do {} while() 这个循环就是runloop的核心代码块
    do {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
        voucher_mach_msg_state_t voucherState = VOUCHER_MACH_MSG_STATE_UNCHANGED;
        voucher_t voucherCopy = NULL;
#endif  
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
        mach_msg_header_t *msg = NULL;
        mach_port_t livePort = MACH_PORT_NULL;
#elif DEPLOYMENT_TARGET_WINDOWS
        HANDLE livePort = NULL;
        Boolean windowsMessageReceived = false;
#endif
        // 申请一个存放消息的空间
        uint8_t msg_buffer[3 * 1024];

        __CFPortSet waitSet = rlm->_portSet;

        __CFRunLoopUnsetIgnoreWakeUps(rl);

        // 1.通知 observer,即将处理 timers
        if (rlm->_observerMask & kCFRunLoopBeforeTimers) 
            __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
        // 2.通知 observer,即将处理 sources
        if (rlm->_observerMask & kCFRunLoopBeforeSources) 
            __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
        
        // 3.处理 blocks
        __CFRunLoopDoBlocks(rl, rlm);

        // 4.处理 sources0
        Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        // 如果实际处理了 sources0,则再一次处理 blocks
        if (sourceHandledThisLoop) {
            __CFRunLoopDoBlocks(rl, rlm);
        }
        
        // 处理完 sources0 或 超时时间为0
        Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
      
        // 5.处理主线程中的GCD事件,循环的第一次是不会进入的,因为didDispatchPortLastTime永远是true
        if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
            msg = (mach_msg_header_t *)msg_buffer;
            if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
                goto handle_msg;
            }
#elif DEPLOYMENT_TARGET_WINDOWS
            if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) {
                goto handle_msg;
            }
#endif
        }
        didDispatchPortLastTime = false;

        // 6.没有处理完sources0 && 没有超时,通知 observer,即将进入睡眠
        if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting))    
            __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        // 7.设置标志,正在睡眠 (实际runloop还没有睡眠)
        __CFRunLoopSetSleeping(rl);
        // 8.将GCD端口加入所有监听端口集合中
        __CFPortSetInsert(dispatchPort, waitSet);
        
        __CFRunLoopModeUnlock(rlm);
        __CFRunLoopUnlock(rl);

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

#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#if USE_DISPATCH_SOURCE_FOR_TIMERS
        // 如果使用 GCD timer,获取消息后需要对GCD Timer做一些额外的处理
        do {        
            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);
            
            if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
                while (_dispatch_runloop_root_queue_perform_4CF(rlm->_queue));
                if (rlm->_timerFired) {
                    rlm->_timerFired = false;
                    break;
                } else {
                    if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
                }
            } else {
                break;
            }
        } while (1);
#else
        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);
#endif
        
#elif DEPLOYMENT_TARGET_WINDOWS
        __CFRunLoopWaitForMultipleObjects(waitSet, NULL, poll ? 0 : TIMEOUT_INFINITY, rlm->_msgQMask, &livePort, &windowsMessageReceived);
#endif
        
        __CFRunLoopLock(rl);
        __CFRunLoopModeLock(rlm);

        rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart));

        // 移除 GCD 端口
        __CFPortSetRemove(dispatchPort, waitSet);
        
        __CFRunLoopSetIgnoreWakeUps(rl);

        //  处理完成 GCD 后,通知 observer,即将进入睡眠
        __CFRunLoopUnsetSleeping(rl);
        if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) 
            __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);

        // 收到消息的标签
        // 1. 基于 port 的 Sources1 的事件
        // 2. Timer 到时间
        // 3. RunLoop 超时
        // 4. 被手动唤醒
        handle_msg:;
        __CFRunLoopSetIgnoreWakeUps(rl);

#if DEPLOYMENT_TARGET_WINDOWS
        if (windowsMessageReceived) {
            __CFRunLoopModeUnlock(rlm);
            __CFRunLoopUnlock(rl);

            if (rlm->_msgPump) {
                rlm->_msgPump();
            } else {
                MSG msg;
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            
            __CFRunLoopLock(rl);
            __CFRunLoopModeLock(rlm);
            sourceHandledThisLoop = true;
            
            __CFRunLoopSetSleeping(rl);
            __CFRunLoopModeUnlock(rlm);
            __CFRunLoopUnlock(rl);
            
            __CFRunLoopWaitForMultipleObjects(waitSet, NULL, 0, 0, &livePort, NULL);
            
            __CFRunLoopLock(rl);
            __CFRunLoopModeLock(rlm);            
            __CFRunLoopUnsetSleeping(rl);
        }  
#endif

        if (MACH_PORT_NULL == livePort) {
            // 不知道哪个端口唤醒的
            CFRUNLOOP_WAKEUP_FOR_NOTHING();
        } else if (livePort == rl->_wakeUpPort) {
            // 被 CFRunLoopWakeUp 函数唤醒的
            CFRUNLOOP_WAKEUP_FOR_WAKEUP();
        }

#if USE_DISPATCH_SOURCE_FOR_TIMERS
        else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
            // 被 GCD timers 唤醒,处理 timers
            CFRUNLOOP_WAKEUP_FOR_TIMER();
            if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
                __CFArmNextTimerInMode(rlm, rl);
            }
        }
#endif

#if USE_MK_TIMER_TOO
        else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
            // 被其它 timers 唤醒,处理 timers
            CFRUNLOOP_WAKEUP_FOR_TIMER();
            if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
                __CFArmNextTimerInMode(rlm, rl);
            }
        }
#endif
        else if (livePort == dispatchPort) {
            // 被主线程 GCD 唤醒,处理 GCD
            CFRUNLOOP_WAKEUP_FOR_DISPATCH();
            __CFRunLoopModeUnlock(rlm);
            __CFRunLoopUnlock(rl);
            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
#if DEPLOYMENT_TARGET_WINDOWS
            void *msg = 0;
#endif
            __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
            _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);
            __CFRunLoopLock(rl);
            __CFRunLoopModeLock(rlm);
            sourceHandledThisLoop = true;
            didDispatchPortLastTime = true;
        } else {
            // 被 sources1 唤醒,处理 sources1
            CFRUNLOOP_WAKEUP_FOR_SOURCE();
            voucher_t previousVoucher = _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, (void *)voucherCopy, os_release);

            CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);
            if (rls) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
                mach_msg_header_t *reply = NULL;
                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);
                }
#elif DEPLOYMENT_TARGET_WINDOWS
                sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop;
#endif
            }
            _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, previousVoucher, os_release);
        } 
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
        if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
#endif

        // 再一次处理 blocks
        __CFRunLoopDoBlocks(rl, rlm);
         
        // 判断是否退出
        if (sourceHandledThisLoop && stopAfterHandle) {
            // 处理完事件后退出
            retVal = kCFRunLoopRunHandledSource;
        } else if (timeout_context->termTSR < mach_absolute_time()) {
            // 超时退出
            retVal = kCFRunLoopRunTimedOut;
        } else if (__CFRunLoopIsStopped(rl)) {
            // 调用CFRunLoopStop()退出
            __CFRunLoopUnsetStopped(rl);
            retVal = kCFRunLoopRunStopped;
        } else if (rlm->_stopped) {
            // 运行模式被终止时退出
            rlm->_stopped = false;
            retVal = kCFRunLoopRunStopped;
        } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
            // 没有要处理的事件时退出
            retVal = kCFRunLoopRunFinished;
        }
        
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
        voucher_mach_msg_revert(voucherState);
        os_release(voucherCopy);
#endif

    } while (0 == retVal);

    if (timeout_timer) {
        dispatch_source_cancel(timeout_timer);
        dispatch_release(timeout_timer);
    } else {
        free(timeout_context);
    }

    return retVal;
}

Runloop 运行的核心函数__CFRunLoopRun大概有300多行代码,看似很多代码,其实其中有很多是为了适配不同平台的代码,如果我们将其删减一下,删掉那些平台的适配以及一些复杂的逻辑判断,我们就可以得到如下的runloop执行过程

staticint32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
    do {
        // 1. 通知 observers,RunLoop 即将处理 Timers
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
        // 2. 通知 observers,RunLoop 即将处理 Sources
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
        // 3. 处理 sources0 事件
        __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        // 4. 处理 blocks
        __CFRunLoopDoBlocks(rl, rlm);
        // 5. 处理 sources1 事件
        goto handle_msg;
        // 6. 通知 observers, RunLoop 即将休眠
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
        // 7. RunLoop 休眠
        __CFRunLoopSetSleeping(rl);
        // 8. 线程进入休眠, 直到被下面某一个事件唤醒:
        // a. 基于 port 的 Source1 的事件
        // b. Timer 到时间了
        // c. RunLoop 启动时设置的最大超时时间到了
        // d. 被手动唤醒
        // 9. 当接收到第8步中的消息时,Runloop 醒来
        __CFRunLoopUnsetSleeping(rl);
        // 10. 通知 observers,RunLoop 已被唤醒
        __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
        // 11. 处理消息
        handle_msg:;
        if(MACH_PORT_NULL == livePort) {
            CFRUNLOOP_WAKEUP_FOR_NOTHING();
        } else if(livePort == rl->_wakeUpPort) {
            CFRUNLOOP_WAKEUP_FOR_WAKEUP();
        } else if(modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
            // 处理定时器事件
            CFRUNLOOP_WAKEUP_FOR_TIMER();
        } else if(livePort == dispatchPort) {
            // 处理主线程消息
            CFRUNLOOP_WAKEUP_FOR_DISPATCH();
        } else {
            // 处理 sources1
            CFRUNLOOP_WAKEUP_FOR_SOURCE();
        } 
        // 12. 退出 RunLoop
    return retVal;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏walterlv - 吕毅的博客

各个版本 Windows 10 系统中自带的 .NET Framework 版本

发布于 2017-10-17 02:49 更新于 2018-06...

7992
来自专栏张善友的专栏

网上Silverlight项目收集

1、Silverlight + OpenXML Video  :This is a Silverlight proof of concept applicati...

2209
来自专栏张善友的专栏

.NET 4.0 的Web Form和EF的例子 Employee Info Starter Kit (v4.0.0)

ASP.NET 4.0改进了许多不同的场景集(set of scenarios),如Webforms ,Dynamic Data以及基于AJAX的Web开发。此...

20210
来自专栏张善友的专栏

Mono 2.2 发布了

Mono 2.2 推出新的代码生成引擎,会产生更优质的代码.对 Windows Form 以及其它内容做进一步改进 MONO 2.2 新特性: JIT N...

1997
来自专栏林德熙的博客

win10 UWP 使用 MD5算法

在我们的应用需求很常见的,我们需要使用md5算法。 uwp的 md5 和 WPF 的使用差不多。

1332
来自专栏张善友的专栏

11年微软MVP:每周.NET前沿技术文章摘要(2017-05-10)

汇总国内外.NET社区相关文章,覆盖.NET ,ASP.NET两个方面的内容

5500
来自专栏流媒体人生

SetTimer在无窗口和有窗口线程的使用

 今天犯了一个粗心的错误,在无窗口线程中,SetTimer中设置计时器ID,而WM_TIMER消息响应函数中得到的计时器ID却不是之前设置的计时器ID.

862
来自专栏施炯的IoT开发专栏

Silverlight for Windows Phone Toolkit 更新

The Silverlight Toolkit team has just published the new release of the Silverlig...

1975
来自专栏张善友的专栏

HELP! I’m an Object Factory!

It has been a week since my last post, I’ve been coding on ePortal WYSIWYG ASP.N...

2055
来自专栏盟主来了

淘宝的npaliedit在mb下会崩溃的问题解决了

2185

扫码关注云+社区

领取腾讯云代金券