注:以Core Foundation的實(shí)現(xiàn)作為參考(版本為CF-855.17)。
1. 相關(guān)數(shù)據(jù)結(jié)構(gòu)
1.1 run loop的基本結(jié)構(gòu)
CFRunLoopRef,是__CFRunLoop的結(jié)構(gòu)體指針:
typedef struct __CFRunLoop * CFRunLoopRef;
struct __CFRunLoop {
CFRuntimeBase _base; // CF對(duì)象類(lèi)型,相當(dāng)于OC對(duì)象的isa
pthread_mutex_t _lock; // 訪問(wèn)mode列表時(shí)保證同步
__CFPort _wakeUpPort; // 線程被喚醒時(shí)使用
Boolean _unused;
volatile _per_run_data *_perRunData; // 每次運(yùn)行的相關(guān)狀態(tài)數(shù)據(jù)
pthread_t _pthread; // 綁定的線程
uint32_t _winthread;
// 標(biāo)記為“common”的mode的名稱(chēng)組成的集合
CFMutableSetRef _commonModes;
// “common”的mode對(duì)應(yīng)的統(tǒng)一item的集合
CFMutableSetRef _commonModeItems;
// runloop當(dāng)前所處的mode
CFRunLoopModeRef _currentMode;
// 所有的mode的集合
CFMutableSetRef _modes;
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFTypeRef _counterpart;
};
作為RunLoop的基本數(shù)據(jù)結(jié)構(gòu),CFRunLoopRef內(nèi)部主要包含了:
- _commonModes:標(biāo)記為“common”的mode的集合
- _commonModeItems:所有“common”mode中共享的item,即修改此內(nèi)部的item,就會(huì)對(duì)所有的“common”的mode內(nèi)部的item進(jìn)行更新。
- _currentMode:當(dāng)前所在的mode模式,切換時(shí)要退出重新指定
- _modes:所有支持的mode。
常用API:
// 獲取當(dāng)前線程的run loop(延遲加載,不訪問(wèn)不創(chuàng)建)
CF_EXPORT CFRunLoopRef CFRunLoopGetCurrent(void);
// 獲取主線程的run loop(APP啟動(dòng)后自動(dòng)創(chuàng)建并運(yùn)行)
CF_EXPORT CFRunLoopRef CFRunLoopGetMain(void);
既然引入了mode這一概念,我們就看看mode到底是個(gè)啥。
1.2 RunLoop的Mode
RunLoop的mode為內(nèi)部數(shù)據(jù),沒(méi)有對(duì)外公開(kāi)。類(lèi)型為CFRunLoopModeRef,即__CFRunLoopMode的結(jié)構(gòu)體指針??匆幌潞?jiǎn)化過(guò)的代碼結(jié)構(gòu):
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; // 在對(duì)mode加鎖之前必須持有了run loop的鎖
CFStringRef _name; // mode名稱(chēng),區(qū)分mode使用
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0;
CFMutableSetRef _sources1;
CFMutableArrayRef _observers;
CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet;
CFIndex _observerMask;
mach_port_t _timerPort;
Boolean _mkTimerArmed;
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
其中,CFRunLoopModeRef中主要包含了如下幾個(gè)內(nèi)容:
- _name:用于識(shí)別區(qū)分不同的mode實(shí)例。切換mode時(shí)可以使用。
- _sources0:非基于端口的源的集合(我們?cè)诰€程中自己添加的一般都是source0)
- _sources1:基于端口的源的集合(通過(guò)Mach Port進(jìn)行線程間通信使用)
- _observers:觀察者的數(shù)組,用于runloop在不同狀態(tài)時(shí)發(fā)送通知的接收對(duì)象。
- _timers:定時(shí)器數(shù)組,包含的就是NSTimer對(duì)象。
常用API:
// 啟動(dòng)run loop
CF_EXPORT void CFRunLoopRun(void);
// 以指定mode的方式啟動(dòng)run loop
CF_EXPORT SInt32 CFRunLoopRunInMode(CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled);
// 將指定mode加入到run loop的commonMode數(shù)組中(加入的是modeName)
CF_EXPORT void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef mode);
下面我們分著來(lái)看各部分的數(shù)據(jù)結(jié)構(gòu)。
1.3 RunLoop源
CFRunLoopSourceRef,即__CFRunLoopSource結(jié)構(gòu)體的指針。其基本結(jié)構(gòu)如下:
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order; // 優(yōu)先級(jí),不可變
CFMutableBagRef _runLoops; // 綁定的runloop對(duì)象
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
其中,聯(lián)合體中的成員version0和version1即為上面mode中的source0和source1。大概看一下二者的結(jié)構(gòu)體:
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, CFStringRef mode);
void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef 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_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
mach_port_t (*getPort)(void *info);
void * (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info);
#else
void * (*getPort)(void *info);
void (*perform)(void *info);
#endif
} CFRunLoopSourceContext1;
可以看到,二者內(nèi)容基本相同,都是包含了內(nèi)存管理、相等性、hash等信息。不同的是source1的結(jié)構(gòu)體(CFRunLoopSourceContext1)包含了mach_port相關(guān)函數(shù)。
因此,可以將source根據(jù)類(lèi)型(version成員的0和1)分為source0和source1。
常用API:
// 創(chuàng)建source(傳入不同類(lèi)型的context即可得到source0或source1)
CF_EXPORT CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context);
// 向run loop的指定mode中添加source
CF_EXPORT void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode);
// 從run loop的指定mode中移除source
CF_EXPORT void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode);
1.4 Run Loop的定時(shí)器
定時(shí)器為CFRunLoopTimerRef類(lèi)型,也就是__CFRunLoopTimer的結(jié)構(gòu)體指針。
typedef struct __CFRunLoopTimer * CFRunLoopTimerRef;
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop; // 綁定的run loop
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate; // 下次觸發(fā)時(shí)間
CFTimeInterval _interval; // 時(shí)間間隔
CFTimeInterval _tolerance; // 寬容度
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; // 回調(diào)
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
其中,主要包含了:
- _runLoop:綁定到的run loop
- _interval:執(zhí)行事件間隔(重復(fù)執(zhí)行的定時(shí)器)
- _tolerance:寬容度,也就是指定執(zhí)行時(shí)間的最大延遲時(shí)間
- _callout:執(zhí)行的回調(diào)函數(shù)指針
- _context:定時(shí)器上下文對(duì)象,包含內(nèi)存管理等相關(guān)函數(shù)
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);
常用API:
// 以callback回調(diào)函數(shù)指針的形式創(chuàng)建timer
CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context);
// 以block的形式創(chuàng)建timer
CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, void (^block) (CFRunLoopTimerRef timer)) CF_AVAILABLE(10_7, 5_0);
// 向run loop的指定mode中添加timer
CF_EXPORT void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);
// 從run loop的指定mode中移除timer
CF_EXPORT void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode);
1.5 Run Loop的觀察者
觀察者為CFRunLoopObserverRef類(lèi)型,即__CFRunLoopObserver的結(jié)構(gòu)體指針。
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
其中,主要包含:
- _runLoop:對(duì)應(yīng)的run loop
- _activities:用于監(jiān)聽(tīng)的run loop的指定運(yùn)行狀態(tài)。
- _order:優(yōu)先級(jí)
- _callout:收到監(jiān)聽(tīng)通知的回調(diào)函數(shù)指針。
- _context:上下文對(duì)象
activities,即CFOptionFlags,用于識(shí)別run loop在不同執(zhí)行時(shí)刻的運(yùn)行狀態(tài):
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
/** 進(jìn)入loop */
kCFRunLoopEntry = (1UL << 0),
/** 準(zhǔn)備執(zhí)行timer */
kCFRunLoopBeforeTimers = (1UL << 1),
/** 準(zhǔn)備執(zhí)行source */
kCFRunLoopBeforeSources = (1UL << 2),
/** 線程準(zhǔn)備進(jìn)入休眠 */
kCFRunLoopBeforeWaiting = (1UL << 5),
/** 線程剛被喚醒,還沒(méi)有進(jìn)行任務(wù)處理 */
kCFRunLoopAfterWaiting = (1UL << 6),
/** 退出loop */
kCFRunLoopExit = (1UL << 7),
/** 所有的狀態(tài) */
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
上下文對(duì)象為CFRunLoopObserverContext結(jié)構(gòu)體,內(nèi)部包含了內(nèi)存管理的相關(guān)函數(shù)指針:
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopObserverContext;
回調(diào)函數(shù)的類(lèi)型為:
typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
常用API:
// 創(chuàng)建新的run loop觀察者,使用callback回調(diào)函數(shù)指針的方式
CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context);
// 創(chuàng)建新的run loop觀察者,使用block的方式
CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, void (^block) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) CF_AVAILABLE(10_7, 5_0);
// 向run loop的指定mode中添加觀察者
CF_EXPORT void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode);
// 從run loop的指定mode中移除觀察者
CF_EXPORT void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode);
2. 重點(diǎn)API基本實(shí)現(xiàn)
2.1 CFRunLoopGetMain & CFRunLoopGetCurrent
系統(tǒng)隱藏了生成過(guò)程,通過(guò)獲取線程對(duì)應(yīng)的runloop對(duì)象,即可完成創(chuàng)建。
// 獲取主線程的runloop
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
// 獲取當(dāng)前線程的runloop
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
可以看到,真正的實(shí)現(xiàn)都在 _CFRunLoopGet0 函數(shù)中:
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFSpinLock_t loopsLock = CFSpinLockInit;
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
// t為0,即為主線程
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
// 獲取鎖
__CFSpinLock(&loopsLock);
// 懶加載,第一次調(diào)用為主線程,創(chuàng)建全局字典,并將新創(chuàng)建的主線程runloop加入其中
if (!__CFRunLoops) {
// 釋放鎖
__CFSpinUnlock(&loopsLock);
// 創(chuàng)建字典容器,用于存儲(chǔ)runloop
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
// 創(chuàng)建主線程的runloop
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
// 插入到字典中(key為線程指針)
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
// __CFRunLoops全局字典指針指向此字典容器
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
CFRelease(mainLoop);
// 再次獲取鎖
__CFSpinLock(&loopsLock);
}
// 從全局字典容器中獲取指定runloop
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
// 釋放鎖
__CFSpinUnlock(&loopsLock);
// 懶加載
if (!loop) {
// 創(chuàng)建新runloop
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFSpinLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
// 在全局字典容器中插入runloop
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
__CFSpinUnlock(&loopsLock);
CFRelease(newLoop);
}
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;
}
通過(guò)實(shí)現(xiàn)可以看到:
- runloop對(duì)象整體懶加載,不調(diào)用不生成。
- runloop對(duì)象保存在全局字典中,key為線程指針。
- 系統(tǒng)第一次調(diào)用時(shí),生成全局字典,且自動(dòng)創(chuàng)建主線程的runloop,插入其中,因此APP可以保持運(yùn)行。
2.2 CFRunLoopRun
首先看一下run loop的啟動(dòng)過(guò)程:
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);
}
在以上兩個(gè)啟動(dòng)run loop的函數(shù)中,真正的實(shí)現(xiàn)都包含在CFRunLoopRunSpecific中,且此函數(shù)會(huì)返回run loop的執(zhí)行狀態(tài)(由CFRunLoopRunInMode()函數(shù)返回)。
enum {
kCFRunLoopRunFinished = 1,
kCFRunLoopRunStopped = 2,
kCFRunLoopRunTimedOut = 3,
kCFRunLoopRunHandledSource = 4
};
現(xiàn)在,我們看一下運(yùn)行循環(huán),到底是如何循環(huán)的。
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
CHECK_FOR_FORK();
// 正在釋放,直接返回
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
// run loop獲取鎖
__CFRunLoopLock(rl);
// 根據(jù)指定modeName,獲取到mode對(duì)象
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
// 若不存在此mode,或內(nèi)部沒(méi)有mode item
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) {
// 返回
Boolean did = false;
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished;
}
// 設(shè)置新的perRunData,返回舊值
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl);
// 之前所處的mode
CFRunLoopModeRef previousMode = rl->_currentMode;
// 記錄為新的運(yùn)行mode
rl->_currentMode = currentMode;
// 設(shè)置為已完成,待返回
int32_t result = kCFRunLoopRunFinished;
// 如果存在監(jiān)聽(tīng)進(jìn)入loop狀態(tài)的觀察者
if (currentMode->_observerMask & kCFRunLoopEntry )
// 通知觀察者,run loop已進(jìn)入(新mode進(jìn)入)
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
// ** 核心:切換運(yùn)行新mode(循環(huán)在這里面實(shí)現(xiàn)) **
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
// 如果存在監(jiān)聽(tīng)退出loop狀態(tài)的觀察者
if (currentMode->_observerMask & kCFRunLoopExit )
// 通知觀察者,run loop已退出
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
// 釋放mode的鎖
__CFRunLoopModeUnlock(currentMode);
// 恢復(fù)為原始的perRunData,恢復(fù)狀態(tài)
__CFRunLoopPopPerRunData(rl, previousPerRun);
// run loop的運(yùn)行mode恢復(fù)為原mode
rl->_currentMode = previousMode;
// 釋放run loop自身的鎖
__CFRunLoopUnlock(rl);
return result;
}
CFRunLoopRunSpecific函數(shù)的整體運(yùn)行,是一個(gè)“創(chuàng)建新現(xiàn)場(chǎng) -- 執(zhí)行l(wèi)oop -- 恢復(fù)舊現(xiàn)場(chǎng)”的過(guò)程。
- 根據(jù)指定的modeName名稱(chēng),獲取run loop內(nèi)部保存的mode對(duì)象。將其設(shè)置為currentMode,然后創(chuàng)建新的perRunData進(jìn)行設(shè)置。且如果存在進(jìn)入循環(huán)的觀察者,發(fā)通知進(jìn)行告知。
其中,_per_run_data指針標(biāo)記為volatile,即告知編譯器要直接從原地址讀取值,而不是從寄存器中讀?。ǚ乐苟嗑€程更改時(shí)不修改寄存器中的值導(dǎo)致的數(shù)據(jù)不一致問(wèn)題)。__CFRunLoopPushPerRunData函數(shù)的內(nèi)部實(shí)現(xiàn)為:
typedef struct _per_run_data {
uint32_t a;
uint32_t b;
uint32_t stopped;
uint32_t ignoreWakeUps;
} _per_run_data;
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;
}
可以看到,runloop的_perRunData成員每次都是創(chuàng)建固定的新值。用來(lái)管理runloop的相關(guān)設(shè)置(stop狀態(tài),是否允許喚醒等)
- 調(diào)用 __CFRunLoopRun 函數(shù),此函數(shù)才是真正的運(yùn)行循環(huán)過(guò)程。后面進(jìn)行單獨(dú)說(shuō)明。
- 運(yùn)行循環(huán)執(zhí)行結(jié)束后,恢復(fù)現(xiàn)場(chǎng)。將上一次的運(yùn)行mode、_perRunData等數(shù)據(jù)進(jìn)行恢復(fù)。且如果存在監(jiān)聽(tīng)退出狀態(tài)的觀察者,發(fā)通知告知。
這里,我們看一下runloop是如何給觀察者發(fā)送通知的。
2.2 __CFRunLoopDoObservers
static void __CFRunLoopDoObservers() __attribute__((noinline));
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
CHECK_FOR_FORK();
// 查看mode中observers的個(gè)數(shù)
CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
// 不存在,直接返回
if (cnt < 1) return;
/* Fire the observers */
STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
// cnt超過(guò)1024后,開(kāi)辟cnt個(gè)內(nèi)存空間,相當(dāng)于數(shù)組
CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef));
CFIndex obs_cnt = 0;
for (CFIndex idx = 0; idx < cnt; idx++) {
// 依次取出observer
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
// 若observer中存在需要的activity
if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
// retain后,插入數(shù)組中
collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo);
}
}
// 釋放mode的鎖
__CFRunLoopModeUnlock(rlm);
// 釋放run loop鎖
__CFRunLoopUnlock(rl);
// **** 由此可以看出,為了提高訪問(wèn)效率,將所有的觀察者添加到額外的數(shù)組中,是為了釋放鎖后,其他對(duì)象的高效訪問(wèn)。 ****
for (CFIndex idx = 0; idx < obs_cnt; idx++) {
// 從數(shù)組中依次取出observer
CFRunLoopObserverRef rlo = collectedObservers[idx];
// 對(duì)observer加鎖
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
// 根據(jù)是否重復(fù)確定是否需要置為無(wú)效
Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo);
// 設(shè)置對(duì)應(yīng)位的值(標(biāo)記為正在調(diào)用)
__CFRunLoopObserverSetFiring(rlo);
// 釋放鎖
__CFRunLoopObserverUnlock(rlo);
// 調(diào)用觀察者對(duì)應(yīng)的回調(diào)方法(_callout)
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info);
// 需要置為無(wú)效,則釋放此observer
if (doInvalidate) {
CFRunLoopObserverInvalidate(rlo);
}
// 設(shè)置對(duì)應(yīng)位的值(標(biāo)記為沒(méi)有調(diào)用)
__CFRunLoopObserverUnsetFiring(rlo);
} else {
// 觀察者對(duì)象錯(cuò)誤,直接釋放鎖
__CFRunLoopObserverUnlock(rlo);
}
// 釋放observer(數(shù)組不再保留observer)
CFRelease(rlo);
}
// 釋放runloop和mode的鎖
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
// 創(chuàng)建了新數(shù)組,則釋放內(nèi)存
if (collectedObservers != buffer) free(collectedObservers);
}
- 將指定run loop mode中的_observers取出,單獨(dú)放到一個(gè)指定數(shù)組中進(jìn)行處理(超出1024個(gè)observer后要單獨(dú)開(kāi)辟內(nèi)存)。由于調(diào)用callback函數(shù)為同步操作,由可能會(huì)長(zhǎng)時(shí)間鎖住runloop和mode。故單獨(dú)處理,防止影響runloop的執(zhí)行效率。
- 將監(jiān)聽(tīng)的activity對(duì)應(yīng)的observer插入到數(shù)組容器中。activity即上面說(shuō)過(guò)的CFOptionFlags,也就是runloop運(yùn)行過(guò)程中的各種監(jiān)控時(shí)間點(diǎn)。
- 插入到數(shù)組容器時(shí)要對(duì)observer進(jìn)行保留操作,使用后要對(duì)observer進(jìn)行釋放操作,內(nèi)存管理要時(shí)刻謹(jǐn)記。
- 在observer數(shù)組中依次取出,通過(guò) CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION 函數(shù)對(duì)observer的_callout進(jìn)行函數(shù)調(diào)用。
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);
}
getpid(); // thwart tail-call optimization
}
主要就是直接進(jìn)行函數(shù)調(diào)用(getpid神馬進(jìn)程相關(guān)的,就不動(dòng)了。。。)。
2.3 __CFRunLoopRun
前面說(shuō)了,__CFRunLoopRun個(gè)才是核心所在,真正的“l(fā)oop”在這里執(zhí)行。
由于代碼過(guò)長(zhǎng),我們分步驟看。
2.3.1 其他(非do-while循環(huán))
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
// 1. 狀態(tài)判斷
if (__CFRunLoopIsStopped(rl)) {
// 如果runloop已經(jīng)stop(_perRunData中的stop的值)
// 恢復(fù)stop為初值,返回已stop狀態(tài)
__CFRunLoopUnsetStopped(rl);
return kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
// 若當(dāng)前mode已經(jīng)stop
// 恢復(fù)stop為初值,返回已stop狀態(tài)
rlm->_stopped = false;
return kCFRunLoopRunStopped;
}
// 2. dispatchPort的獲取
// 派發(fā)端口,如果當(dāng)前runloop是主線程runloop,則為主隊(duì)列port,否則為NULL
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();
}
// 3. 超時(shí)定時(shí)器的設(shè)置
dispatch_source_t timeout_timer = NULL;
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
if (seconds <= 0.0) { // instant timeout
// 不設(shè)置超時(shí)的情況,即運(yùn)行完就散
seconds = 0.0;
timeout_context->termTSR = 0ULL;
} else if (seconds <= TIMER_INTERVAL_LIMIT) {
// 有超時(shí),但是未達(dá)到上限的情況
// 通過(guò)global隊(duì)列,添加一個(gè)超時(shí)的timer,到時(shí)間喚醒線程,釋放runloop
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_OVERCOMMIT);
timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_retain(timeout_timer);
timeout_context->ds = timeout_timer;
timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
dispatch_set_context(timeout_timer, timeout_context);
// source gets ownership of context
dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout);
dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel);
uint64_t ns_at = (uint64_t)((__CFTSRToTimeInterval(startTSR) + seconds) * 1000000000ULL);
dispatch_source_set_timer(timeout_timer, dispatch_time(1, ns_at), DISPATCH_TIME_FOREVER, 1000ULL);
dispatch_resume(timeout_timer);
} else { // infinite timeout
// 超過(guò)上限,即無(wú)限運(yùn)行時(shí)間的情況
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
int32_t retVal = 0;
do {
...
} while (0 == retVal);
// retVal只要不為0,則runloop結(jié)束循環(huán),退出
if (timeout_timer) {
// 存在超時(shí)定時(shí)器,移除
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
} else {
free(timeout_context);
}
return retVal;
}
非核心部分主要做了三件事:
- 對(duì)runloop和currentMode的運(yùn)行狀態(tài)進(jìn)行判斷,防止無(wú)畏的運(yùn)行。
- 根據(jù)情況,查看端口是否為GCD的主隊(duì)列端口(用于后面通過(guò)主線程自身端口調(diào)用mach_msg函數(shù),執(zhí)行主隊(duì)列的異步任務(wù))。
- 根據(jù)設(shè)置的超時(shí)時(shí)間,使用GCD添加一個(gè)定時(shí)器,超時(shí)時(shí)直接釋放runloop。最后結(jié)尾時(shí)檢查移除此定時(shí)器。
2.3.2 do-while運(yùn)行循環(huán)
int32_t retVal = 0;
do {
// 1. 根據(jù)運(yùn)行狀態(tài),進(jìn)行預(yù)處理(發(fā)通知、執(zhí)行block、準(zhǔn)備處理GCD事件、休眠)
// 存在kCFRunLoopBeforeTimers的觀察者,發(fā)通知
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 存在kCFRunLoopBeforeSources的觀察者,發(fā)通知
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 調(diào)用block的時(shí)機(jī)1
__CFRunLoopDoBlocks(rl, rlm);
// 執(zhí)行source0(手動(dòng)source)
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
// 執(zhí)行source0后,調(diào)用block(調(diào)用block的時(shí)機(jī)2)
__CFRunLoopDoBlocks(rl, rlm);
}
// GCD的主隊(duì)列
if (MACH_PORT_NULL != dispatchPort) {
msg = (mach_msg_header_t *)msg_buffer;
// 通過(guò)主隊(duì)列端口直接發(fā)送消息(內(nèi)部的source1消息,mach_msg執(zhí)行),進(jìn)行處理
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0)) {
goto handle_msg;
}
}
// 存在監(jiān)聽(tīng)kCFRunLoopBeforeWaiting的觀察者,發(fā)通知
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
msg = (mach_msg_header_t *)msg_buffer;
// 嘗試通過(guò)mach_msg函數(shù)進(jìn)入休眠狀態(tài),接收到消息后(即被喚醒),返回true
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY);
// 如果存在監(jiān)聽(tīng)kCFRunLoopAfterWaiting的觀察者,發(fā)通知
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
// 2. 處理消息部分(線程已被喚醒 或 直接進(jìn)入處理)
// ** 處理消息:**
handle_msg:;
if (rlm->_timerPort != MACH_PORT_NULL && livePort == rlm->_timerPort) {
// timer喚醒的
// 以當(dāng)前時(shí)間為時(shí)間點(diǎn),執(zhí)行相應(yīng)的timer
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
} else if (livePort == dispatchPort) {
// GCD主隊(duì)列喚醒的(dispatchPort不為NULL,即證明是主隊(duì)列喚醒的)
// 執(zhí)行主隊(duì)列的任務(wù)block
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
} else {
// 其他線程的source1喚醒的
// 根據(jù)livePort,查詢(xún)獲取source1對(duì)象
CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);
if (rls) {
mach_msg_header_t *reply = NULL;
// 執(zhí)行source1
sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
}
}
if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg);
// 執(zhí)行block的時(shí)機(jī)3
__CFRunLoopDoBlocks(rl, rlm);
// 3. 根據(jù)狀態(tài)設(shè)置retVal值,決定運(yùn)行循環(huán)是否繼續(xù)
if (sourceHandledThisLoop && stopAfterHandle) {
// 單次執(zhí)行完source
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
// runloop超時(shí)
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
// runloop已停止
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
// runloop的對(duì)應(yīng)mode已停止
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
// runloop執(zhí)行完成
retVal = kCFRunLoopRunFinished;
}
} while (0 == retVal);
雖然代碼很多(已經(jīng)大幅度簡(jiǎn)化),但實(shí)際上只是分為三部分:
- 根據(jù)運(yùn)行狀態(tài),進(jìn)行預(yù)處理:
- 在不同運(yùn)行狀態(tài),給觀察者發(fā)通知(準(zhǔn)備執(zhí)行timer、準(zhǔn)備執(zhí)行source)
- 執(zhí)行block
- 執(zhí)行配置到mode中的source0,成功后再次檢測(cè)執(zhí)行block。實(shí)現(xiàn)函數(shù)為 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
- 準(zhǔn)備處理GCD事件(通過(guò)mach_msg函數(shù),自身主隊(duì)列的port執(zhí)行,存在則直接去處理任務(wù))
- 沒(méi)有其他事件時(shí),通過(guò)mach_msg函數(shù),讓線程進(jìn)入睡眠,同時(shí)在接收消息后自動(dòng)喚醒
- 處理消息部分(線程已被喚醒 或 直接進(jìn)入處理),根據(jù)端口類(lèi)型,對(duì)執(zhí)行的工作進(jìn)行區(qū)分:
- 執(zhí)行timer:CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION,其入口函數(shù) __CFRunLoopDoTimers 與 __CFRunLoopDoObservers 實(shí)現(xiàn)相似:先將符合要求(剛剛到達(dá)或者稍微過(guò)時(shí)一點(diǎn)的)的timer加入到數(shù)組中,防止長(zhǎng)時(shí)間鎖住runloop,然后依次調(diào)用 __CFRunLoopDoTimer ,也就是calling_out函數(shù),完成回調(diào)。
- 執(zhí)行GCD主隊(duì)列的異步任務(wù):CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
- source1的主動(dòng)喚醒任務(wù):mach_msg,進(jìn)入內(nèi)核態(tài),直接進(jìn)行線程通信
- 再次檢測(cè)執(zhí)行block
- 根據(jù)狀態(tài)設(shè)置retVal值,決定運(yùn)行循環(huán)是否繼續(xù)。如果狀態(tài)都不滿足,仍為0,則繼續(xù)執(zhí)行循環(huán),保證線程不退出。