Runloop源代码学习(一)基础数据结构

1,750 阅读16分钟

2021-08-06

前言

之前发过一篇文章,从 UIKit 事件响应入手,简单学习了一下 Runloop 的接口,当时只简单总结了一下 Runloop 的接口,并没有深入探究其原理性的东西。实际上无论是在 Apple Documentation 还是网上的很多博文中,都可以了解到 Runloop 的一些实现细节,本文则是从 Runloop 源代码中寻找些这些细节所对应的“证据”。先附上 Runloop 源代码地址:CFRunloop

一、数据结构

数据结构是一切代码的基础。

1.1 Mode

开发过程中使用最多的 Runloop 接口想必是CFRunLoopGetCurrentCFRunLoopGetMain,使用最多的相关数据结构除了CFRunLoopRef外,就是CFRunLoopModeRef了。我们知道每个 Runloop 都包含多个 Mode,Mode 代表了 Runloop 的运行模式,CF 公开的 Runloop Mode 只有两种:

  • kCFRunLoopDefaultMode
  • kCFRunLoopCommonModes

在使用NSTimer时,经常需要考虑是否有必要将 Timer schedule 到 CommonModes 上以防止界面滚动时,NSTimer 的回调事件被强行忽略。那么 Runloop Mode 的数据结构是什么样子的呢?源代码如下。加上简单的注释,先忽略还没学习到的 Sources 相关成员变量。

NOTE:源码中忽略了适配 Windows 平台的代码,且假设部署环境不是 Mac OS。

typedef struct __CFRunLoopMode *CFRunLoopModeRef;

struct __CFRunLoopMode {
    /// 标记CFRunLoopMode是Runtime基础类型
    CFRuntimeBase _base;
    /// 是个递归锁
    pthread_mutex_t _lock;
    /// 名称具有唯一性
    CFStringRef _name;
    /// 是否已终止
    Boolean _stopped;
    /// 保留位。暂时没用
    char _padding[3];
    
#pragma mark - Mode包含的各种源及相关必备数据
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    CFMutableDictionaryRef _portToV1SourceMap;
    __CFPortSet _portSet;
    CFIndex _observerMask;
#if USE_MK_TIMER_TOO
    mach_port_t _timerPort;
    Boolean _mkTimerArmed;
#endif
    uint64_t _timerSoftDeadline; /* TSR */
    uint64_t _timerHardDeadline; /* TSR */
};

其中比较重要的是_name成员,Runloop Mode 是使用名称来标记其唯一性,所以无论是 Runloop Mode 判等,还是哈希,都是使用_name作为入参。

static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) {
    CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1;
    CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2;
    return CFEqual(rlm1->_name, rlm2->_name);
}

static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) {
    CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf;
    return CFHash(rlm->_name);
}

NOTE:注意到 Source0 和 Source1 数据结构是 Set,Observers 和 Timers 的数据结构是 Array,所以初步推测单次循环中 Timer 和 Observers 的处理是必定是有序的,Source0、Source1 的处理可能是无序的。

1.2 Runloop

以下是 CF 源代码对CFRunLoopRef的基本定义。其中_block_item是用于将诸多void(^)(void)类型的 block 串联成单链表的数据结构,包含_mode成员,_block_item可以与某个 Mode 或多个 Mode 绑定,因此_mode可以是CFStringRef类型,也可以是CFSetRef类型。_per_run_data用于记录 Runloop 的状态,其中ab在构建后会被置为常数0x4346524C,作用可以忽略。Runloop 的每次执行 Run 循环前,都会先清空其_perRunData

NOTE:下列源码中视为不重要的成员不作注释。Runloop Modes 相关成员也很重要,但是也没加注释,因为基本可以“顾名思义”。

typedef struct __CFRunLoop * CFRunLoopRef;

struct _block_item {
    /// 下一个节点
    struct _block_item *_next;
    /// 绑定的Mode。注意:_mode可以是字符串,也可以是集合
    CFTypeRef _mode;
    /// 该节点对应的操作
    void (^_block)(void);
};

typedef struct _per_run_data {
    uint32_t a;
    uint32_t b;
    /// 标记Runloop是否已终止
    uint32_t stopped;
    /// 标记Runloop是否忽略外部唤醒
    uint32_t ignoreWakeUps;
} _per_run_data;

