Runloop 源码阅读笔记
runloop部分代码属于苹果开源部分,本次阅读代码来源 CF-CF-1153.18 2
一. Runloop启动
在iOS 应用中:
1 2 3 4 5 6
| int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
|
在macOS应用中:
1 2 3
| int main(int argc, const char * argv[]) { return NSApplicationMain(argc, argv); }
|
这些函数内部会:
在 UIKit/AppKit 框架中,UIApplicationMain/NSApplicationMain 会调用到 CoreFoundation 的 RunLoop 相关函数,建立整个事件循环系统。
runloop 启动方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void CFRunLoopRun(void) { int32_t result; do { result = CFRunLoopRunSpecific( CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false );
CHECK_FOR_FORK();
} while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| SInt32 CFRunLoopRunSpecific( CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled ) { CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished;
__CFRunLoopLock(rl);
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false);
if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) { Boolean did = false; if (currentMode) __CFRunLoopModeUnlock(currentMode); __CFRunLoopUnlock(rl); return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished; }
volatile _per_run_data *previousPerRun = __CFRunLoopPushPerRunData(rl); CFRunLoopModeRef previousMode = rl->_currentMode; rl->_currentMode = currentMode; int32_t result = kCFRunLoopRunFinished;
if (currentMode->_observerMask & kCFRunLoopEntry) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
if (currentMode->_observerMask & kCFRunLoopExit) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopModeUnlock(currentMode); __CFRunLoopPopPerRunData(rl, previousPerRun); rl->_currentMode = previousMode; __CFRunLoopUnlock(rl);
return result; }
|
这是 RunLoop 的核心实现函数,让我分段解释这个复杂的函数:
1. 初始化和准备阶段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { // 记录开始时间 uint64_t startTSR = mach_absolute_time();
// 检查是否已停止 if (__CFRunLoopIsStopped(rl)) { __CFRunLoopUnsetStopped(rl); return kCFRunLoopRunStopped; }
// 设置 dispatch 端口(主队列相关) mach_port_name_t dispatchPort = MACH_PORT_NULL; Boolean libdispatchQSafe = pthread_main_np() && /*...*/; if (libdispatchQSafe /*...*/) dispatchPort = _dispatch_get_main_queue_port_4CF();
|
2. 超时处理设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| dispatch_source_t timeout_timer = NULL; struct __timeout_context *timeout_context = malloc(sizeof(*timeout_context));
if (seconds <= 0.0) { seconds = 0.0; timeout_context->termTSR = 0ULL; } else if (seconds <= TIMER_INTERVAL_LIMIT) { timeout_timer = dispatch_source_create(); } else { seconds = 9999999999.0; timeout_context->termTSR = UINT64_MAX; }
|
3. 主循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| do { if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
__CFRunLoopDoBlocks(rl, rlm);
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) { __CFRunLoopDoBlocks(rl, rlm); }
|
4. 等待和处理消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
__CFRunLoopUnsetSleeping(rl);
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
|
5. 处理收到的消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| if (MACH_PORT_NULL == livePort) { } else if (livePort == rl->_wakeUpPort) { } else if (livePort == dispatchPort) { __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg); } else { CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(); if (rls) { sourceHandledThisLoop = __CFRunLoopDoSource1(); } }
|
6. 退出检查
1 2 3 4 5 6 7 8 9 10 11
| if (sourceHandledThisLoop && stopAfterHandle) { retVal = kCFRunLoopRunHandledSource; } else if (timeout_context->termTSR < mach_absolute_time()) { retVal = kCFRunLoopRunTimedOut; } else if (__CFRunLoopIsStopped(rl)) { retVal = kCFRunLoopRunStopped; } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) { retVal = kCFRunLoopRunFinished; } } while (0 == retVal);
|
主要功能:
事件源处理
- Source0(手动触发)
- Source1(基于端口)
- Timers
- Blocks
观察者通知
消息循环
状态管理
这是 RunLoop 的核心实现,处理了所有事件源和状态转换,是整个事件驱动系统的基础。
二. 对外暴露api方法
2.1 对外暴露的结构体
定义宏CF_IMPLICIT_BRIDGING_ENABLED
开放隐式桥接,(eg. CFString 类型转换NString 可以直接转换)。
定义 CF_EXTERN_C_BEGIN
使用C风格的函数声明,避免C++编译器对C函数进行名称修饰。
对外暴露结构体指针(Runloop对象、Source结构体、Observer结构体、Timer结构体) 其中Timer 显示桥接到NSTimer(CF_BRIDGED_MUTABLE_TYPE)。
1 2 3 4 5 6 7 8 9 10 11
| #define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin") #define CF_EXTERN_C_BEGIN extern "C" {
typedef struct __CFRunLoop * CFRunLoopRef;
typedef struct __CFRunLoopSource * CFRunLoopSourceRef;
typedef struct __CFRunLoopObserver * CFRunLoopObserverRef;
typedef struct CF_BRIDGED_MUTABLE_TYPE(NSTimer) __CFRunLoopTimer * CFRunLoopTimerRef;
|
2.2 对外暴露管理Runloop对象的方法签名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| CF_EXPORT const CFStringRef kCFRunLoopDefaultMode; CF_EXPORT const CFStringRef kCFRunLoopCommonModes;
CF_EXPORT CFTypeID CFRunLoopGetTypeID(void);
CF_EXPORT CFRunLoopRef CFRunLoopGetCurrent(void); CF_EXPORT CFRunLoopRef CFRunLoopGetMain(void);
CF_EXPORT CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl); CF_EXPORT CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl); CF_EXPORT void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef mode);
CF_EXPORT CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef mode);
CF_EXPORT void CFRunLoopRun(void); CF_EXPORT SInt32 CFRunLoopRunInMode( CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled ); CF_EXPORT Boolean CFRunLoopIsWaiting(CFRunLoopRef rl); CF_EXPORT void CFRunLoopWakeUp(CFRunLoopRef rl); CF_EXPORT void CFRunLoopStop(CFRunLoopRef rl);
#if __BLOCKS__ CF_EXPORT void CFRunLoopPerformBlock( CFRunLoopRef rl, CFTypeRef mode, void (^block)(void) ) CF_AVAILABLE(10_6, 4_0); #endif
CF_EXPORT Boolean CFRunLoopContainsSource( CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode ); CF_EXPORT void CFRunLoopAddSource( CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode ); CF_EXPORT void CFRunLoopRemoveSource( CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode );
CF_EXPORT Boolean CFRunLoopContainsObserver( CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode ); CF_EXPORT void CFRunLoopAddObserver( CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode ); CF_EXPORT void CFRunLoopRemoveObserver( CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode );
CF_EXPORT Boolean CFRunLoopContainsTimer( CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode ); CF_EXPORT void CFRunLoopAddTimer( CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode ); CF_EXPORT void CFRunLoopRemoveTimer( CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode );
|
2.3 Source的管理
CFRunLoopSourceContext(版本0)
用于自定义输入源
处理应用程序定义的自定义事件
适用于一般性的事件处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| typedef struct { CFIndex version; // 版本号,用于区分不同版本的 Context 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); // 计算哈希值
// RunLoop 相关回调 void (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode); // 源被添加到 RunLoop 时调用 void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode); // 源被从 RunLoop 移除时调用 void (*perform)(void *info); // 源被触发时执行的操作 } CFRunLoopSourceContext;
|
CFRunLoopSourceContext1(版本1)
专门用于基于端口的输入源
主要用于处理 Mach 端口相关的事件
系统底层进程间通信使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| typedef struct { CFIndex version; // 版本号 void *info; // 自定义信息指针
// 内存管理回调(与版本0相同) const void *(*retain)(const void *info); void (*release)(const void *info);
// 调试和比较功能(与版本0相同) CFStringRef (*copyDescription)(const void *info); Boolean (*equal)(const void *info1, const void *info2); CFHashCode (*hash)(const void *info);
// 在 Mac/iOS 平台特有的功能 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) mach_port_t (*getPort)(void *info); // 获取 Mach 端口 void *(*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info); // 处理 Mach 消息 #else void *(*getPort)(void *info); void (*perform)(void *info); #endif } CFRunLoopSourceContext1;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
CF_EXPORT CFTypeID CFRunLoopSourceGetTypeID(void);
CF_EXPORT CFRunLoopSourceRef CFRunLoopSourceCreate( CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context );
CF_EXPORT CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef source);
CF_EXPORT void CFRunLoopSourceInvalidate(CFRunLoopSourceRef source);
CF_EXPORT Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef source);
CF_EXPORT void CFRunLoopSourceGetContext( CFRunLoopSourceRef source, CFRunLoopSourceContext *context );
CF_EXPORT void CFRunLoopSourceSignal(CFRunLoopSourceRef source);
|
2.4 Observer的管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| 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 );
CF_EXPORT CFTypeID CFRunLoopObserverGetTypeID(void);
CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate( CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context );
#if __BLOCKS__ CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler( CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, void (^block) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) ) CF_AVAILABLE(10_7, 5_0); #endif
CF_EXPORT CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef observer);
CF_EXPORT Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef observer);
CF_EXPORT CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef observer);
CF_EXPORT void CFRunLoopObserverInvalidate(CFRunLoopObserverRef observer);
CF_EXPORT Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef observer);
CF_EXPORT void CFRunLoopObserverGetContext( CFRunLoopObserverRef observer, CFRunLoopObserverContext *context );
|
2.5 Timer 的管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| 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 );
CF_EXPORT CFTypeID CFRunLoopTimerGetTypeID(void);
CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreate( CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context );
#if __BLOCKS__ CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler( CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, void (^block) (CFRunLoopTimerRef timer) ) CF_AVAILABLE(10_7, 5_0); #endif
CF_EXPORT CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef timer);
CF_EXPORT void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef timer, CFAbsoluteTime fireDate);
CF_EXPORT CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef timer);
CF_EXPORT Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef timer);
CF_EXPORT CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef timer);
CF_EXPORT void CFRunLoopTimerInvalidate(CFRunLoopTimerRef timer);
CF_EXPORT Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef timer);
CF_EXPORT void CFRunLoopTimerGetContext(CFRunLoopTimerRef timer, CFRunLoopTimerContext *context);
CF_EXPORT CFTimeInterval CFRunLoopTimerGetTolerance(CFRunLoopTimerRef timer) CF_AVAILABLE(10_9, 7_0);
CF_EXPORT void CFRunLoopTimerSetTolerance(CFRunLoopTimerRef timer, CFTimeInterval tolerance) CF_AVAILABLE(10_9, 7_0);
|
三. 内部实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| CF_PRIVATE uint32_t __CFGetProcessPortCount(void) { ipc_info_space_t info; ipc_info_name_array_t table = 0; mach_msg_type_number_t tableCount = 0; ipc_info_tree_name_array_t tree = 0; mach_msg_type_number_t treeCount = 0;
kern_return_t ret = mach_port_space_info( mach_task_self(), &info, &table, &tableCount, &tree, &treeCount );
if (ret != KERN_SUCCESS) { return (uint32_t)0; }
if (table != NULL) { ret = vm_deallocate(mach_task_self(), (vm_address_t)table, tableCount * sizeof(*table)); } if (tree != NULL) { ret = vm_deallocate(mach_task_self(), (vm_address_t)tree, treeCount * sizeof(*tree)); }
return (uint32_t)tableCount; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| CF_PRIVATE CFArrayRef __CFStopAllThreads(void) { CFMutableArrayRef suspended_list = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
mach_port_t my_task = mach_task_self(); mach_port_t my_thread = mach_thread_self();
thread_act_array_t thr_list = 0; mach_msg_type_number_t thr_cnt = 0;
kern_return_t ret = task_threads(my_task, &thr_list, &thr_cnt);
if (ret == KERN_SUCCESS) { for (CFIndex idx = 0; idx < thr_cnt; idx++) { thread_act_t thread = thr_list[idx];
if (thread == my_thread) continue;
if (CFArrayContainsValue(suspended_list, CFRangeMake(0, CFArrayGetCount(suspended_list)), (const void *)(uintptr_t)thread)) continue;
ret = thread_suspend(thread); if (ret == KERN_SUCCESS) { CFArrayAppendValue(suspended_list, (const void *)(uintptr_t)thread); } else { mach_port_deallocate(my_task, thread); } }
vm_deallocate(my_task, (vm_address_t)thr_list, sizeof(thread_t) * thr_cnt); }
mach_port_deallocate(my_task, my_thread);
return suspended_list; }
|
在 Mach 内核中,任务(Task)和线程(Thread)是两个不同层次的概念:
Task 对应的是用户空间的进程。
Task (进程)
|
|– Thread 1 (线程1)
|– Thread 2 (线程2)
|– Thread 3 (线程3)
|
|– 共享资源
|– 内存空间
|– 文件描述符
|– 端口权限
|– 其他系统资源
3.1 RunloopMode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| struct __CFRunLoopMode { CFRuntimeBase _base;
pthread_mutex_t _lock;
CFStringRef _name; Boolean _stopped; char _padding[3];
CFMutableSetRef _sources0; CFMutableSetRef _sources1; CFMutableArrayRef _observers; CFMutableArrayRef _timers;
CFMutableDictionaryRef _portToV1SourceMap; __CFPortSet _portSet;
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS dispatch_source_t _timerSource; dispatch_queue_t _queue; Boolean _timerFired; Boolean _dispatchTimerArmed; #endif
#if USE_MK_TIMER_TOO mach_port_t _timerPort; Boolean _mkTimerArmed; #endif
#if DEPLOYMENT_TARGET_WINDOWS DWORD _msgQMask; void (*_msgPump)(void); #endif
uint64_t _timerSoftDeadline; uint64_t _timerHardDeadline; };
|
3.2 Runloop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| struct _block_item { struct _block_item *_next; CFTypeRef _mode; void (^_block)(void); };
typedef struct _per_run_data { uint32_t a; uint32_t b; uint32_t stopped; uint32_t ignoreWakeUps; } _per_run_data;
struct __CFRunLoop { CFRuntimeBase _base; pthread_mutex_t _lock; __CFPort _wakeUpPort; Boolean _unused;
volatile _per_run_data *_perRunData;
pthread_t _pthread; uint32_t _winthread;
CFMutableSetRef _commonModes; CFMutableSetRef _commonModeItems; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes;
struct _block_item *_blocks_head; struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime; CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart; };
|
1 2 3 4 5 6 7 8 9 10 11 12
| RunLoop | |-- _modes (所有模式) | |-- Mode1 | |-- Mode2 | `-- Mode3 | |-- _commonModes (通用模式名称) | |-- "Default" | `-- "Common" | `-- _currentMode (当前模式)
|
3.3 Source
1 2 3 4 5 6 7 8 9 10 11
| struct __CFRunLoopSource { CFRuntimeBase _base; uint32_t _bits; pthread_mutex_t _lock; CFIndex _order; CFMutableBagRef _runLoops; union { CFRunLoopSourceContext version0; CFRunLoopSourceContext1 version1; } _context; };
|
3.4 Observers
1 2 3 4 5 6 7 8 9 10
| struct __CFRunLoopObserver { CFRuntimeBase _base; pthread_mutex_t _lock; CFRunLoopRef _runLoop; CFIndex _rlCount; CFOptionFlags _activities; CFIndex _order; CFRunLoopObserverCallBack _callout; CFRunLoopObserverContext _context; };
|
3.5 Timers
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct __CFRunLoopTimer { CFRuntimeBase _base; uint16_t _bits; pthread_mutex_t _lock; CFRunLoopRef _runLoop; CFMutableSetRef _rlModes; CFAbsoluteTime _nextFireDate; CFTimeInterval _interval; CFTimeInterval _tolerance; uint64_t _fireTSR; CFIndex _order; CFRunLoopTimerCallBack _callout; CFRunLoopTimerContext _context; };
|
3.6 Runloop 的释放
创建在释放方法下面,暂时不详细介绍释放,后续复习时补充。
__CFRunLoopCleanseSources
__CFRunLoopDeallocateSources
__CFRunLoopDeallocateObservers
__CFRunLoopDeallocateTimers
__CFRunLoopDeallocate
3.7 Runloop的创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| static CFRunLoopRef __CFRunLoopCreate(pthread_t t) { CFRunLoopRef loop = NULL; CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
loop = (CFRunLoopRef)_CFRuntimeCreateInstance( kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL );
if (NULL == loop) { return NULL; }
(void)__CFRunLoopPushPerRunData(loop);
__CFRunLoopLockInit(&loop->_lock);
loop->_wakeUpPort = __CFPortAllocate(); if (CFPORT_NULL == loop->_wakeUpPort) HALT;
__CFRunLoopSetIgnoreWakeUps(loop);
loop->_commonModes = CFSetCreateMutable( kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks ); CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode);
loop->_commonModeItems = NULL; loop->_currentMode = NULL; loop->_modes = CFSetCreateMutable( kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks );
loop->_blocks_head = NULL; loop->_blocks_tail = NULL;
loop->_counterpart = NULL;
loop->_pthread = t;
#if DEPLOYMENT_TARGET_WINDOWS loop->_winthread = GetCurrentThreadId(); #else loop->_winthread = 0; #endif
rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true); if (NULL != rlm) __CFRunLoopModeUnlock(rlm);
return loop; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) { if (pthread_equal(t, kNilPthreadT)) { t = pthread_main_thread_np(); }
__CFLock(&loopsLock);
if (!__CFRunLoops) { __CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable( kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks );
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np()); CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { CFRelease(dict); } CFRelease(mainLoop); __CFLock(&loopsLock); }
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); __CFUnlock(&loopsLock);
if (!loop) { CFRunLoopRef newLoop = __CFRunLoopCreate(t); __CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); if (!loop) { CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); loop = newLoop; } __CFUnlock(&loopsLock); CFRelease(newLoop); }
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; }
|
runloop 执行block事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm) { if (!rl->_blocks_head) return false; if (!rlm || !rlm->_name) return false;
Boolean did = false;
struct _block_item *head = rl->_blocks_head; struct _block_item *tail = rl->_blocks_tail; rl->_blocks_head = NULL; rl->_blocks_tail = NULL;
CFSetRef commonModes = rl->_commonModes; CFStringRef curMode = rlm->_name;
__CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl);
struct _block_item *prev = NULL; struct _block_item *item = head; while (item) { struct _block_item *curr = item; item = item->_next;
Boolean doit = false; if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) { doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode)); } else { doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode)); }
if (!doit) prev = curr;
if (doit) { if (prev) prev->_next = item; if (curr == head) head = item; if (curr == tail) tail = prev;
void (^block)(void) = curr->_block; CFRelease(curr->_mode); free(curr);
if (doit) { __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block); did = true; }
Block_release(block); } }
__CFRunLoopLock(rl); __CFRunLoopModeLock(rlm);
if (head) { tail->_next = rl->_blocks_head; rl->_blocks_head = head; if (!rl->_blocks_tail) rl->_blocks_tail = tail; }
return did; }
|
12.24 更新至1664行
未完待续……
思考 & 答案
关于闲等是怎么实现的?
在 RunLoop 中,闲等主要体现在以下几个关键点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| // 1. 使用 mach_msg 等待消息,这是一个系统调用,会让线程进入休眠状态 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, // 关键参数:TIMEOUT_INFINITY 表示无限等待 &voucherState, &voucherCopy ); #endif
// 2. 进入休眠前的标记 if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); __CFRunLoopSetSleeping(rl); // 设置休眠状态
// 3. poll 变量控制是否需要立即返回 Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR); // poll 为 false 时表示需要等待,为 true 时表示立即返回
|
关键区别:
忙等实现
1 2 3 4
| while (!condition) { }
|
闲等实现(RunLoop 采用)
1 2
| mach_msg(... TIMEOUT_INFINITY ...);
|
闲等的优势:
- 不消耗 CPU 资源
- 线程会真正进入休眠状态
- 由系统中断或消息唤醒
- 更节能高效
这就是为什么 RunLoop 能够高效管理线程的原因,它在没有工作时不会消耗 CPU 资源。