RunLoop
在 0202 年的今天其實(shí)已經(jīng)不是個(gè)新鮮的話題了且改,關(guān)于這方面的文章網(wǎng)上有很多大神總結(jié)得非常精辟拘央。
作為 iOS
查漏補(bǔ)缺系列斋日,這篇文章是筆者探索 RunLoop
底層的一些知識(shí)點(diǎn)總結(jié)渴杆,同時(shí)也借鑒了網(wǎng)上一些優(yōu)秀的 RunLoop
技術(shù)文章的內(nèi)容林艘。
本文內(nèi)容如有錯(cuò)誤盖奈,歡迎指正。
RunLoop 前導(dǎo)知識(shí)
iOS/OS X 系統(tǒng)架構(gòu)
iOS 進(jìn)化史
Mac OS Classic 擁有偉大的 GUI狐援,但系統(tǒng)設(shè)計(jì)卻非常糟糕钢坦,尤其是協(xié)作式的多任務(wù)系統(tǒng)和低效的內(nèi)存管理,以今天的標(biāo)準(zhǔn)看非常原始啥酱。
NeXTSTEP 操作系統(tǒng)作為喬布斯回歸蘋(píng)果的嫁妝爹凹,連同架構(gòu)中的 Mach 和 OC 等一起融合進(jìn)了Mac OS Classic。與其說(shuō)是 Mac OS Classic 融合了 NeXTSTEP镶殷,不如說(shuō)是后者反客為主替換了前者禾酱,這個(gè)轉(zhuǎn)變并不是一瞬間發(fā)生的。
Mac OS Classic 擁有不錯(cuò)的 GUI 但系統(tǒng)設(shè)計(jì)糟糕绘趋,NeXTSTEP 設(shè)計(jì)很棒颤陶,但 GUI 非常平淡。這兩個(gè)小眾操作系統(tǒng)融合的結(jié)果是一個(gè)繼承二者優(yōu)點(diǎn)的成功得多的全新操作系統(tǒng)—Mac OS X
全新的 Mac OS X 在設(shè)計(jì)與實(shí)現(xiàn)上都同 NeXTSTEP 非常接近陷遮,諸如 Cocoa滓走、Mach 、Interface Builder 等核心組件都源自 NeXTSTEPiOS 最初稱為 iPhone OS,是 Mac OS X 應(yīng)對(duì)移動(dòng)平臺(tái)的分支帽馋,iOS 擁有和
Mac OS X
一樣的操作系統(tǒng)層次結(jié)構(gòu)以及相同的操作系統(tǒng)核心Dawin搅方。
iOS 系統(tǒng)架構(gòu)
蘋(píng)果官方將整個(gè)系統(tǒng)大致劃分為上述4個(gè)層次:
應(yīng)用層包括用戶能接觸到的圖形應(yīng)用,例如 Spotlight绽族、Aqua(macOS)姨涡、SpringBoard(iOS) 等。
應(yīng)用框架層即開(kāi)發(fā)人員接觸到的 Cocoa 等框架项秉。
核心框架層包括各種核心框架绣溜、OpenGL 等內(nèi)容。
Darwin層是操作系統(tǒng)核心娄蔼,包括 XNU 內(nèi)核(2017 年已開(kāi)源)怖喻、驅(qū)動(dòng)和 UNIX shell
Darwin 架構(gòu)
Darwin 的內(nèi)核是 XNU底哗,XNU is Not Unix。XNU 是兩種技術(shù)的混合體锚沸,Mach和BSD跋选。BSD 層確保了 Darwin 系統(tǒng)的 UNIX 特性,真正的內(nèi)核是 Mach哗蜈,但是對(duì)外部隱藏前标。BSD 以上屬于用戶態(tài),所有的內(nèi)容都可以被應(yīng)用程序訪問(wèn)距潘,而應(yīng)用程序不能訪問(wèn)內(nèi)核態(tài)炼列。當(dāng)需要從用戶態(tài)切換到內(nèi)核態(tài)的時(shí)候,需要通過(guò) mach trap 實(shí)現(xiàn)切換音比。
---《深入解析Mac OS X & iOS 操作系統(tǒng)》
其中俭尖,在硬件層上面的三個(gè)組成部分:Mach、BSD洞翩、IOKit (還包括一些上面沒(méi)標(biāo)注的內(nèi)容)稽犁,共同組成了 XNU 內(nèi)核。
XNU 內(nèi)核的內(nèi)環(huán)被稱作 Mach骚亿,其作為一個(gè)微內(nèi)核已亥,僅提供了諸如處理器調(diào)度、IPC (進(jìn)程間通信)等非常少量的基礎(chǔ)服務(wù)来屠。
BSD 層可以看作圍繞 Mach 層的一個(gè)外環(huán)虑椎,其提供了諸如進(jìn)程管理、文件系統(tǒng)和網(wǎng)絡(luò)等功能俱笛。
IOKit 層是為設(shè)備驅(qū)動(dòng)提供了一個(gè)面向?qū)ο?C++)的一個(gè)框架绣檬。
Mach 本身提供的 API 非常有限,而且蘋(píng)果也不鼓勵(lì)使用 Mach 的 API嫂粟,但是這些API非辰课矗基礎(chǔ),如果沒(méi)有這些API的話星虹,其他任何工作都無(wú)法實(shí)施零抬。
在 Mach 中,所有的東西都是通過(guò)自己的對(duì)象實(shí)現(xiàn)的宽涌,進(jìn)程平夜、線程和虛擬內(nèi)存都被稱為”對(duì)象”。和其他架構(gòu)不同卸亮, Mach 的對(duì)象間不能直接調(diào)用忽妒,只能通過(guò)消息傳遞的方式實(shí)現(xiàn)對(duì)象間的通信。
”消息”是 Mach 中最基礎(chǔ)的概念,消息在兩個(gè)端口 (port) 之間傳遞段直,這就是 Mach 的 IPC (進(jìn)程間通信) 的核心吃溅。
--- 《深入理解RunLoop》ibireme
mach_msg 函數(shù)
mach_msg
函數(shù)位于 mach
內(nèi)核的 message.h
頭文件中
這是系統(tǒng)內(nèi)核在某個(gè) port 收發(fā)消息所使用的函數(shù),理解這個(gè)函數(shù)對(duì)于理解 runloop 的運(yùn)行機(jī)制非常重要鸯檬。
詳細(xì)的說(shuō)明可參考 這里。
// mach 消息基礎(chǔ)結(jié)構(gòu)體
typedef struct{
// 消息頭部
mach_msg_header_t header;
// 消息體
mach_msg_body_t body;
} mach_msg_base_t;
// mach 消息頭結(jié)構(gòu)體
typedef struct{
// 消息頭的 bits
mach_msg_bits_t msgh_bits;
// 消息頭的大小
mach_msg_size_t msgh_size;
// 遠(yuǎn)程端口號(hào)
mach_port_t msgh_remote_port;
// 本地端口號(hào)
mach_port_t msgh_local_port;
// 憑證端口號(hào)
mach_port_name_t msgh_voucher_port;
// 消息ID
mach_msg_id_t msgh_id;
} mach_msg_header_t;
// mach_msg 函數(shù)
mach_msg_return_t mach_msg(
// 消息頭
mach_msg_header_t *msg,
// 消息選項(xiàng)喧务,可用來(lái)指定是發(fā)消息(MACH_SEND_MSG)還是收消息(MACH_RCV_MSG)
mach_msg_option_t option,
// 發(fā)消息時(shí)設(shè)置的緩存區(qū)大小赖歌,無(wú)符號(hào)整型
mach_msg_size_t send_size,
// 收消息時(shí)設(shè)置的緩存區(qū)大小,無(wú)符號(hào)整型
mach_msg_size_t rcv_size,
// 收消息的端口功茴,無(wú)符號(hào)整型
mach_port_name_t rcv_name,
// 消息過(guò)期時(shí)間
// 當(dāng) option 參數(shù)中包含 MACH_SEND_TIMEOUT 或 MACH_RCV_TIMEOUT 的時(shí)候庐冯,傳入以毫秒單位的過(guò)期時(shí)間
mach_msg_timeout_t timeout,
// 接收通知的端口
// 當(dāng) option 參數(shù)中包含 MACH_SEND_CANCEL 和 MACH_RCV_NOTIFY 時(shí),設(shè)置接收通知的端口坎穿;否則肄扎,傳入 MACH_PORT_NULL。
mach_port_name_t notify);
可以簡(jiǎn)單的將 mach_msg 理解為多進(jìn)程之間的一種通信機(jī)制赁酝,不同的進(jìn)程可以使用同一個(gè)消息隊(duì)列來(lái)交流數(shù)據(jù),當(dāng)使用 mach_msg 從消息隊(duì)列里讀取 msg 時(shí)旭等,可以在參數(shù)中設(shè)置 timeout 值酌呆,在 timeout 之前如果沒(méi)有讀到 msg,當(dāng)前線程會(huì)一直處于休眠狀態(tài)隙袁。這也是 runloop 在沒(méi)有任務(wù)可執(zhí)行的時(shí)候弃榨,能夠進(jìn)入 sleep 狀態(tài)的原因菩收。
--- 《解密 Runloop》MrPeak
為了實(shí)現(xiàn)消息的發(fā)送和接收,mach_msg() 函數(shù)實(shí)際上是調(diào)用了一個(gè) Mach 陷阱 (trap)鲸睛,即函數(shù) mach_msg_trap()娜饵,陷阱這個(gè)概念在 Mach 中等同于系統(tǒng)調(diào)用。當(dāng)你在用戶態(tài)調(diào)用 mach_msg_trap() 時(shí)會(huì)觸發(fā)陷阱機(jī)制官辈,切換到內(nèi)核態(tài)箱舞;內(nèi)核態(tài)中內(nèi)核實(shí)現(xiàn)的 mach_msg() 函數(shù)會(huì)完成實(shí)際的工作。
--- 《深入理解RunLoop》ibireme
CoreFoundation 基礎(chǔ)
CoreFoundation 是一套基于 C
的 API
拳亿,為 iOS
提供了基本數(shù)據(jù)管理和服務(wù)功能晴股。因?yàn)?CoreFoundation 對(duì)象是基于 C 實(shí)現(xiàn)的,也有引用計(jì)數(shù)的概念怎诫,而 Foundation 對(duì)象是基于 OC 實(shí)現(xiàn)的涌哲。兩種對(duì)象在相互轉(zhuǎn)換的時(shí)候需要用到三個(gè)關(guān)鍵字: bridge初烘、bridge_retained吗铐、__bridge_transfer镊逝,下面進(jìn)行簡(jiǎn)單的介紹减江。
__bridge
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;
將 Objective-C 的對(duì)象類型用 *bridge 轉(zhuǎn)換為 void 類型和使用 **unsafe_unretained 關(guān)鍵字修飾的變量是一樣的巡莹。
__bridge: 只做類型轉(zhuǎn)換腰根,不修改相關(guān)對(duì)象的引用計(jì)數(shù)东帅,原來(lái)的 Core Foundation 對(duì)象在不用時(shí)坎炼,需要調(diào)用 CFRelease 方法
__bridge_retained
d obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;
從名字上我們應(yīng)該能理解其意義:類型被轉(zhuǎn)換時(shí),其對(duì)象的所有權(quán)也將被變換后變量所持有。<br />如果是 MRC 中:
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
下面的例子驗(yàn)證了出了大括號(hào)的范圍后瑞侮,p 仍然指向一個(gè)有效的實(shí)體梅掠。說(shuō)明她擁有該對(duì)象的所有權(quán)都哭,該對(duì)象沒(méi)有因?yàn)槌銎涠x范圍而被銷毀。
void *p = 0;
{
id obj = [[NSObject alloc] init];
p = (__bridge_retained void *)obj;
}
NSLog(@"class=%@", [(__bridge id)p class]);
__bridge_retained: 類型轉(zhuǎn)換后,將相關(guān)對(duì)象的引用計(jì)數(shù)加 1,原來(lái)的 Core Foundation 對(duì)象在不用時(shí)迂烁,需要調(diào)用 CFRelease 方法
__bridge_transfer
MRC 中:
// p 變量原先持有對(duì)象的所有權(quán)
id obj = (id)p;
[obj retain];
[(id)p release];
ARC 中:
// p 變量原先持有對(duì)象的所有權(quán)
id obj = (__bridge_transfer id)p;
可以看出來(lái),**bridge_retained 是編譯器替我們做了 retain 操作屈溉,而 **bridge_transfer 是替我們做了 release场航。
__bridge_transfer: 類型轉(zhuǎn)換后孩饼,將該對(duì)象的引用計(jì)數(shù)交給 ARC 管理,Core Foundation 對(duì)象在不用時(shí)竹挡,不需要調(diào)用 CFRelease 方法
Toll-Free bridged
CoreFoundation 和 Foundation 之間有一個(gè) Toll-free bridging
機(jī)制镀娶。<br />在 MRC 時(shí)代,可以直接通過(guò)類型強(qiáng)轉(zhuǎn)完成兩個(gè)框架對(duì)象的類型轉(zhuǎn)換贤重。但是在 ARC 時(shí)代疤祭,則需要使用 Toll-free bridging
機(jī)制提供的方法來(lái)操作。上面已經(jīng)介紹了三種不同的轉(zhuǎn)換機(jī)制,而實(shí)際上在 Foundation 中,有更簡(jiǎn)便的方法來(lái)操作。如下所示:
// After using a CFBridgingRetain on an NSObject, the caller must take responsibility for calling CFRelease at an appropriate time.
NS_INLINE CF_RETURNS_RETAINED CFTypeRef _Nullable CFBridgingRetain(id _Nullable X) {
return (__bridge_retained CFTypeRef)X;
}
NS_INLINE id _Nullable CFBridgingRelease(CFTypeRef CF_CONSUMED _Nullable X) {
return (__bridge_transfer id)X;
}
CFBridgingRetain 可以代替 **bridge_retained搜囱,CFBridgingRelease 可以代替 **bridge_transfer咐蚯。
RunLoop 初探
什么是 RunLoop
根據(jù)蘋(píng)果官方文檔的定義
Run loops are part of the fundamental infrastructure associated with threads.
RunLoop 是與線程相關(guān)的基礎(chǔ)結(jié)構(gòu)渠旁。
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
RunLoop 是一個(gè)調(diào)度任務(wù)和處理事件的事件循環(huán)饵沧。其意義在于讓線程有事做的時(shí)候繁忙起來(lái)绪撵,沒(méi)事做的時(shí)候休眠瓢姻。
了解過(guò) NodeJS
事件循環(huán)機(jī)制的同學(xué)應(yīng)該不會(huì)對(duì) 事件循環(huán)
這一名詞陌生,用偽代碼實(shí)現(xiàn)如下:
while(AppIsRunning) {
id whoWakesMe = SleepForWakingUp();
id event = GetEvent(whoWakesMe);
HandleEvent(event);
}
這份偽代碼來(lái)自 sunnyx 大神的 RunLoop 技術(shù)分享
可以看到音诈,RunLoop 就是這么一個(gè)簡(jiǎn)單的工作原理幻碱。但是其內(nèi)部實(shí)現(xiàn)要比上面的代碼復(fù)雜得多。我們下一節(jié)將深入 RunLoop 底層一探究竟细溅。
OSX/iOS 系統(tǒng)中褥傍,提供了兩個(gè)這樣的對(duì)象:NSRunLoop 和 CFRunLoopRef。
CFRunLoopRef 是在 CoreFoundation 框架內(nèi)的喇聊,它提供了純 C 函數(shù)的 API摔桦,所有這些 API 都是線程安全的。
NSRunLoop 是基于 CFRunLoopRef 的封裝承疲,提供了面向?qū)ο蟮?API邻耕,但是這些 API 不是線程安全的。
RunLoop 底層數(shù)據(jù)結(jié)構(gòu)
如上圖所示燕鸽,每一個(gè) RunLoop 內(nèi)部有多個(gè) mode兄世,而每一個(gè) mode 內(nèi)部有 sources0,source1, observers 和 timers啊研。mode 中的元素統(tǒng)稱為 mode item
御滩。下面我們一起回顧下這五個(gè)類的數(shù)據(jù)結(jié)構(gòu)定義:
- CFRunLoopRef
- CFRunLoopModeRef
- CFRunLoopSourceRef
- CFRunLoopTimerRef
- CFRunLoopObserverRef
CFRunLoopRef
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop
{
// CoreFoundation 中的 runtime 基礎(chǔ)信息
CFRuntimeBase _base;
// 針對(duì)獲取 mode 列表操作的鎖
pthread_mutex_t _lock; /* locked for accessing mode list */
// 喚醒端口
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
// 是否使用過(guò)
Boolean _unused;
// runloop 運(yùn)行會(huì)重置的一個(gè)數(shù)據(jù)結(jié)構(gòu)
volatile _per_run_data *_perRunData; // reset for runs of the run loop
// runloop 所對(duì)應(yīng)線程
pthread_t _pthread;
uint32_t _winthread;
// 存放 common mode 的集合
CFMutableSetRef _commonModes;
// 存放 common mode item 的集合
CFMutableSetRef _commonModeItems;
// runloop 當(dāng)前所在 mode
CFRunLoopModeRef _currentMode;
// 存放 mode 的集合
CFMutableSetRef _modes;
// runloop 內(nèi)部 block 鏈表表頭指針
struct _block_item *_blocks_head;
// runloop 內(nèi)部 block 鏈表表尾指針
struct _block_item *_blocks_tail;
// 運(yùn)行時(shí)間點(diǎn)
CFAbsoluteTime _runTime;
// 休眠時(shí)間點(diǎn)
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};
// 每次 RunLoop 運(yùn)行后會(huì)重置
typedef struct _per_run_data
{
uint32_t a;
uint32_t b;
uint32_t stopped; // runloop 是否停止
uint32_t ignoreWakeUps; // runloop 是否已喚醒
} _per_run_data;
// 鏈表節(jié)點(diǎn)
struct _block_item
{
// 指向下一個(gè) _block_item
struct _block_item *_next;
// 要么是 string 類型,要么是集合類型党远,也就是說(shuō)一個(gè) block 可能對(duì)應(yīng)單個(gè)或多個(gè) mode
CFTypeRef _mode; // CFString or CFSet
// 存放的真正要執(zhí)行的 block
void (^_block)(void);
};
通過(guò)上面的代碼可以看出削解,CFRunLoopRef 其實(shí)是一個(gè) __CFRunLoop
類型的結(jié)構(gòu)體指針。__CFRunLoop
內(nèi)部以下屬性需要重點(diǎn)關(guān)注:
_pthread
_commonModes
_currentMode
_modes
CFRunLoopModeRef
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode
{
// CoreFoundation 中的 runtime 基礎(chǔ)信息
CFRuntimeBase _base;
// 互斥鎖沟娱,加鎖前需要 runloop 先加鎖
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
// mode 的名稱
CFStringRef _name;
// mode 是否停止
Boolean _stopped;
char _padding[3];
// source0
CFMutableSetRef _sources0;
// source1
CFMutableSetRef _sources1;
// observers
CFMutableArrayRef _observers;
// timers
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
// port 的集合
__CFPortSet _portSet;
// observer 的 mask
CFIndex _observerMask;
// 如果定義了 GCD 定時(shí)器
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// GCD 定時(shí)器
dispatch_source_t _timerSource;
// 隊(duì)列
dispatch_queue_t _queue;
// 當(dāng) GCD 定時(shí)器觸發(fā)時(shí)設(shè)置為 true
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
// 如果使用 MK_TIMER
#if USE_MK_TIMER_TOO
// MK_TIMER 的 port
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
// 定時(shí)器軟臨界點(diǎn)
uint64_t _timerSoftDeadline; /* TSR */
// 定時(shí)器硬臨界點(diǎn)
uint64_t _timerHardDeadline; /* TSR */
};
通過(guò)上面的代碼可以看出氛驮,CFRunLoopModeRef 其實(shí)是一個(gè) __CFRunLoopMode
類型的結(jié)構(gòu)體指針。<br />__CFRunLoopMode
內(nèi)部以下屬性需要重點(diǎn)關(guān)注:
_sources0
_sources1
_observers
_timers
CFRunLoopSourceRef
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
struct __CFRunLoopSource
{
// CoreFoundation 中的 runtime 基礎(chǔ)信息
CFRuntimeBase _base;
uint32_t _bits;
// 互斥鎖
pthread_mutex_t _lock;
// source 的優(yōu)先級(jí)济似,值為小矫废,優(yōu)先級(jí)越高
CFIndex _order; /* immutable */
// runloop 集合
CFMutableBagRef _runLoops;
// 一個(gè)聯(lián)合體,說(shuō)明 source 要么為 source0砰蠢,要么為 source1
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
typedef struct {
CFIndex version;
// source 的信息
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
// 判斷 source 相等的函數(shù)
Boolean (*equal)(const void *info1, const void *info2);
CFHashCode (*hash)(const void *info);
void (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode);
void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode);
// source 要執(zhí)行的任務(wù)塊
void (*perform)(void *info);
} CFRunLoopSourceContext;
通過(guò)上面的代碼可以看出蓖扑,CFRunLoopSourceRef 其實(shí)是一個(gè) __CFRunLoopSource
類型的結(jié)構(gòu)體指針律杠。<br />__CFRunLoopSource
的結(jié)構(gòu)相對(duì)來(lái)說(shuō)要簡(jiǎn)單一點(diǎn),有幾個(gè)屬性要重點(diǎn)關(guān)注:
_order
_context
-
CFRunLoopSourceContext
下的perform
函數(shù)指針
CFRunLoopTimerRef
typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
struct __CFRunLoopTimer
{
// CoreFoundation 中的 runtime 基礎(chǔ)信息
CFRuntimeBase _base;
uint16_t _bits;
// 互斥鎖
pthread_mutex_t _lock;
// timer 對(duì)應(yīng)的 runloop
CFRunLoopRef _runLoop;
// timer 對(duì)應(yīng)的 mode 集合
CFMutableSetRef _rlModes;
// 下一次觸發(fā)時(shí)間點(diǎn)
CFAbsoluteTime _nextFireDate;
// 定時(shí)器每次任務(wù)的間隔
CFTimeInterval _interval; /* immutable */
// 定時(shí)器所允許的誤差
CFTimeInterval _tolerance; /* mutable */
// 觸發(fā)時(shí)間點(diǎn)
uint64_t _fireTSR; /* TSR units */
// 定時(shí)器的優(yōu)先級(jí)
CFIndex _order; /* immutable */
// 定時(shí)器所要執(zhí)行的任務(wù)
CFRunLoopTimerCallBack _callout; /* immutable */
// 定時(shí)器上下文
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
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);
通過(guò)上面的代碼可以看出灰嫉,CFRunLoopTimerRef 其實(shí)是一個(gè) __CFRunLoopTimer
類型的結(jié)構(gòu)體指針诡蜓,并且這里 __CFRunLoopTimer
在前面還有一個(gè) CF_BRIDGED_MUTABLE_TYPE(NSTimer)
#define CF_BRIDGED_TYPE(T) __attribute__((objc_bridge(T)))
#define CF_BRIDGED_MUTABLE_TYPE(T) __attribute__((objc_bridge_mutable(T)))
#define CF_RELATED_TYPE(T,C,I) __attribute__((objc_bridge_related(T,C,I)))
#else
#define CF_BRIDGED_TYPE(T)
#define CF_BRIDGED_MUTABLE_TYPE(T)
#define CF_RELATED_TYPE(T,C,I)
#endif
從這里說(shuō)明 CFRunLoopTimerRef
與 NSTimer
是 toll-free bridged
的胰挑。
__CFRunLoopTimer
中有幾個(gè)屬性需要重點(diǎn)關(guān)注:
- _order
- _callout
- _context
CFRunLoopObserverRef
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
struct __CFRunLoopObserver
{
// CoreFoundation 中的 runtime 基礎(chǔ)信息
CFRuntimeBase _base;
// 互斥鎖
pthread_mutex_t _lock;
// observer 對(duì)應(yīng)的 runloop
CFRunLoopRef _runLoop;
// observer 觀察了多少個(gè) runloop
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
// observer 優(yōu)先級(jí)
CFIndex _order; /* immutable */
// observer 回調(diào)函數(shù)
CFRunLoopObserverCallBack _callout; /* immutable */
// observer 上下文
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
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);
通過(guò)上面的代碼可以看出瞻颂,CFRunLoopObserverRef 其實(shí)是一個(gè) __CFRunLoopObserver
類型的結(jié)構(gòu)體指針贡这。
__CFRunLoopObserver
中有幾個(gè)屬性需要重點(diǎn)關(guān)注:
- _order
- _callout
- _context
CFRunLoopActivity
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
通過(guò)上面的源碼可知盖矫,RunLoop 有以下?tīng)顟B(tài)
- kCFRunLoopEntry: 即將進(jìn)入 Loop
- kCFRunLoopBeforeTimers: 即將處理 Timer
- kCFRunLoopBeforeSources: 即將處理 Source
- kCFRunLoopBeforeWaiting: 即將進(jìn)入休眠
- kCFRunLoopAfterWaiting: 剛從休眠中喚醒
- kCFRunLoopExit: 即將推出 Loop
RunLoop 與線程關(guān)系
要想搞清楚 RunLoop 與線程的關(guān)系责掏,我們從 CFRunLoopGetMain
和 CFRunLoopGetCurrent
函數(shù)開(kāi)始研究:
CFRunLoopRef CFRunLoopGetMain(void)
{
CHECK_FOR_FORK();
// 聲明一個(gè)空的 RunLoop
static CFRunLoopRef __main = NULL; // no retain needed
// 如果 __main 為空换衬,則調(diào)用 _CFRunLoopGet0 函數(shù)來(lái)獲取 RunLoop
if (!__main)
__main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
CFRunLoopRef CFRunLoopGetCurrent(void)
{
CHECK_FOR_FORK();
// 從 線程的 TSD(Thread Specific Data) 中獲取 runloop
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
// 如果拿到了就返回
if (rl)
return rl;
// 如果在 TSD 中沒(méi)有瞳浦,那么就調(diào)用 _CFRunLoopGet0 函數(shù)
return _CFRunLoopGet0(pthread_self());
}
pthread_main_thread_np()
獲取的是主線程叫潦,其內(nèi)部實(shí)現(xiàn)如下
#define pthread_main_thread_np() _CF_pthread_main_thread_np()
CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
pthread_t _CF_pthread_main_thread_np(void) {
return _CFMainPThread;
}void __CFInitialize(void) {
..._CFMainPThread = pthread_self();
...
}
我們接著探索 _CFRunLoopGet0
函數(shù)诅挑,其實(shí)現(xiàn)如下
// 存儲(chǔ)了 runloop 與線程的字典
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFLock_t loopsLock = CFLockInit;
// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
// t為0的話拔妥,表示是要獲取 主線程對(duì)應(yīng)的 RunLoop
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t)
{
// 如果傳入的現(xiàn)場(chǎng)為空,則再通過(guò) pthread_main_thread_np() 獲取到主線程
if (pthread_equal(t, kNilPthreadT))
{
t = pthread_main_thread_np();
}
// 加鎖
__CFLock(&loopsLock);
// 如果 __CFRunLoops 字典為空达箍,則初始化字典没龙,并把 mainLoop 加入字典
if (!__CFRunLoops)
{
// 解鎖
__CFUnlock(&loopsLock);
// 初始化一個(gè) 可變字典
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
// 拿到主線程對(duì)應(yīng)的 RunLoop
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
// 將 runloop 和 線程存入字典中,線程為 key硬纤,runloop 為 value
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void *volatile *)&__CFRunLoops))
{
// 釋放 字典
CFRelease(dict);
}
// 釋放 mainLoop
CFRelease(mainLoop);
// 加鎖
__CFLock(&loopsLock);
}
// 根據(jù)傳入的 線程 t 從字典中獲取 loop 對(duì)象
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
// 對(duì) loops 字典解鎖
__CFUnlock(&loopsLock);
// 如果 loop 為空
if (!loop)
{
// 創(chuàng)建一個(gè)新的 loop
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
// 對(duì) loops 字典加鎖
__CFLock(&loopsLock);
// 從 loops 字典中獲取 loop
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop)
{
// 如果在字典中沒(méi)有找到 loop洼裤,把新的 loop 存入 loops 字典中
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
// don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
// 不要在 字典鎖作用域里面釋放 runloop 對(duì)象,因?yàn)?CFRunLoopDeallocate 會(huì)釋放掉 runloop
__CFUnlock(&loopsLock);
// 釋放 newLoop
CFRelease(newLoop);
}
// 判斷 t 是否是當(dāng)前線程
if (pthread_equal(t, pthread_self()))
{
// 設(shè)置 thread specific data移国,簡(jiǎn)稱 TSD,這也是一個(gè)字典
// 以 __CFTSDKeyRunLoop 為 key, loop 對(duì)象為 value 存入 TSD 中
/**
// Set some thread specific data in a pre-assigned slot. Don't pick a random value.
Make sure you're using a slot that is unique.
Pass in a destructor to free this data, or NULL if none is needed. Unlike pthread TSD, the destructor is per-thread.
// 和 pthread 的 TSD 不一樣的時(shí)祝懂,第三個(gè)參數(shù) 析構(gòu)函數(shù)指針是每個(gè)線程都擁有的
CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, void (*destructor)(void *));
*/
_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr))
{
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS - 1), (void (*)(void *))__CFFinalizeRunLoop);
}
}
return loop;
}
通過(guò)上面的源碼,我們明確了在底層有一個(gè)字典的數(shù)據(jù)結(jié)構(gòu)。<br />這個(gè)字典存儲(chǔ)方式的是以 pthread_t
線程為 key缕允,CFRunLoopRef 為 value。<br />我們可以有以下的結(jié)論:
- 每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
- RunLoop 保存在一個(gè)全局的 Dictionary 里驾霜,線程作為 key,RunLoop 作為 value
- 線程剛創(chuàng)建時(shí)并沒(méi)有 RunLoop 對(duì)象蓉冈,RunLoop 會(huì)在第一次獲取它時(shí)創(chuàng)建
- RunLoop 會(huì)在線程結(jié)束時(shí)銷毀
- 主線程的 RunLoop 已經(jīng)自動(dòng)獲燃叶帷(創(chuàng)建)拉馋,子線程默認(rèn)沒(méi)有開(kāi)啟RunLoop
Runloop 底層
RunLoop 啟動(dòng)方式
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);
}
由上面的源碼可知:
- 默認(rèn)啟動(dòng)方式,底層是通過(guò)
CFRunLoopRun
來(lái)實(shí)現(xiàn)景馁,超時(shí)時(shí)間傳入的是1.0e10
绰精,這是一個(gè)很大的數(shù)字卿樱,所以可以理解為不超時(shí)繁调。 - 自定義啟動(dòng)方式,可以配置超時(shí)時(shí)間以及 mode 等其它參數(shù)裕寨。
RunLoop 核心邏輯
我們接著進(jìn)入 CFRunLoopRunSpecific
:
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)
{ /* DOES CALLOUT */
CHECK_FOR_FORK();
// 如果 runloop 正在回收中,直接返回 kCFRunLoopRunFinished 庆猫,表示 runloop 已經(jīng)完成
if (__CFRunLoopIsDeallocating(rl))
return kCFRunLoopRunFinished;
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 從 runloop 中查找給定的 mode
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
// 如果找不到 mode好渠,且當(dāng)前 runloop 的 currentMode 也為空,進(jìn)入 if 邏輯
// __CFRunLoopModeIsEmpty 函數(shù)結(jié)果為空的話霍掺,說(shuō)明 runloop 已經(jīng)處理完所有任務(wù)
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode))
{
Boolean did = false;
// 如果 currentMode 不為空
if (currentMode)
// 對(duì) currentMode 解鎖
__CFRunLoopModeUnlock(currentMode);
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
// 暫時(shí)取出 runloop 的 per_run_data
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
// 取出 runloop 的當(dāng)前 mode
CFRunLoopModeRef previousMode = rl->_currentMode;
// 將查找到的 mode 賦值到 runloop 的 _curentMode,也就是說(shuō)在這 runloop 完成了 mode 的切換
rl->_currentMode = currentMode;
// 初始化返回結(jié)果 result
int32_t result = kCFRunLoopRunFinished;
// 如果注冊(cè)了 observer 監(jiān)聽(tīng) kCFRunLoopEntry 狀態(tài)(即將進(jìn)入 loop)兔魂,則通知 observer
if (currentMode->_observerMask & kCFRunLoopEntry)
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
// runloop 核心函數(shù) __CFRunLoopRun
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
// 如果注冊(cè)了 observer 監(jiān)聽(tīng) kCFRunLoopExit 狀態(tài)(即將推出 loop)长酗,則通知 observer
if (currentMode->_observerMask & kCFRunLoopExit)
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
// 對(duì) currentMode 解鎖
__CFRunLoopModeUnlock(currentMode);
// 還原原來(lái)的 previousPerRun
__CFRunLoopPopPerRunData(rl, previousPerRun);
// 還原原來(lái)的 mode
rl->_currentMode = previousMode;
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
return result;
}
這塊的代碼精簡(jiǎn)一下之后:
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)
{ /* DOES CALLOUT */
// 通知 Observers 進(jìn)入 loop
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
// 具體要做的事情
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
// 通知 Observers 退出 loop
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
return result;
}
功夫不負(fù)有心人吊奢,終于來(lái)到了最核心的流程 __CFRunLoopRun
函數(shù)页滚,說(shuō)白了,一次運(yùn)行循環(huán)就是一次 __CFRunLoopRun
的運(yùn)行邦马。
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode)
__CFRunLoopRun
參數(shù)有 5 個(gè),分別表示:
-
rl
: CFRunLoopRef 對(duì)象 -
rlm
: mode 的名稱 -
seconds
: 超時(shí)時(shí)間 -
stopAfterHandle
: 處理完 source 后是否直接返回 -
previousMode
: 前一次運(yùn)行循環(huán)的 mode
下面提供
__CFRunLoopRun
的完整代碼和精簡(jiǎn)代碼随闽,讀者可根據(jù)自身需要選擇閱讀蛾扇。
__CFRunLoopRun 完整代碼
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode)
{
// 獲取開(kāi)始時(shí)間
uint64_t startTSR = mach_absolute_time();
if (__CFRunLoopIsStopped(rl))
{
// Runloop 處于停止?fàn)顟B(tài),修改runloop底層數(shù)據(jù)結(jié)構(gòu) 停止?fàn)顟B(tài) flag
__CFRunLoopUnsetStopped(rl);
// 返回 kCFRunLoopRunStopped 狀態(tài)
return kCFRunLoopRunStopped;
}
else if (rlm->_stopped)
{
// Mode 處于停止?fàn)顟B(tài)更哄,修改 mode 的成員變量 _stopped 為 false
rlm->_stopped = false;
// 返回 kCFRunLoopRunStopped 狀態(tài)
return kCFRunLoopRunStopped;
}
// 判斷是否有主隊(duì)列的 Mach Port
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();
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// 從 mode 的 成員變量 _queue 中取出對(duì)應(yīng)的 Mach Port
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
// 聲明一個(gè)空的 GCD 定時(shí)器
dispatch_source_t timeout_timer = NULL;
// 初始化一個(gè) 「超時(shí)上下文」 結(jié)構(gòu)體指針對(duì)象
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
// 如果 runloop 超時(shí)時(shí)間小于等于0
if (seconds <= 0.0)
{ // instant timeout
// 將 seconds 置為 0s
seconds = 0.0;
// 將 「超時(shí)上下文」的 termTSR 屬性設(shè)置為 0赦役,0ULL 后面的 ULL 表示 Unsigned Long Long 即無(wú)符號(hào) long long 整型
timeout_context->termTSR = 0ULL;
}
else if (seconds <= TIMER_INTERVAL_LIMIT)
{
// 如果 runloop 超時(shí)時(shí)間小于等于 TIMER_INTERVAL_LIMIT 常量
// 如果主線程存在术羔,則獲取主線程的主隊(duì)列
// 如果主線程不存在聂示,則獲取全局隊(duì)列
dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
// 將隊(duì)列傳入并初始化一個(gè) GCD 對(duì)象秀鞭,對(duì)象類型為定時(shí)器
timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 對(duì) GCD 對(duì)象進(jìn)行 retain
dispatch_retain(timeout_timer);
// 將 GCD 對(duì)象賦值于 「超時(shí)上下文」 結(jié)構(gòu)體的 ds 屬性
timeout_context->ds = timeout_timer;
// 對(duì) runloop 對(duì)象進(jìn)行 retain皱坛,然后賦值于「超時(shí)上下文」 結(jié)構(gòu)體的 rl 屬性
timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
// 將本次運(yùn)行循環(huán)的開(kāi)始時(shí)間加上要運(yùn)行的時(shí)間得到runloop的生命周期時(shí)間
// 然后賦值于「超時(shí)上下文」 結(jié)構(gòu)體的 termTSR 屬性
timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
// 設(shè)置 GCD 對(duì)象的上下文為 自定義的 「超時(shí)上下文」 結(jié)構(gòu)體
dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
// 設(shè)置 GCD 對(duì)象的回調(diào) 可以理解為要執(zhí)行的任務(wù)
/**
static void __CFRunLoopTimeout(void *arg)
{
struct __timeout_context *context = (struct __timeout_context *)arg;
context->termTSR = 0ULL;
CFRUNLOOP_WAKEUP_FOR_TIMEOUT();
CFRunLoopWakeUp(context->rl);
// The interval is DISPATCH_TIME_FOREVER, so this won't fire again
}
__CFRunLoopTimeout 函數(shù)內(nèi)部
1.將 「超時(shí)上下文」 結(jié)構(gòu)體的 termTSR 屬性賦值為0
2.CFRUNLOOP_WAKEUP_FOR_TIMEOUT() 宏內(nèi)部是一個(gè) do-while(0) 的無(wú)用操作,可以忽略
3.然后通過(guò) CFRunLoopWakeUp 函數(shù)來(lái)喚醒 runloop
*/
dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
// 設(shè)置 GCD 對(duì)象的取消回調(diào) 可以理解為取消任務(wù)時(shí)的回調(diào)
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
// 將開(kāi)始時(shí)間加上給定的 runloop 過(guò)期時(shí)間,因?yàn)榇藭r(shí)結(jié)果為 秒吭服,需要轉(zhuǎn)換為 納秒蝌戒,所以再乘以 10 ^ 9
uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
// 設(shè)置 GCD 定時(shí)器
// 第二個(gè)參數(shù)表示定時(shí)器開(kāi)始時(shí)間 也就是說(shuō),如果是 CFRunLoopRun 進(jìn)來(lái)的話
// 因?yàn)閭魅氲闹凳?1.0e10粹淋,所以這個(gè)定時(shí)器永遠(yuǎn)不會(huì)觸發(fā),也就意味著 runloop 永遠(yuǎn)不會(huì)超時(shí)
// 第三個(gè)參數(shù)表示 定時(shí)器 納秒級(jí)的 間隔借杰,這里傳入的是 DISPATCH_TIME_FOREVER,說(shuō)明定時(shí)器只會(huì)觸發(fā)一次绞惦,不會(huì)觸發(fā)多次
// 第四個(gè)參數(shù)表示 定時(shí)器 納秒級(jí) 的容錯(cuò)時(shí)間
dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
// 開(kāi)啟 GCD 定時(shí)器
dispatch_resume(timeout_timer);
}
else
{ // infinite timeout
// 設(shè)置超時(shí)時(shí)間為 9999999999
// 然后設(shè)置 自定義的 「超時(shí)上下文」 結(jié)構(gòu)體的 termTSR 屬性值為 UNIT64_MAX
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
// 初始化一個(gè)布爾值 上一次是否通過(guò) dispatch port
Boolean didDispatchPortLastTime = true;
int32_t retVal = 0;
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
// 初始化一個(gè) 無(wú)符號(hào) int8 整型類型的 消息緩沖區(qū)菠发,緩沖區(qū)大小為 3KB
uint8_t msg_buffer[3 * 1024];
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
// 初始化一個(gè)空的 mach_msg_header_t 類型的 msg 結(jié)構(gòu)體指針變量
mach_msg_header_t *msg = NULL;
// 初始化一個(gè)值為 MACH_PORT_NULL 的 port
mach_port_t livePort = MACH_PORT_NULL;
// 將 mode 的 _portSet 取出
__CFPortSet waitSet = rlm->_portSet;
// 設(shè)置 runloop 底層數(shù)據(jù)結(jié)構(gòu)的 ignoreWakeUps 值為 0
__CFRunLoopUnsetIgnoreWakeUps(rl);
// 判斷如果 mode 的 observer 的 mask 與上 kCFRunLoopBeforeTimers 枚舉值是否為1
// 如果成功雁乡,通知 Observers 即將處理 Timers
if (rlm->_observerMask & kCFRunLoopBeforeTimers)
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 判斷如果 mode 的 observer 的 mask 與上 kCFRunLoopBeforeSources 枚舉值是否為1
// 如果成功踱稍,通知 Observers 即將處理 Sources
if (rlm->_observerMask & kCFRunLoopBeforeSources)
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 處理 Blocks,傳入 runloop 和 mode
__CFRunLoopDoBlocks(rl, rlm);
// 處理 Source0,傳入 runloop 和 mode侵浸,以及 stopAfterHandle
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
// 如果處理 Sources0 成功区端,再次處理 Blocks
if (sourceHandledThisLoop)
{
__CFRunLoopDoBlocks(rl, rlm);
}
// 如果本次 loop 執(zhí)行 source0 成功 或 超時(shí)時(shí)間為0,設(shè)置 poll 為 true
Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
// 如果主隊(duì)列 port 不為空且上一次 loop 沒(méi)有主隊(duì)列 port
if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime)
{
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
// 初始化一個(gè) mach_msg_header_t 結(jié)構(gòu)的 msg
msg = (mach_msg_header_t *)msg_buffer;
// 判斷主隊(duì)列的port上是否有消息沥邻,如果有,進(jìn)入 handle_msg 流程
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL))
{
// 說(shuō)明主隊(duì)列的port上有消息過(guò)來(lái),需要喚醒 runloop
goto handle_msg;
}
#endif
}
// 將上一次 loop 主隊(duì)列 值為空
didDispatchPortLastTime = false;
// 說(shuō)明沒(méi)有從 port 拉取消息延届,并且 mode 的 _observerMask 與上 kCFRunLoopBeforeWaiting 為真,
// 則通知 Observers 即將休眠
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting))
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
/**
CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl)
{
__CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1);
}
*/
// 設(shè)置 runloop sleeping 的flag
__CFRunLoopSetSleeping(rl);
// do not do any user callouts after this point (after notifying of sleeping)
// 在 runloop 已經(jīng)睡眠之后赴涵,不要做任何用戶調(diào)用
// Must push the local-to-this-activation ports in on every loop
// iteration, as this mode could be run re-entrantly and we don't
// want these ports to get serviced.
/**
//必須在每個(gè)循環(huán)中都將 local-to-this-activation 端口推入
//迭代扇苞,因?yàn)榇四J娇梢灾匦逻\(yùn)行鳖敷,我們不
//希望這些端口可以被服務(wù)。
*/
// 將主隊(duì)列 port 加入 waitSet 中
__CFPortSetInsert(dispatchPort, waitSet);
// 解鎖 mode
__CFRunLoopModeUnlock(rlm);
// 解鎖 runloop
__CFRunLoopUnlock(rl);
// 如果 poll 為真崖媚,sleepStart 為 0肴楷,否則為當(dāng)前時(shí)間
CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent();
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// 這個(gè) do - while 循環(huán)主要針對(duì)于 GCD 定時(shí)器
do
{
if (kCFUseCollectableAllocator)
{
// objc_clear_stack(0);
// <rdar://problem/16393959>
// 將 msg_buffer 緩沖區(qū) 置為0
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
// 判斷 waitSet 的 port 是否有消息
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
// 判斷 modeQueuePort 這個(gè) port 不為空泥张,且 livePort 為 modeQueuePort
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.
/**
清空內(nèi)部隊(duì)列媚创。 如果其中一個(gè)標(biāo)注塊設(shè)置了 timerFired 標(biāo)志晌姚,請(qǐng)中斷并為計(jì)時(shí)器提供服務(wù)。
*/
while (_dispatch_runloop_root_queue_perform_4CF(rlm->_queue))
;
// 如果 mode 的 _timerFired 為 真宝磨,則置為 false,并退出 do-while 循環(huán)
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);
#else
if (kCFUseCollectableAllocator)
{
// objc_clear_stack(0);
// <rdar://problem/16393959>
// 將 msg_buffer 緩沖區(qū) 置為0
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
// 判斷 waitSet 的 port 是否有消息
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
#endif
#endif
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 加鎖
__CFRunLoopModeLock(rlm);
// 如果 poll 為真,說(shuō)明主隊(duì)了喚醒了 runloop,反之則獲得 runloop 的睡眠時(shí)間
rl->_sleepTime += (poll ? 0.0 : (CFAbsoluteTimeGetCurrent() - sleepStart));
// Must remove the local-to-this-activation ports in on every loop
// iteration, as this mode could be run re-entrantly and we don't
// want these ports to get serviced. Also, we don't want them left
// in there if this function returns.
/**
CF_INLINE kern_return_t __CFPortSetRemove(__CFPort port, __CFPortSet portSet)
{
if (MACH_PORT_NULL == port)
{
return -1;
}
return mach_port_extract_member(mach_task_self(), port, portSet);
}
*/
// 將 dispatchPort 從 waitSet 中移除,因?yàn)槊看?runloop 迭代中 dispatchPort 都會(huì)被加入 waitSet
__CFPortSetRemove(dispatchPort, waitSet);
/**
CF_INLINE void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl)
{
rl->_perRunData->ignoreWakeUps = 0x57414B45; // 'WAKE'
}
喚醒 runloop
*/
__CFRunLoopSetIgnoreWakeUps(rl);
// user callouts now OK again
// 設(shè)置 runloop 的 sleeping flag 為 0
__CFRunLoopUnsetSleeping(rl);
// 通知 Observers 結(jié)束休眠
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting))
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:;
/**
CF_INLINE void __CFRunLoopSetIgnoreWakeUps(CFRunLoopRef rl)
{
rl->_perRunData->ignoreWakeUps = 0x57414B45; // 'WAKE'
}
表示收到了 port 消息靠胜,需要處理
*/
__CFRunLoopSetIgnoreWakeUps(rl);
// 如果喚醒的端口為空菠赚,啥事也不干
if (MACH_PORT_NULL == livePort)
{
CFRUNLOOP_WAKEUP_FOR_NOTHING();
// handle nothing
}
// 如果喚醒端口是 runloop 的 _wakeUpPort,則執(zhí)行 CFRUNLOOP_WAKEUP_FOR_WAKEUP() 函數(shù)
// CFRUNLOOP_WAKEUP_FOR_WAKEUP() 函數(shù)其實(shí)啥也沒(méi)干
else if (livePort == rl->_wakeUpPort)
{
CFRUNLOOP_WAKEUP_FOR_WAKEUP();
// do nothing on Mac OS
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// 如果喚醒端口是 modeQueuePort,說(shuō)明是 定時(shí)器喚醒了 runloop
else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort)
{
// 調(diào)用 CFRUNLOOP_WAKEUP_FOR_TIMER 函數(shù)塌忽,
CFRUNLOOP_WAKEUP_FOR_TIMER();
// 執(zhí)行 timer
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time()))
{
// Re-arm the next timer, because we apparently fired early
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
#if USE_MK_TIMER_TOO
// 如果喚醒端口是 mode 的 _timerPort
else if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort)
{
CFRUNLOOP_WAKEUP_FOR_TIMER();
// On Windows, we have observed an issue where the timer port is set before the time which we requested it to be set. For example, we set the fire time to be TSR 167646765860, but it is actually observed firing at TSR 167646764145, which is 1715 ticks early. The result is that, when __CFRunLoopDoTimers checks to see if any of the run loop timers should be firing, it appears to be 'too early' for the next timer, and no timers are handled.
// In this case, the timer port has been automatically reset (since it was returned from MsgWaitForMultipleObjectsEx), and if we do not re-arm it, then no timers will ever be serviced again unless something adjusts the timer list (e.g. adding or removing timers). The fix for the issue is to reset the timer here if CFRunLoopDoTimers did not handle a timer itself. 9308754
// 執(zhí)行 timer
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time()))
{
// Re-arm the next timer
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
// 如果喚醒端口是 dispatchPort嬉探,說(shuō)明是主隊(duì)列喚醒了 Runloop
else if (livePort == dispatchPort)
{
// 執(zhí)行 CFRUNLOOP_WAKEUP_FOR_DISPATCH() 函數(shù)
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
// 解鎖 mode
__CFRunLoopModeUnlock(rlm);
// 解鎖 runloop
__CFRunLoopUnlock(rl);
// 設(shè)置 TSD眷蜓,以 __CFTSDKeyIsInGCDMainQ 為 key, 6 為值
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
// 執(zhí)行主隊(duì)列任務(wù)
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
// 設(shè)置 TSD汽纤,以 __CFTSDKeyIsInGCDMainQ 為 key, 0 為值
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 加鎖
__CFRunLoopModeLock(rlm);
// 標(biāo)記本次 loop 處理了主隊(duì)列
sourceHandledThisLoop = true;
didDispatchPortLastTime = true;
}
else
{
// 來(lái)到這,說(shuō)明是被 source1 喚醒
CFRUNLOOP_WAKEUP_FOR_SOURCE();
// If we received a voucher from this mach_msg, then put a copy of the new voucher into TSD. CFMachPortBoost will look in the TSD for the voucher. By using the value in the TSD we tie the CFMachPortBoost to this received mach_msg explicitly without a chance for anything in between the two pieces of code to set the voucher again.
voucher_t previousVoucher = _CFSetTSD(__CFTSDKeyMachMessageHasVoucher, (void *)voucherCopy, os_release);
// Despite the name, this works for windows handles as well
// 從端口中取出 source1
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;
// 執(zhí)行 source1 z任務(wù)
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 DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
if (msg && msg != (mach_msg_header_t *)msg_buffer)
free(msg);
#endif
// 處理 Blocks栋烤,傳入 runloop 和 mode
__CFRunLoopDoBlocks(rl, rlm);
/**
CFRunLoopRunInMode() 函數(shù)返回的原因买窟,有四種
// Reasons for CFRunLoopRunInMode() to Return
enum {
kCFRunLoopRunFinished = 1, // 完成了 loop
kCFRunLoopRunStopped = 2, // loop 被終止
kCFRunLoopRunTimedOut = 3, // loop 超時(shí)
kCFRunLoopRunHandledSource = 4 // loop 執(zhí)行了 主隊(duì)列任務(wù)
};
*/
// 如果執(zhí)行了主隊(duì)列任務(wù)并且 stopAfterHandle 為真瞳购,則退出 do-while 循環(huán)
if (sourceHandledThisLoop && stopAfterHandle)
{
retVal = kCFRunLoopRunHandledSource;
}
// 如果超時(shí)亏推,則退出 do-while 循環(huán)
else if (timeout_context->termTSR < mach_absolute_time())
{
retVal = kCFRunLoopRunTimedOut;
}
// 如果 runloop 已經(jīng)停止学赛,則退出 do-while 循環(huán)
else if (__CFRunLoopIsStopped(rl))
{
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
}
// 如果 mode 的 _stopped 屬性為真,則退出 do-while 循環(huán)
else if (rlm->_stopped)
{
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
}
// 如果 mode 此時(shí)為空吞杭,則退出 do-while 循環(huán)
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);
// 如果開(kāi)啟了 GCD 定時(shí)器
if (timeout_timer)
{
// 停掉定時(shí)器并釋放資源
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
}
else
{
// 釋放 超時(shí)上下文 結(jié)構(gòu)體指針
free(timeout_context);
}
return retVal;
}
__CFRunLoopRun 精簡(jiǎn)代碼
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode)
{
int32_t retVal = 0;
do
{
// 通知 Observers 即將處理 Timers
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 通知 Observers 即將處理 Sources
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 處理 Blocks
__CFRunLoopDoBlocks(rl, rlm);
// 處理 Source0
if (__CFRunLoopDoSources0(rl, rlm, stopAfterHandle))
{
// 處理 Blocks
__CFRunLoopDoBlocks(rl, rlm);
}
Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
// 判斷有無(wú) Source1
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL))
{
// 如果有 Source1,就跳轉(zhuǎn)到 handle_msg
goto handle_msg;
}
didDispatchPortLastTime = false;
// 通知 Observers 即將休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent();
do
{
if (kCFUseCollectableAllocator)
{
// objc_clear_stack(0);
// <rdar://problem/16393959>
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
// 等待別的消息來(lái)喚醒當(dāng)前線程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
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);
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
// 通知 Observers 結(jié)束休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
handle_msg:
if (被 timer 喚醒)
{
// 處理 timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
}
else if (被 GCD 喚醒)
{
// 處理 GCD 主隊(duì)列
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
}
else
{
// 被 Source1 喚醒
__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
}
// 處理 Blocks
__CFRunLoopDoBlocks(rl, rlm);
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))
{
retVal = kCFRunLoopRunFinished;
}
voucher_mach_msg_revert(voucherState);
os_release(voucherCopy);
} while (0 == retVal);
return retVal;
}
RunLoop 執(zhí)行的任務(wù)
通過(guò) __CFRunLoopRun
芽狗,我們知道了 RunLoop
執(zhí)行的任務(wù)有以下幾個(gè):
__CFRunLoopDoObservers
__CFRunLoopDoBlocks
__CFRunLoopDoSources0
__CFRunLoopDoSource1
__CFRunLoopDoTimers
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
下面绢掰,我們將一個(gè)一個(gè)進(jìn)行分析:
__CFRunLoopDoObservers
/* rl is locked, rlm is locked on entrance and exit */
static void __CFRunLoopDoObservers() __attribute__((noinline));
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity)
{ /* DOES CALLOUT */
CHECK_FOR_FORK();
// 判斷傳入的 mode 對(duì)應(yīng)的 observer 數(shù)量是否為 0
CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
if (cnt < 1)
return;
/* Fire the observers */
// #define STACK_BUFFER_DECL(T, N, C) T N[C]
// 這里可以分為兩種情況
// 如果 mode 中的 observer 數(shù)量小于等于 1024 個(gè),那么相當(dāng)于 CFRunLoopObserverRef buffer[cnt]
// 如果 mode 中的 observer 數(shù)量大于 1024 個(gè)童擎,那么相當(dāng)于 CFRunLoopObserverRef buffer[1]
// 所以這里通過(guò) observer 數(shù)量來(lái)分配不同大小的緩存區(qū)
STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
// 判斷如果 observer 數(shù)量小于 1024 個(gè)滴劲,則把上一步得到的 buffer 緩存區(qū)賦值給 collectedObservers
// 如果 observer 數(shù)量大于 1024 個(gè),則調(diào)用 malloc 函數(shù)來(lái)分配空間, 最終空間大小為 = observer數(shù)目 * CFRunLoopObserverRef 類型占用內(nèi)存大小
// 最終獲得了一個(gè) 類型為 CFRunLoopObserverRef 的數(shù)組指針變量 collectedObservers
CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef));
CFIndex obs_cnt = 0;
// 循環(huán)遍歷傳入的 runloop mode 中所有的 observers
for (CFIndex idx = 0; idx < cnt; idx++)
{
// 從 observers 集合中取出一個(gè) observer
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
// 滿足下列三個(gè)條件后進(jìn)入 if 內(nèi)部的邏輯
// 1.判斷 observer 當(dāng)前的狀態(tài)是否與傳入的狀態(tài)匹配顾复,這里是通過(guò) 與 運(yùn)算來(lái)完成哑芹,如果相等,結(jié)果應(yīng)為 1捕透,所以這里判斷是不等于 0
// 2.判斷 observer 是否是有效的
/**
// Bit 3 in the base reserved bits is used for invalid state in run loop objects
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);
}
*/
// 3.判斷 observer 是否已經(jīng) fire 了
/**
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);
}
*/
/**
探索第二步和第三步操作之后聪姿,可以發(fā)現(xiàn) CFRuntimeBase 結(jié)構(gòu)中的
Bit 0 是用來(lái)表示 啟動(dòng)狀態(tài)
Bit 1 是用來(lái)表示 重復(fù)狀態(tài)
Bit 3 是用來(lái)表示 runloop 對(duì)象的可用狀態(tài)
*/
if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo))
{
// 對(duì) observer 進(jìn)行 retain,然后存入 collectedObservers 集合中
// CoreFoundation 框架中 需要手動(dòng)MRC乙嘀,也就是對(duì)接收到的對(duì)象需要調(diào)用 CFRetain末购,與此同時(shí),需要有配對(duì)的 CFRelease 操作防止內(nèi)存泄漏
collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo);
}
}
// 對(duì)傳入的 mode 解鎖
// 底層實(shí)現(xiàn)是一個(gè)互斥鎖
/**
CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm)
{
//CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm);
pthread_mutex_unlock(&(rlm->_lock));
}
*/
__CFRunLoopModeUnlock(rlm);
// 對(duì)傳入的 runloop 解鎖
// 底層實(shí)現(xiàn)是一個(gè)互斥鎖
/**
CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl)
{
// CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl);
pthread_mutex_unlock(&(((CFRunLoopRef)rl)->_lock));
}
*/
__CFRunLoopUnlock(rl);
// 根據(jù)上面 for 循環(huán)內(nèi)部自增的變量 obs_cnt 虎谢,也就是有效的 observer 的個(gè)數(shù)進(jìn)行遍歷
for (CFIndex idx = 0; idx < obs_cnt; idx++)
{
// 取出一個(gè) observer
CFRunLoopObserverRef rlo = collectedObservers[idx];
// 對(duì) observer 進(jìn)行加鎖
// 底層實(shí)現(xiàn)是一把互斥鎖
/**
CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo)
{
pthread_mutex_lock(&(rlo->_lock));
// CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo);
}
*/
__CFRunLoopObserverLock(rlo);
// 再次判斷 observer 是否已失效
if (__CFIsValid(rlo))
{
// 從 observer 中取出 重復(fù)狀態(tài)盟榴,然后取反,賦值給 doInvalidate 布爾變量
// 這個(gè)布爾變量在后面用作判斷婴噩,即如果 observer 的 repeat 為真擎场,那么 doInvalidate 就為假,
// 如果 observer 的 repeat 為假几莽,那么 doInvalidate 就為真迅办,
// 就會(huì)調(diào)用 CFRunLoopObserverInvalidate 來(lái)將 observer 從所屬 runloop 中剔除,然后 observer 被釋放
Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo);
// 設(shè)置 observer 的 runtimebase 里面的 bit 0 值為1 章蚣,即標(biāo)記 observer 已經(jīng)啟動(dòng)
/**
CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo)
{
__CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1);
}
*/
__CFRunLoopObserverSetFiring(rlo);
// 對(duì) observer 解鎖
__CFRunLoopObserverUnlock(rlo);
// 調(diào)用 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ 函數(shù)站欺,傳入 observer 對(duì)應(yīng)的 callout,以及 observer 自己,runloop 當(dāng)前狀態(tài)矾策,以及 observer 上下文信息
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info);
if (doInvalidate)
{
CFRunLoopObserverInvalidate(rlo);
}
// 取消 observer 的 firing 狀態(tài)
__CFRunLoopObserverUnsetFiring(rlo);
}
else
{
// 說(shuō)明 observer 已經(jīng)失效磷账,對(duì) observer 解鎖
__CFRunLoopObserverUnlock(rlo);
}
// 因?yàn)榇藭r(shí) observer 要么已經(jīng)觸發(fā)了回調(diào),要么由于已經(jīng)失效啥也沒(méi)干贾虽,所以需要釋放釋放掉 observer逃糟,然后開(kāi)啟下一次循環(huán)過(guò)程
CFRelease(rlo);
}
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 加鎖
__CFRunLoopModeLock(rlm);
// 判斷集合如果不等于 buffer ,說(shuō)明是使用的 malloc 函數(shù)初始化而來(lái)蓬豁,需要調(diào)用 free 函數(shù)釋放
if (collectedObservers != buffer)
free(collectedObservers);
}
可以看到最終執(zhí)行回調(diào)任務(wù)的是 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
绰咽,我們來(lái)到它的內(nèi)部:
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
if (func)
{
func(observer, activity, info);
}
asm __volatile__(""); // thwart tail-call optimization
}
__CFRunLoopDoBlocks
/**
從 runloop 的 _block_item 鏈表里面匹配 mode,匹配上了的就執(zhí)行 block 任務(wù)
*/
static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm)
{ // Call with rl and rlm locked
/*
因?yàn)?runloop 內(nèi)部有這樣的結(jié)構(gòu)
struct _block_item *_blocks_head; // 鏈表的頭指針
struct _block_item *_blocks_tail; // 鏈表的尾指針
struct _block_item
{
struct _block_item *_next; // 指向下一個(gè) _block_item
CFTypeRef _mode; // CFString or CFSet // mode 可能是字符串庆尘,也可能是集合
void (^_block)(void); // block
};
所以 runloop 底層是以單鏈表的方式存儲(chǔ)著 _block_item 結(jié)構(gòu)體指針對(duì)象
*/
// 如果 block 鏈表頭指針為空剃诅,說(shuō)明當(dāng)前 runloop 沒(méi)有要執(zhí)行的 block,直接返回 false
if (!rl->_blocks_head)
return false;
// 如果 mode 為空或者 mode 的名稱為空驶忌,也直接返回 false
if (!rlm || !rlm->_name)
return false;
// 是否執(zhí)行了 block
Boolean did = false;
// 取出 block 鏈表頭指針
struct _block_item *head = rl->_blocks_head;
// 取出 block 鏈表尾指針
struct _block_item *tail = rl->_blocks_tail;
// 將 runloop 上的 block 鏈表頭指針置空
rl->_blocks_head = NULL;
// 將 runloop 上的 block 鏈表尾指針置空
rl->_blocks_tail = NULL;
// 獲取 runloop 的 commonModes
CFSetRef commonModes = rl->_commonModes;
// 獲取傳入的 mode 的名稱
CFStringRef curMode = rlm->_name;
// 對(duì) mode 解鎖
__CFRunLoopModeUnlock(rlm);
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
// 初始化一個(gè)空的指針
struct _block_item *prev = NULL;
// 初始化一個(gè)指向鏈表頭結(jié)點(diǎn)的指針
struct _block_item *item = head;
// 從取得的 block 鏈表頭指針開(kāi)始遍歷整個(gè) block 鏈表
while (item)
{
// 當(dāng)前拿到的 _block_item 結(jié)構(gòu)體變量
struct _block_item *curr = item;
// 指針往前移動(dòng)一個(gè)位置矛辕,用于下一次循環(huán)
item = item->_next;
// 初始化 doit 布爾值
Boolean doit = false;
// 判斷 _block_item 的 mode 是字符串還是集合,即這個(gè) block_item 是對(duì)應(yīng)一個(gè) mode 還是多個(gè) mode
if (CFStringGetTypeID() == CFGetTypeID(curr->_mode))
{
// 說(shuō)明是一個(gè) mode
// 判斷兩種情況
// 1.傳入的 mode 是否與 block_item 內(nèi)部的 mode 相等
// 2.判斷 block_item 內(nèi)部的 mode 是否為 kCFRunLoopCommonModes付魔,同時(shí)判斷 commonModes 里面是否有傳入的 mode
// 以上情況有一個(gè)滿足聊品,則 doit 為 true,否則 doit 為 false
doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
}
else
{
// 說(shuō)明是多個(gè) mode
// 也是判斷兩種情況
// 1.判斷 _block_item 內(nèi)部的 mode 集合是否包含傳入的 mode
// 2.判斷 _block_item 內(nèi)部的 mode 集合是否包含 kCFRunLoopCommonModes几苍,以及 commonModes 里面是否有傳入的 mode
// 以上情況有一個(gè)滿足翻屈,則 doit 為 true,否則 doit 為 false
doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode));
}
// 說(shuō)白了只要 _block_item 節(jié)點(diǎn)滿足 mode 匹配關(guān)系妻坝,就要執(zhí)行其內(nèi)部的 block 任務(wù)
// 如果 doit 為 false伸眶,說(shuō)明要執(zhí)行 block 任務(wù)的不是當(dāng)前的 _block_item,則將 prev 指針指向當(dāng)前的 _block_item
// 然后因?yàn)樵谇懊嬉呀?jīng)做過(guò) item = item->_next 的操作了,此時(shí)的 item 已經(jīng)指向下一個(gè) _block_item 了
if (!doit)
prev = curr;
// 如果 doit 為 true刽宪,說(shuō)明要執(zhí)行 block 任務(wù)的就是當(dāng)前的 _block_item
if (doit)
{
// 這里其實(shí)可以分為三種情況
// 一.目標(biāo)節(jié)點(diǎn)在頭尾之間的任一節(jié)點(diǎn)
// 二.目標(biāo)節(jié)點(diǎn)在頭節(jié)點(diǎn)
// 三.目標(biāo)節(jié)點(diǎn)在尾節(jié)點(diǎn)
// 因?yàn)橐呀?jīng)執(zhí)行完了 block 任務(wù)厘贼,需要?jiǎng)h除目標(biāo)節(jié)點(diǎn)
// 判斷 prev 指針是否為空,如果不為空圣拄,則將 prev 指針的 _next 指向 item嘴秸,注意,此時(shí) item 為下一次要遍歷的 _block_item
// 這里的作用就是情況一
if (prev)
prev->_next = item;
// 下面分別判斷了兩種邊界值情況庇谆,即要執(zhí)行 block 的任務(wù)為頭節(jié)點(diǎn)或尾節(jié)點(diǎn)
// 判斷如果當(dāng)前正在遍歷的 _block_time 是否等于 head 指針
// 因?yàn)?head 在進(jìn)入 while 循環(huán)之前指向的鏈表的頭結(jié)點(diǎn)岳掐,所以能夠進(jìn)入 if 內(nèi)部邏輯的條件
// 說(shuō)白了也就是剛好頭結(jié)點(diǎn)就是要執(zhí)行 block 任務(wù)的那個(gè)節(jié)點(diǎn),此時(shí)將 head 指針指向下一節(jié)點(diǎn)饭耳,在循環(huán)結(jié)束后有一個(gè)判斷串述,
// 如果 head 不為空,然后里面的有一步操作就是重新讓 rl->_blocks_head 指向 head哥攘,也就是說(shuō) 執(zhí)行了 block 任務(wù)且剛好為頭節(jié)點(diǎn)的節(jié)點(diǎn)被刪除了剖煌。
// 這里的作用就是情況二
if (curr == head)
head = item;
// 判斷如果當(dāng)前正在遍歷的 _block_time 是否等于 tail 指針
// 因?yàn)?tail 指針在 while 循環(huán)之前是指向的鏈表的尾節(jié)點(diǎn)材鹦,所有能夠進(jìn)入 if 內(nèi)部邏輯條件
// 說(shuō)白了就是剛好尾節(jié)點(diǎn)就是要執(zhí)行 block 任務(wù)的那個(gè)節(jié)點(diǎn)逝淹,此時(shí)將 tail 指針指向 prev 指針指向的節(jié)點(diǎn)耕姊,
// 而 prev 指針的指向,我們知道栅葡,顯然就是尾節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)茉兰,說(shuō)白了就是把執(zhí)行了 block 任務(wù)且剛好為尾節(jié)點(diǎn)的節(jié)點(diǎn)被刪除了
// 這里的作用就是情況三
if (curr == tail)
tail = prev;
// 取出如果當(dāng)前正在遍歷的 _block_item 中的 block
void (^block)(void) = curr->_block;
// 釋放如果當(dāng)前正在遍歷的 _block_item 的 mode
CFRelease(curr->_mode);
// 釋放如果當(dāng)前正在遍歷的 _block_item
free(curr);
// 再次判斷 doit
if (doit)
{
// 傳入 block,執(zhí)行任務(wù)
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
// 將 did 置為 true
did = true;
}
// 釋放 block
Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
// 在重新加鎖之前釋放 blcok 可以防止程序員在 dealloc 方法里面重新讓 runloop 運(yùn)行起來(lái)而導(dǎo)致死鎖的情況
}
}
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 加鎖
__CFRunLoopModeLock(rlm);
// 如果 head 指針不為空欣簇,這里 if 的邏輯也是必進(jìn)
if (head)
{
// 因?yàn)樵谇懊嬉呀?jīng)對(duì) rl->_blocks_head 指針進(jìn)行了置空操作规脸,這里等價(jià)于 tail->_next = NULL
tail->_next = rl->_blocks_head;
// 讓 rl->_blocks_head 指向 head 指針指向的節(jié)點(diǎn)
// 如果在上面的 while 循環(huán)中,沒(méi)找到要執(zhí)行的 block熊咽,那么 head 其實(shí)就是原來(lái) rl->_blocks_head 的值
// 如果在上面的 while 循環(huán)中莫鸭,找到了要執(zhí)行的 block,那么 head 是指向的
rl->_blocks_head = head;
// 因?yàn)樵谇懊嬉呀?jīng)對(duì) rl->_blocks_tail 指針進(jìn)行了置空操作,所以這里 if 的邏輯必進(jìn)
// 所以這里就是讓 rl->_blocks_tail 指向 tail 指針指向的節(jié)點(diǎn)
if (!rl->_blocks_tail)
rl->_blocks_tail = tail;
}
return did;
}
可以看到真正執(zhí)行回調(diào)函數(shù)的是 CFRUNLOOP_IS_CALLING_OUT_TO_A__BLOCK 函數(shù)横殴,其內(nèi)部實(shí)現(xiàn)如下
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block)(void))
{
if (block)
{
block();
}
asm __volatile__(""); // thwart tail-call optimization
}
__CFRunLoopDoSources0
/* rl is locked, rlm is locked on entrance and exit */
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) __attribute__((noinline));
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle)
{ /* DOES CALLOUT */
CHECK_FOR_FORK();
// 初始化 sources 被因,并置空
CFTypeRef sources = NULL;
// 初始化返回值 sourceHandled,并置為 false 衫仑,意為是否已經(jīng)處理了 source0
Boolean sourceHandled = false;
/* Fire the version 0 sources */
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0))
{
// 判斷 mode 的 _source0 不為空且大小大于0
// CFSetApplyFunction (Calls a function once for each value in the set.)
// 這個(gè)函數(shù)的作用是對(duì)傳入的 set 里面的每個(gè)元素執(zhí)行 傳入的函數(shù)指針
// 第一個(gè)參數(shù)是 set
// 第二個(gè)參數(shù)是 要對(duì)set每個(gè)元素執(zhí)行一次的函數(shù)指針
// 第三個(gè)參數(shù)作為傳入的函數(shù)指針的第二個(gè)參數(shù)
CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources);
}
// 此時(shí) sources 里面已經(jīng)有全部的 source0 了
if (NULL != sources)
{
// 對(duì) mode 解鎖
__CFRunLoopModeUnlock(rlm);
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
// sources 有可能是一個(gè) runloop source 也有可能是一個(gè)裝的 runloop source 的數(shù)組
// sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
if (CFGetTypeID(sources) == CFRunLoopSourceGetTypeID())
{
// sources 是單個(gè) runloop source
// 類型強(qiáng)轉(zhuǎn)一下
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
// 對(duì) rls 加鎖
__CFRunLoopSourceLock(rls);
if (__CFRunLoopSourceIsSignaled(rls))
{
// 來(lái)到這梨与,說(shuō)明 rls 被標(biāo)記為 signaled
// 取消 signaled 的標(biāo)志
__CFRunLoopSourceUnsetSignaled(rls);
// 判斷 rls 是否有效
if (__CFIsValid(rls))
{
// 對(duì) rls 進(jìn)行解鎖
__CFRunLoopSourceUnlock(rls);
// 執(zhí)行 source0 回調(diào)
/**
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info)
{
if (perform)
{
perform(info);
}
asm __volatile__(""); // thwart tail-call optimization
}
*/
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
// 將處理 source0 的結(jié)果置為 true
sourceHandled = true;
}
else
{
__CFRunLoopSourceUnlock(rls);
}
}
else
{
// 對(duì) rls 解鎖,來(lái)到這文狱,說(shuō)明 rls 沒(méi)有被標(biāo)記為 signaled
__CFRunLoopSourceUnlock(rls);
}
}
else
{
// sources 是數(shù)組
// 取出 source0 的個(gè)數(shù)
CFIndex cnt = CFArrayGetCount((CFArrayRef)sources);
// 對(duì) sources 進(jìn)行排序粥鞋,按照 _order 進(jìn)行升序排序
/**
static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context)
{
CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1;
CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2;
if (o1->_order < o2->_order)
return kCFCompareLessThan;
if (o2->_order < o1->_order)
return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
*/
CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
// 遍歷 sources 數(shù)組
for (CFIndex idx = 0; idx < cnt; idx++)
{
// 取出一個(gè) source0 rls
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx);
// 對(duì) rls 加鎖
__CFRunLoopSourceLock(rls);
if (__CFRunLoopSourceIsSignaled(rls))
{
// 來(lái)到這,說(shuō)明 rls 被標(biāo)記為 signaled
// 取消 signaled 的標(biāo)志
__CFRunLoopSourceUnsetSignaled(rls);
// 判斷 rls 是否有效
if (__CFIsValid(rls))
{
// 對(duì) rls 進(jìn)行解鎖
__CFRunLoopSourceUnlock(rls);
// 執(zhí)行 source0 回調(diào)
/**
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info)
{
if (perform)
{
perform(info);
}
asm __volatile__(""); // thwart tail-call optimization
}
*/
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
// 將處理 source0 的結(jié)果置為 true
sourceHandled = true;
}
else
{
__CFRunLoopSourceUnlock(rls);
}
}
else
{
// 對(duì) rls 解鎖瞄崇,來(lái)到這呻粹,說(shuō)明 rls 沒(méi)有被標(biāo)記為 signaled
__CFRunLoopSourceUnlock(rls);
}
// 如果有一個(gè) source0 處理完成且 傳入的 stopAfterHandle 為 true苏研,則跳出循環(huán)
if (stopAfterHandle && sourceHandled)
{
break;
}
}
}
// 釋放 sources
CFRelease(sources);
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 解鎖
__CFRunLoopModeLock(rlm);
}
// 返回處理 source0 結(jié)果
return sourceHandled;
}
而真正執(zhí)行回調(diào)的是 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
函數(shù),其內(nèi)部實(shí)現(xiàn)如下
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info)
{
if (perform)
{
perform(info);
}
asm __volatile__(""); // thwart tail-call optimization
}
__CFRunLoopDoSource1
// msg, size and reply are unused on Windows
static Boolean __CFRunLoopDoSource1() __attribute__((noinline));
static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
,
mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply
#endif
)
{ /* DOES CALLOUT */
CHECK_FOR_FORK();
// 初始化 是否處理成功 source1 結(jié)果
Boolean sourceHandled = false;
/* Fire a version 1 source */
// 對(duì) source1 進(jìn)行 retian
CFRetain(rls);
// 對(duì) mode 解鎖
__CFRunLoopModeUnlock(rlm);
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
// 對(duì) source1 加鎖
__CFRunLoopSourceLock(rls);
// 如果 source1 有效
if (__CFIsValid(rls))
{
/**
// Bit 1 of the base reserved bits is used for signalled state
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);
}
*/
// 設(shè)置 source1 狀態(tài)為未激活
__CFRunLoopSourceUnsetSignaled(rls);
// 解鎖 source1
__CFRunLoopSourceUnlock(rls);
__CFRunLoopDebugInfoForRunLoopSource(rls);
// 執(zhí)行 source1 回調(diào)
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(rls->_context.version1.perform,
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
msg, size, reply,
#endif
rls->_context.version1.info);
CHECK_FOR_FORK();
sourceHandled = true;
}
else
{
// 寫(xiě)入到日志驱显,source1 失效
if (_LogCFRunLoop)
{
CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls);
}
// 對(duì) source1 解鎖
__CFRunLoopSourceUnlock(rls);
}
// 釋放 source1
CFRelease(rls);
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 加鎖
__CFRunLoopModeLock(rlm);
return sourceHandled;
}
其中真正的回調(diào)函數(shù)為 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
鹰霍,其內(nèi)部實(shí)現(xiàn)為:
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
void *(*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info),
mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply,
#else
void (*perform)(void *),
#endif
void *info)
{
if (perform)
{
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
*reply = perform(msg, size, kCFAllocatorSystemDefault, info);
#else
perform(info);
#endif
}
asm __volatile__(""); // thwart tail-call optimization
}
__CFRunLoopDoTimers
// rl and rlm are locked on entry and exit
static Boolean __CFRunLoopDoTimers(CFRunLoopRef rl, CFRunLoopModeRef rlm, uint64_t limitTSR)
{ /* DOES CALLOUT */
// 初始化 timer 是否被處理成功 結(jié)果
Boolean timerHandled = false;
// 初始化一個(gè)空的 timers 集合
CFMutableArrayRef timers = NULL;
// 遍歷 mode 的 _itemrs 定時(shí)器數(shù)組
for (CFIndex idx = 0, cnt = rlm->_timers ? CFArrayGetCount(rlm->_timers) : 0; idx < cnt; idx++)
{
// 取出 timer
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx);
// 如果 timer 有效且尚未被觸發(fā)
if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt))
{
// 并且 timer 的觸發(fā)時(shí)間小于等于 限定的時(shí)間
if (rlt->_fireTSR <= limitTSR)
{
// 初始化 timers 集合
if (!timers)
timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
// 把 timer 加入 timers 集合
CFArrayAppendValue(timers, rlt);
}
}
}
// 遍歷 timers 集合送巡,里面裝的都是要干活的 timer
for (CFIndex idx = 0, cnt = timers ? CFArrayGetCount(timers) : 0; idx < cnt; idx++)
{
// 取出 timer
CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timers, idx);
// 執(zhí)行 timer 回調(diào)
Boolean did = __CFRunLoopDoTimer(rl, rlm, rlt);
timerHandled = timerHandled || did;
}
// 釋放 timers 集合
if (timers)
CFRelease(timers);
return timerHandled;
}
static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt)
{ /* DOES CALLOUT */
// 初始化 timer 被處理成功結(jié)果
Boolean timerHandled = false;
uint64_t oldFireTSR = 0;
/* Fire a timer */
// 對(duì) timer retain
CFRetain(rlt);
// 對(duì) timer 加鎖
__CFRunLoopTimerLock(rlt);
// 如果 timer 有效,并且 timer 觸發(fā)時(shí)間點(diǎn)未到骗爆,以及 timer 沒(méi)有被觸發(fā)次氨,以及 timer 的 runloop 就是傳入的 runloop ,進(jìn)入 if 邏輯
if (__CFIsValid(rlt) && rlt->_fireTSR <= mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl)
{
// 初始化空的 context_info
void *context_info = NULL;
// 初始化空的 context_release 函數(shù)指針
void (*context_release)(const void *) = NULL;
// 如果 timer 的 context 屬性的 retain 函數(shù)指針不為空摘投,進(jìn)入 if 邏輯
if (rlt->_context.retain)
{
// 將 info retain 后賦值給 context_info
context_info = (void *)rlt->_context.retain(rlt->_context.info);
// 取出 timer 的 release 函數(shù)指針賦值給 context_release
context_release = rlt->_context.release;
}
else
{
// 取出 timer 的 info
context_info = rlt->_context.info;
}
// timer 的時(shí)間間隔是否為 0
Boolean doInvalidate = (0.0 == rlt->_interval);
// 設(shè)置 timer 的 是否觸發(fā)的 bits 為1
__CFRunLoopTimerSetFiring(rlt);
// Just in case the next timer has exactly the same deadlines as this one, we reset these values so that the arm next timer code can correctly find the next timer in the list and arm the underlying timer.
// 以防萬(wàn)一下一個(gè)計(jì)時(shí)器與該計(jì)時(shí)器的截止日期完全相同煮寡,我們重置這些值虹蓄,以便啟用下一個(gè)計(jì)時(shí)器代碼可以正確地找到列表中的下一個(gè)計(jì)時(shí)器并啟用基礎(chǔ)計(jì)時(shí)器。
rlm->_timerSoftDeadline = UINT64_MAX;
rlm->_timerHardDeadline = UINT64_MAX;
// 解鎖 timer
__CFRunLoopTimerUnlock(rlt);
// 對(duì) timer 觸發(fā)加鎖
__CFRunLoopTimerFireTSRLock();
// 取出 _fireTSR
oldFireTSR = rlt->_fireTSR;
// 對(duì) timer 觸發(fā)解鎖
__CFRunLoopTimerFireTSRUnlock();
// 裝配下一個(gè) timer
__CFArmNextTimerInMode(rlm, rl);
// 對(duì) mode 解鎖
__CFRunLoopModeUnlock(rlm);
// 對(duì) runloop 解鎖
__CFRunLoopUnlock(rl);
// 執(zhí)行 timer 真正的回調(diào)
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt->_callout, rlt, context_info);
CHECK_FOR_FORK();
// 如果 timer 只跑一次
if (doInvalidate)
{
// 讓 timer 失效
CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
}
// 如果 context_release 函數(shù)指針不為空幸撕,則釋放掉 context_info
if (context_release)
{
context_release(context_info);
}
// 對(duì) runloop 加鎖
__CFRunLoopLock(rl);
// 對(duì) mode 解鎖
__CFRunLoopModeLock(rlm);
// 對(duì) timer 加鎖
__CFRunLoopTimerLock(rlt);
// 設(shè)置 處理 timer 結(jié)果為 true
timerHandled = true;
// 設(shè)置 timer 的 是否觸發(fā)的 bits 為0
__CFRunLoopTimerUnsetFiring(rlt);
}
// 如果 timer 有效薇组,并且 timer 被處理成功
if (__CFIsValid(rlt) && timerHandled)
{
/* This is just a little bit tricky: we want to support calling
* CFRunLoopTimerSetNextFireDate() from within the callout and
* honor that new time here if it is a later date, otherwise
* it is completely ignored. */
// 如果 舊的觸發(fā)時(shí)間 小于 當(dāng)前的觸發(fā)時(shí)間
if (oldFireTSR < rlt->_fireTSR)
{
/* Next fire TSR was set, and set to a date after the previous
* fire date, so we honor it. */
__CFRunLoopTimerUnlock(rlt);
// The timer was adjusted and repositioned, during the
// callout, but if it was still the min timer, it was
// skipped because it was firing. Need to redo the
// min timer calculation in case rlt should now be that
// timer instead of whatever was chosen.
__CFArmNextTimerInMode(rlm, rl);
}
else
{
uint64_t nextFireTSR = 0LL;
uint64_t intervalTSR = 0LL;
if (rlt->_interval <= 0.0)
{
}
else if (TIMER_INTERVAL_LIMIT < rlt->_interval)
{
intervalTSR = __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
}
else
{
intervalTSR = __CFTimeIntervalToTSR(rlt->_interval);
}
if (LLONG_MAX - intervalTSR <= oldFireTSR)
{
nextFireTSR = LLONG_MAX;
}
else
{
if (intervalTSR == 0)
{
// 15304159: Make sure we don't accidentally loop forever here
CRSetCrashLogMessage("A CFRunLoopTimer with an interval of 0 is set to repeat");
HALT;
}
uint64_t currentTSR = mach_absolute_time();
nextFireTSR = oldFireTSR;
while (nextFireTSR <= currentTSR)
{
nextFireTSR += intervalTSR;
}
}
CFRunLoopRef rlt_rl = rlt->_runLoop;
if (rlt_rl)
{
CFRetain(rlt_rl);
CFIndex cnt = CFSetGetCount(rlt->_rlModes);
STACK_BUFFER_DECL(CFTypeRef, modes, cnt);
CFSetGetValues(rlt->_rlModes, (const void **)modes);
// To avoid A->B, B->A lock ordering issues when coming up
// towards the run loop from a source, the timer has to be
// unlocked, which means we have to protect from object
// invalidation, although that's somewhat expensive.
for (CFIndex idx = 0; idx < cnt; idx++)
{
CFRetain(modes[idx]);
}
__CFRunLoopTimerUnlock(rlt);
for (CFIndex idx = 0; idx < cnt; idx++)
{
CFStringRef name = (CFStringRef)modes[idx];
modes[idx] = (CFTypeRef)__CFRunLoopFindMode(rlt_rl, name, false);
CFRelease(name);
}
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
for (CFIndex idx = 0; idx < cnt; idx++)
{
CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx];
if (rlm)
{
__CFRepositionTimerInMode(rlm, rlt, true);
}
}
__CFRunLoopTimerFireTSRUnlock();
for (CFIndex idx = 0; idx < cnt; idx++)
{
__CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]);
}
CFRelease(rlt_rl);
}
else
{
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
__CFRunLoopTimerFireTSRUnlock();
}
}
}
else
{
// 解鎖 timer
__CFRunLoopTimerUnlock(rlt);
}
// 釋放掉 timer
CFRelease(rlt);
return timerHandled;
}
其中真正執(zhí)行回調(diào)的是 CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION 函數(shù),其內(nèi)部實(shí)現(xiàn)如下:
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func, CFRunLoopTimerRef timer, void *info)
{
if (func)
{
func(timer, info);
}
asm __volatile__(""); // thwart tail-call optimization
}
CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__() __attribute__((noinline));
static void __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(void *msg)
{
_dispatch_main_queue_callback_4CF(msg);
asm __volatile__(""); // thwart tail-call optimization
}