struct __CFRunLoop {
    CFRuntimeBase _base;
    /// 递归锁,访问Modes都需要加锁
    pthread_mutex_t _lock;
    /// 用于唤醒该Runloop,调用CFRunLoopWakeUp需要用到
    __CFPort _wakeUpPort;
    Boolean _unused;
    /// 记录单次Run的状态
    volatile _per_run_data *_perRunData;
    /// posix线程
    pthread_t _pthread;
    uint32_t _winthread;
    
    CFMutableSetRef _commonModes;
    CFMutableSetRef _commonModeItems;
    CFRunLoopModeRef _currentMode;
    CFMutableSetRef _modes;
    
    /// 仅供CFRunLoopPerformBlock使用(不太重要)
    struct _block_item *_blocks_head;
    /// 仅供CFRunLoopPerformBlock使用(不太重要)
    struct _block_item *_blocks_tail;
    
    CFAbsoluteTime _runTime;
    CFAbsoluteTime _sleepTime;
    CFTypeRef _counterpart;
};

_modes成员的数据类型可知,Runloop 可以包含多个 Runloop Mode。从_commonModes成员的数据类型可知,Common Modes 并不是单一 Mode,而是多个 Runloop Mode 的集合。从_currentMode成员的数据类型可知,Runloop 不能同时在多个 Mode 上运行。

接下来看看CFRunLoopRef的几个基本操作。

1.2.1 状态管理

状态管理有两种方式:1、使用_base的保留位;2、使用_perRunData成员。两者对应的范围不相同。前者管理 Runloop 的状态,后者管理 Runloop 每次 Run 循环的状态。

例如,对 sleeping 状态的管理。其中,_base成员是用于模拟面向对象继承,其_cfinfo成员是一个数组,使用其CF_INFO_BITS索引的元素的第 1 位记录CFRunLoopRef当前是否处于休眠

CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) {
    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1);
}

CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
}

CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
}

类似的状态管理方式总共有三种,分别使用了_cfinfo[CF_INFO_BITS]的三个 bit 来记录:

  • stopped:第 0 位;
  • sleeping:第 1 位
  • deallocating:第 2 为;

最后,补充CFRuntimeBase以及CF_INFO_BITS的定义。


#if defined(__BIG_ENDIAN__)
#define __CF_BIG_ENDIAN__ 1
#define __CF_LITTLE_ENDIAN__ 0
#endif

#if defined(__LITTLE_ENDIAN__)
#define __CF_LITTLE_ENDIAN__ 1
#define __CF_BIG_ENDIAN__ 0
#endif

#define CF_INFO_BITS (!!(__CF_BIG_ENDIAN__) * 3)

typedef struct __CFRuntimeBase {
    uintptr_t _cfisa;
    uint8_t _cfinfo[4];
#if __LP64__
    uint32_t _rc;
#endif
} CFRuntimeBase;

例如,对 stop 状态的管理:

CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) {
    return (rl->_perRunData->stopped) ? true : false;
}

CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) {
    rl->_perRunData->stopped = 0x53544F50;	// 'STOP'
}

CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) {
    rl->_perRunData->stopped = 0x0;
}

CFRunLoopRef_perRunData的整体操作包括两种:Push 是推入一个初始化的新的_per_run_data实例替换旧的_perRunData成员,并返回旧的_perRunData成员。Pop 是用指定的_per_run_data实例替换_perRunData成员。

CF_INLINE volatile _per_run_data *__CFRunLoopPushPerRunData(CFRunLoopRef rl) {
    volatile _per_run_data *previous = rl->_perRunData;
    rl->_perRunData = (volatile _per_run_data *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(_per_run_data), 0);
    rl->_perRunData->a = 0x4346524C;
    rl->_perRunData->b = 0x4346524C; // 'CFRL'
    rl->_perRunData->stopped = 0x00000000;
    rl->_perRunData->ignoreWakeUps = 0x00000000;
    return previous;
}

CF_INLINE void __CFRunLoopPopPerRunData(CFRunLoopRef rl, volatile _per_run_data *previous) {
    if (rl->_perRunData) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (void *)rl->_perRunData);
    rl->_perRunData = previous;
}

1.2.2 基本操作

首先是 Find Mode 操作。__CFRunLoopFindMode用于在rl_modes成员中查询,是否存在名称为modeNameCFRunLoopMode元素,如果不存在则构建一个名为modeNameCFRunLoopMode并添加到rl_modes成员中。毫无疑问,CFRunLoopRunInMode函数必定会会间接调用__CFRunLoopFindMode

static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
    CHECK_FOR_FORK();
    CFRunLoopModeRef rlm;
    struct __CFRunLoopMode srlm;
    memset(&srlm, 0, sizeof(srlm));
    _CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
    srlm._name = modeName;
    // 关键代码一:查找名为modeName的Mode
    rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
    if (NULL != rlm) {
	__CFRunLoopModeLock(rlm);
	return rlm;
    }
    if (!create) {
	return NULL;
    }
    // 关键代码二:构建名为modeName的Mode
    rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
    if (NULL == rlm) {
	return NULL;
    }
    __CFRunLoopLockInit(&rlm->_lock);
    rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
    rlm->_stopped = false;
    rlm->_portToV1SourceMap = NULL;
    rlm->_sources0 = NULL;
    rlm->_sources1 = NULL;
    rlm->_observers = NULL;
    rlm->_timers = NULL;
    rlm->_observerMask = 0;
    rlm->_portSet = __CFPortSetAllocate();
    rlm->_timerSoftDeadline = UINT64_MAX;
    rlm->_timerHardDeadline = UINT64_MAX;
    
    kern_return_t ret = KERN_SUCCESS;

    ...

#if USE_MK_TIMER_TOO
    // 关键代码3:每个Mode都会构建一个内核mk_timer,Mode的所有Timer本质上都使用这个mk_timer来计时
    rlm->_timerPort = mk_timer_create();
    ret = __CFPortSetInsert(rlm->_timerPort, rlm->_portSet);
    if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
#endif
    
    ret = __CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet);
    if (KERN_SUCCESS != ret) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret);
    
    ...
    
    // 关键代码三:将新构建的名为modeName的Mode添加到_modes成员中
    CFSetAddValue(rl->_modes, rlm);
    CFRelease(rlm);
    __CFRunLoopModeLock(rlm);	/* return mode locked */
    return rlm;
}

其次是判空操作,判空是判断 RunLoop 是否已结束的重要评判标准之一。从__CFRunLoopModeIsEmpty的代码可以看出,其大致的判断标准是以下条件均成立:

  • Source0 为空;
  • Source1 为空;
  • Timers 为空;
  • _block_item成员中包含绑定到rlm的 block;

NOTE:还有个关于 libdispatch 的判断条件,有点复杂,大致意思是添加到主线程 common modes 上的 mode 不会被判断为空,使主线程持续保活。

static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
    CHECK_FOR_FORK();
    if (NULL == rlm) return true;

    ...

    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)) return false; // represents the libdispatch main queue
    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;
}

1.3 MonitorObjects

RunLoop 的可监控对象包括三种:

  • Sources:由外部事件触发回调,可以通过 Signal,可以通过 Port;
  • Observers:RunLoop 状态变更时触发回调;
  • Timers:在特定时间点触发回调;

1.3.1 Source

RunLoop Mode 可以包含若干个源(RunLoop Source),源的类型有两种 Source0 和 Source1,Source0 使用CFRunLoopSourceSignal触发,Source1 使用 Mach Ports 触发。Source0 和 Source1 均使用__CFRunLoopSource表示,通过_context联合体进行区分,联合体的两个成员的主体是一堆函数指针,用于定义源的各种基本操作。

NOTE:注意到其成员_runLoops为复数形式,因此 Source 可以同时被添加到多个 RunLoop 上。

typedef struct {
    CFIndex	version;
    void *	info;
    const void *(*retain)(const void *info);
    void	(*release)(const void *info);
    CFStringRef	(*copyDescription)(const void *info);
    Boolean	(*equal)(const void *info1, const void *info2);
    CFHashCode	(*hash)(const void *info);
    void	(*schedule)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
    void	(*cancel)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
    void	(*perform)(void *info);
} CFRunLoopSourceContext;

typedef struct {
    CFIndex	version;
    void *	info;
    const void *(*retain)(const void *info);
    void	(*release)(const void *info);
    CFStringRef	(*copyDescription)(const void *info);
    Boolean	(*equal)(const void *info1, const void *info2);
    CFHashCode	(*hash)(const void *info);
#if TARGET_OS_OSX || TARGET_OS_IPHONE
    mach_port_t	(*getPort)(void *info);
    void *	(*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);

    ...

} CFRunLoopSourceContext1;

struct __CFRunLoopSource {
    CFRuntimeBase _base;
    /// 状态位
    uint32_t _bits;
    /// 递归锁
    pthread_mutex_t _lock;
    /// 序号
    CFIndex _order;			/* immutable */
    /// 所绑定的RunLoop
    CFMutableBagRef _runLoops;
    /// 上下文,可以是Source0或者Source1
    union {
	CFRunLoopSourceContext version0;	/* immutable, except invalidation */
        CFRunLoopSourceContext1 version1;	/* immutable, except invalidation */
    } _context;
};

RunLoop Source 的状态管理同样使用两种方式:1、使用_base_cfinfo[CF_INFO_BITS];2、使用_bits成员。

例如,使用方式一标记 Source 是否生效:

CF_INLINE Boolean __CFIsValid(const void *cf) {
    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3);
}

CF_INLINE void __CFSetValid(void *cf) {
    __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1);
}

CF_INLINE void __CFUnsetValid(void *cf) {
    __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0);
}

例如,使用方式二标记 Source 是否收到 Signal 信号(针对 Source0);

CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) {
    return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1);
}

CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) {
    __CFBitfieldSetValue(rls->_bits, 1, 1, 1);
}

CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) {
    __CFBitfieldSetValue(rls->_bits, 1, 1, 0);
}

1.3.2 Observer

RunLoop Observer 可以观察 RunLoop 的状态变更。

typedef struct {
    CFIndex	version;
    void *	info;
    const void *(*retain)(const void *info);
    void	(*release)(const void *info);
    CFStringRef	(*copyDescription)(const void *info);
} CFRunLoopObserverContext;

typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);

struct __CFRunLoopObserver {
    CFRuntimeBase _base;
    /// 递归锁
    pthread_mutex_t _lock;
    /// 所观察的RunLoop
    CFRunLoopRef _runLoop;
    /// 所观察的RunLoop计数
    CFIndex _rlCount;
    CFOptionFlags _activities;		/* immutable */
    /// 序号
    CFIndex _order;			/* immutable */
    /// 回调函数
    CFRunLoopObserverCallBack _callout;	/* immutable */
    /// 上下文
    CFRunLoopObserverContext _context;	/* immutable, except invalidation */
};

RunLoop Observer 只使用_base_cfinfo[CF_INFO_BITS]进行状态管理,使用了其中两个位:

  • firing:第 0 位;
  • repeats:第 1 位;
/* Bit 0 of the base reserved bits is used for firing state */
/* Bit 1 of the base reserved bits is used for repeats state */

CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) {
    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0);
}

CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
}

CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0);
}

CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) {
    return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1);
}

CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
}

CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) {
    __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0);
}

RunLoop Observer 的基本操作包括:1、绑定 RunLoop;2、与 RunLoop 解绑。从官方文档中可知 Observer 只能一次只能绑定到一个 RunLoop 上,但是下面的__CFRunLoopObserverSchedule却没有这方面的限制,不过这个逻辑是在CFRunLoopAddObserver上控制的。

NOTE:Each run loop observer can be registered in only one run loop at a time, although it can be added to multiple run loop modes within that run loop.

static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
    __CFRunLoopObserverLock(rlo);
    if (0 == rlo->_rlCount) {
	rlo->_runLoop = rl;
    }
    rlo->_rlCount++;
    __CFRunLoopObserverUnlock(rlo);
}

static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) {
    __CFRunLoopObserverLock(rlo);
    rlo->_rlCount--;
    if (0 == rlo->_rlCount) {
	rlo->_runLoop = NULL;
    }
    __CFRunLoopObserverUnlock(rlo);
}

1.3.3 Timer

至此CFRunLoopTimer的定义实际上和前面几种源基本是相同的套路,不再赘述。

NOTE:Each run loop timer can be registered in only one run loop at a time, although it can be added to multiple run loop modes within that run loop.

typedef struct {
    CFIndex	version;
    void *	info;
    const void *(*retain)(const void *info);
    void	(*release)(const void *info);
    CFStringRef	(*copyDescription)(const void *info);
} CFRunLoopTimerContext;

typedef void (*CFRunLoopTimerCallBack)(CFRunLoopTimerRef timer, void *info);

struct __CFRunLoopTimer {
    CFRuntimeBase _base;
    uint16_t _bits;
    /// 递归锁
    pthread_mutex_t _lock;
    /// 定时器所绑定的RunLoop
    CFRunLoopRef _runLoop;
    /// 定时器所绑定的RunLoopMode
    CFMutableSetRef _rlModes;
    /// 下次触发时间点
    CFAbsoluteTime _nextFireDate;
    CFTimeInterval _interval;		/* immutable */
    CFTimeInterval _tolerance;          /* mutable */
    uint64_t _fireTSR;			/* TSR units */
    CFIndex _order;			/* immutable */
    CFRunLoopTimerCallBack _callout;	/* immutable */
    CFRunLoopTimerContext _context;	/* immutable, except invalidation */
};

/* Bit 0 of the base reserved bits is used for firing state */
/* Bit 1 of the base reserved bits is used for fired-during-callout state */
/* Bit 2 of the base reserved bits is used for waking state */

...

二、构建和析构

该部分了解 RunLoop 及其管理对象是如何构建以及释放的。

2.1 RunLoop构建

对开发者而言,CFRunLoopRef没有提供显式的构建方法,两个可以间接构建 RunLoop 的方法分别是CGRunLoopGetCurrentCFRunLoopGetMain。从下面的源码看,是简单的懒加载的实现——获取 RunLoop 时,存在则直接返回,不存在则调用_CFRunLoopGet0构建。

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;
}

CFRunLoopRef CFRunLoopGetCurrent(void) {
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());
}

_CFRunLoopGet0的实现如下,具体细节注释在代码中。

static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFLock_t loopsLock = CFLockInit;

CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    if (pthread_equal(t, kNilPthreadT)) {
	t = pthread_main_thread_np();
    }
    __CFLock(&loopsLock);
    // 核心操作1:全局记录所有runloop。若为空则构建字典和主线程RunLoop,并记录主线程RunLoop
    if (!__CFRunLoops) {
        __CFUnlock(&loopsLock);
	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
	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);
    }
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    __CFUnlock(&loopsLock);
    // 核心操作2:若全局字典中不存在目标线程的RunLoop,则构建并记录目标线程RunLoop
    if (!loop) {
	CFRunLoopRef newLoop = __CFRunLoopCreate(t);
        __CFLock(&loopsLock);
	loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
	if (!loop) {
	    CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
	    loop = newLoop;
	}
        __CFUnlock(&loopsLock);
	CFRelease(newLoop);
    }
    // 核心操作3:如果目标线程是当前线程,则将RunLoop写入线程的Thread Specific Data,必要时注册RunLoop析构函数,在线程释放时析构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;
}

NOTE:上面线程记录 RunLoop 前,需要先判断目标线程是否为当前线程,原因不太确定。不过从CFRunLoop公开接口看,目标线程非当前线程仅出现在子线程调CFRunLoopGetMain时,此时if分支里面的逻辑确实没有必要执行。另外,关于PTHREAD_DESTRUCTION_ITERATIONS定义见Manual page for pthread_key_create

2.1.1 Observer构建

Observer 构建代码没什么干货,构建时_runLoopNULL_rlCount为 0,因为 Observer 构建阶段显然是未与任何 RunLoop 绑定。

CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
    CHECK_FOR_FORK();
    CFRunLoopObserverRef memory;
    UInt32 size;
    size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
    memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, CFRunLoopObserverGetTypeID(), size, NULL);
    if (NULL == memory) {
	return NULL;
    }
    __CFSetValid(memory);
    __CFRunLoopObserverUnsetFiring(memory);
    if (repeats) {
	__CFRunLoopObserverSetRepeats(memory);
    } else {
	__CFRunLoopObserverUnsetRepeats(memory);
    }
    __CFRunLoopLockInit(&memory->_lock);
    memory->_runLoop = NULL;
    memory->_rlCount = 0;
    memory->_activities = activities;
    memory->_order = order;
    memory->_callout = callout;
    if (context) {
	if (context->retain) {
	    memory->_context.info = (void *)context->retain(context->info);
	} else {
	    memory->_context.info = context->info;
	}
	memory->_context.retain = context->retain;
	memory->_context.release = context->release;
	memory->_context.copyDescription = context->copyDescription;
    } else {
	memory->_context.info = 0;
	memory->_context.retain = 0;
	memory->_context.release = 0;
	memory->_context.copyDescription = 0;
    }
    return memory;
}

2.1.2 Source构建

Source 构建也没什么干货,构建时需要 Source 类型是 Source0 还是 Source1,通过context->version参数来指定。

CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
    CHECK_FOR_FORK();
    CFRunLoopSourceRef memory;
    uint32_t size;
    if (NULL == context) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
    
    size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
    memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, CFRunLoopSourceGetTypeID(), size, NULL);
    if (NULL == memory) {
	return NULL;
    }
    __CFSetValid(memory);
    __CFRunLoopSourceUnsetSignaled(memory);
    __CFRunLoopLockInit(&memory->_lock);
    memory->_bits = 0;
    memory->_order = order;
    memory->_runLoops = NULL;
    size = 0;
    switch (context->version) {
    case 0:
	size = sizeof(CFRunLoopSourceContext);
	break;
    case 1:
	size = sizeof(CFRunLoopSourceContext1);
	break;
    }
    objc_memmove_collectable(&memory->_context, context, size);
    if (context->retain) {
	memory->_context.version0.info = (void *)context->retain(context->info);
    }
    return memory;
}

2.1.3 Timer构建

Timer 构建过程,需要注意到代码中两个局部变量now1now2,两者都表示当前时间,区别是now1是标准时间戳,而now2是通过mach_absolute_time()获取的 CPU Tick Time,也就是说两者的基准是不一样的。构建 Timer 时,fireDate从外部传入赋值给_nextFireDate,再将fireDate转换 CPU Tick Time 赋值给_fireTSR,也就是说_nextFireDate_fireTSR是同义的,只是用了不同的基准。

CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
    CHECK_FOR_FORK();
    if (isnan(interval)) {
        CRSetCrashLogMessage("NaN was used as an interval for a CFRunLoopTimer");
        HALT;
    }
    CFRunLoopTimerRef memory;
    UInt32 size;
    size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
    memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, CFRunLoopTimerGetTypeID(), size, NULL);
    if (NULL == memory) {
	return NULL;
    }
    __CFSetValid(memory);
    __CFRunLoopTimerUnsetFiring(memory);
    __CFRunLoopLockInit(&memory->_lock);
    memory->_runLoop = NULL;
    memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
    memory->_order = order;
    if (interval < 0.0) interval = 0.0;
    memory->_interval = interval;
    memory->_tolerance = 0.0;
    if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
    memory->_nextFireDate = fireDate;
    memory->_fireTSR = 0ULL;
    uint64_t now2 = mach_absolute_time();
    CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
    // 核心逻辑1:标准时间戳转换为CPU Tick Time
    if (fireDate < now1) {
	memory->_fireTSR = now2;
    } else if (TIMER_INTERVAL_LIMIT < fireDate - now1) {
	memory->_fireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
    } else {
	memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
    }
    memory->_callout = callout;
    if (NULL != context) {
	if (context->retain) {
	    memory->_context.info = (void *)context->retain(context->info);
	} else {
	    memory->_context.info = context->info;
	}
	memory->_context.retain = context->retain;
	memory->_context.release = context->release;
	memory->_context.copyDescription = context->copyDescription;
    } else {
	memory->_context.info = 0;
	memory->_context.retain = 0;
	memory->_context.release = 0;
	memory->_context.copyDescription = 0;
    }
    return memory;
}

2.2 RunLoop析构

线程释放时,会触发 Thread Specific Data 释放,若上面的__CFRunLoopGet0方法中将线程的 RunLoop 写入了 TSD,则线程会反复触发 TSD 所对应的析构函数(在这里是_CFSetTSD传入的__CFFinalizeRunLoop函数指针),直到所有 TSD 全部清空,通常最大反复尝试次数是PTHREAD_DESTRUCTOR_ITERATIONS

CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data) {
    CFRunLoopRef rl = NULL;
    // 核心操作1:解除线程和RunLoop的关联
    if (data <= 1) {
	__CFLock(&loopsLock);
	if (__CFRunLoops) {
	    rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
	    if (rl) CFRetain(rl);
	    CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
	}
	__CFUnlock(&loopsLock);
    } else {
        _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(data - 1), (void (*)(void *))__CFFinalizeRunLoop);
    }
    if (rl && CFRunLoopGetMain() != rl) {
        if (NULL != rl->_counterpart) {
            CFRelease(rl->_counterpart);
	    rl->_counterpart = NULL;
        }
        // 核心操作2:移除所有RunLoopMode的Sources
        CFArrayRef array = CFRunLoopCopyAllModes(rl);
        for (CFIndex idx = CFArrayGetCount(array); idx--;) {
            CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
            __CFRunLoopRemoveAllSources(rl, modeName);
        }
        // 核心操作3:移除所有CommonModes的commonModeItems
        __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
        CFRelease(array);
    }
    if (rl) CFRelease(rl);
}

static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) {
    CHECK_FOR_FORK();
    CFRunLoopModeRef rlm;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
        // 核心操作1:如果目标Mode为CommonModes,则移除所有CommonModes的commonModeItems,并递
        // 归移除CommonModes的所有Modes的Sources
	if (NULL != rl->_commonModeItems) {
	    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
	    if (NULL != set) {
                CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl);
		CFRelease(set);
	    }
	}
    } else {
	rlm = __CFRunLoopFindMode(rl, modeName, false);
        // 核心操作2:移除目标Mode的所有Source0
	if (NULL != rlm && NULL != rlm->_sources0) {
	    CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources0);
            CFTypeRef context[2] = {rl, modeName};
            CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
	    CFRelease(set);
	}
        // 核心操作3:移除目标Mode的所有Source1
	if (NULL != rlm && NULL != rlm->_sources1) {
	    CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources1);
            CFTypeRef context[2] = {rl, modeName};
            CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context);
	    CFRelease(set);
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
}

static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) {
    CFStringRef modeName = (CFStringRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)ctx;
    // 核心操作1:移除CommonMode中名称为modeName的Mode的所有Sources。所以CommonMode的移除是递归过程
    __CFRunLoopRemoveAllSources(rl, modeName);
}

static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) {
    CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]);
    // 核心操作1:移除名称为modeName的Mode的目标Source
    CFRunLoopRemoveSource(rl, rls, modeName);
}

void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) {	/* DOES CALLOUT */
    CHECK_FOR_FORK();
    Boolean doVer0Callout = false, doRLSRelease = false;
    __CFRunLoopLock(rl);
    if (modeName == kCFRunLoopCommonModes) {
        //核心操作1:如果目标Mod是CommonModes,
	if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) {
	    CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
            //核心操作1.1:移除commonModeItems中的该Source
	    CFSetRemoveValue(rl->_commonModeItems, rls);
	    if (NULL != set) {
		CFTypeRef context[2] = {rl, rls};
                //核心操作1.2:遍历所有commonModes的Modes,移除目标Source
		CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context);
		CFRelease(set);
	    }
	}
    } else {
	CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false);
        // 核心操作2:如果目标Mode不是CommonModes,则移除目标Mode中的目标Source,Source0和
        // Source1采用不同的处理方式
	if (NULL != rlm && ((NULL != rlm->_sources0 && CFSetContainsValue(rlm->_sources0, rls)) || (NULL != rlm->_sources1 && CFSetContainsValue(rlm->_sources1, rls)))) {
	    CFRetain(rls);
            // 核心操作2.1:如果是Source1类型需要先释放Port
	    if (1 == rls->_context.version0.version) {
		__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
                if (CFPORT_NULL != src_port) {
		    CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port);
                    __CFPortSetRemove(src_port, rlm->_portSet);
                }
	    }
	    CFSetRemoveValue(rlm->_sources0, rls);
	    CFSetRemoveValue(rlm->_sources1, rls);
            __CFRunLoopSourceLock(rls);
            if (NULL != rls->_runLoops) {
                CFBagRemoveValue(rls->_runLoops, rl);
            }
            __CFRunLoopSourceUnlock(rls);
            // 核心操作2.2:如果是Source0类型需要保证cancel调用
	    if (0 == rls->_context.version0.version) {
	        if (NULL != rls->_context.version0.cancel) {
	            doVer0Callout = true;
	        }
	    }
	    doRLSRelease = true;
	}
        if (NULL != rlm) {
	    __CFRunLoopModeUnlock(rlm);
	}
    }
    __CFRunLoopUnlock(rl);
    if (doVer0Callout) {
        rls->_context.version0.cancel(rls->_context.version0.info, rl, modeName);	/* CALLOUT */
    }
    if (doRLSRelease) CFRelease(rls);
}

static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) {
    CFStringRef modeName = (CFStringRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]);
    CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]);
    if (CFGetTypeID(item) == CFRunLoopSourceGetTypeID()) {
	CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopObserverGetTypeID()) {
	CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName);
    } else if (CFGetTypeID(item) == CFRunLoopTimerGetTypeID()) {
	CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName);
    }
}

NOTE:为什么仅非主线程才需要在 Finalize 阶段就提前清空 Sources?为什么只提前清空 Sources 而 Timer 和 Observers 不需要提前清空?

上面代码的最后一句CFRelease会间接调用到__CFRunLoopDeallocate方法(当引用计数清零时),其实__CFRunLoopDeallocate才是真正的 RunLoop 析构操作,基本上是释放各种源所直接持有的容器的过程。

static void __CFRunLoopDeallocate(CFTypeRef cf) {
    CFRunLoopRef rl = (CFRunLoopRef)cf;

    if (_CFRunLoopGet0b(pthread_main_thread_np()) == cf) HALT;

    __CFRunLoopSetDeallocating(rl);
    if (NULL != rl->_modes) {
        // 核心操作1:释放所有Sources对runLoops的反向引用
	CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl
        // 核心操作2:释放Sources、Observers、Timers
	CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl);
	CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl);
	CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl);
    }
    __CFRunLoopLock(rl);
    // 核心操作3:释放Perform Blocks链表
    struct _block_item *item = rl->_blocks_head;
    while (item) {
	struct _block_item *curr = item;
	item = item->_next;
	CFRelease(curr->_mode);
	Block_release(curr->_block);
	free(curr);
    }
    if (NULL != rl->_commonModeItems) {
	CFRelease(rl->_commonModeItems);
    }
    if (NULL != rl->_commonModes) {
	CFRelease(rl->_commonModes);
    }
    if (NULL != rl->_modes) {
	CFRelease(rl->_modes);
    }
    __CFPortFree(rl->_wakeUpPort);
    rl->_wakeUpPort = CFPORT_NULL;
    __CFRunLoopPopPerRunData(rl, NULL);
    __CFRunLoopUnlock(rl);
    pthread_mutex_destroy(&rl->_lock);
    memset((char *)cf + sizeof(CFRuntimeBase), 0x8C, sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase));
}

/// 释放所有Sources对runLoops的反向引用
static void __CFRunLoopCleanseSources(const void *value, void *context) {
    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)context;
    CFIndex idx, cnt;
    const void **list, *buffer[256];
    if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;

    cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0);
    list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
    if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list);
    if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0));
    for (idx = 0; idx < cnt; idx++) {
	CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
	__CFRunLoopSourceLock(rls);
	if (NULL != rls->_runLoops) {
	    CFBagRemoveValue(rls->_runLoops, rl);
	}
	__CFRunLoopSourceUnlock(rls);
    }
    if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}

/// 释放Sources
static void __CFRunLoopDeallocateSources(const void *value, void *context) {
    CFRunLoopModeRef rlm = (CFRunLoopModeRef)value;
    CFRunLoopRef rl = (CFRunLoopRef)context;
    CFIndex idx, cnt;
    const void **list, *buffer[256];
    if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return;

    cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0);
    list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0));
    if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list);
    if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0));
    for (idx = 0; idx < cnt; idx++) {
	CFRetain(list[idx]);
    }
    if (rlm->_sources0) CFSetRemoveAllValues(rlm->_sources0);
    if (rlm->_sources1) CFSetRemoveAllValues(rlm->_sources1);
    for (idx = 0; idx < cnt; idx++) {
        CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx];
        __CFRunLoopSourceLock(rls);
        if (NULL != rls->_runLoops) {
            CFBagRemoveValue(rls->_runLoops, rl);
        }
        __CFRunLoopSourceUnlock(rls);
        if (0 == rls->_context.version0.version) {
            if (NULL != rls->_context.version0.cancel) {
                rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name);	/* CALLOUT */
            }
        } else if (1 == rls->_context.version0.version) {
            __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info);	/* CALLOUT */
            if (CFPORT_NULL != port) {
                __CFPortSetRemove(port, rlm->_portSet);
            }
        }
	CFRelease(rls);
    }
    if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}

static void __CFRunLoopDeallocateObservers(const void *value, void *context) {
    ...
}

static void __CFRunLoopDeallocateTimers(const void *value, void *context) {
    ...
}

NOTE:为什么__CFRunLoopCleanseSources__CFRunLoopDeallocateSources有一半代码相同?为什么非得这样写?

总结

篇幅限制先写到这里。其实 NOTE 中仍然有些没有闹明白的问题,不过都不太重要,那些都是源代码实现上的细节处理,对理解 RunLoop 的影响是很小的。也许下次看就能闹明白了。后面再学习 RunLoop 的核心逻辑:处理各种监控对象、CommonModes 管理。