Runloop源码解析和实践

RunLoop是干啥的

官翻: Run loops是与线程相关的基础设施的一部分,一个Runloop就是一个事件处理的循环。Runloop的目标是让线程在有事情做的时候保持忙碌、没有事情做的时候保持睡眠。

疑问???

  • Runloop的运行机制
  • Runloop是如何唤醒和睡眠线程的,与线程到底是什么关系
  • Runloop的Source、Timer、Observer和Mode与Runloop到底是什么关系
  • iOS系统怎么使用Runloop的
  • 如何自定义

庖丁解🐂

一个Runloop接收2中不同类型的sources.Input source 发送异步事件,一般是来自其他线程或者是其他应用的;Timer source发送同步事件,会在预设好的时间或者重复间隔内触发。这2种source都会通过特殊的处理程序处理事件。

Input source发送异步事件,这种source runloop在处理的时候会调用runUnitlDate:方法开启一个runloop,并且在运行date时间后退出。Timer source则不会使runloop退出。

在处理input source时,runloops 也会生成相关的通知,你可以注册成为观察者在当前线程来处理其他时间。

#####(补充) runloop 的运行方式

1
2
3
- (void)run;
- (BOOL)runMode:(NSRunLoopMode)mode beforeDate:(NSDate *)limitDate;
- (void)runUntilDate:(NSDate *)limitDate;
  • run方法对应CFRunloopRef中的CFRunLoopRun并不会退出,除非手动调用CFRunLoopStop();通常如果想要永远不会退出RunLoop才会使用此方法,否则可以使用runUntilDate。

  • runMode:beforeDate:则对应CFRunLoopRunInMode(mode,limiteDate,true)方法,只执行一次,执行完就退出;通常用于手动控制RunLoop(例如在while循环中)。

  • runUntilDate:方法其实是CFRunLoopRunInMode(kCFRunLoopDefaultMode,limiteDate,false),执行完并不会退出,继续下一次RunLoop直到timeout。

Modes

一个runloop mode是input source和timer sources的集合,同时包含一个runloop观察者的合集。每次运行一个runloop时,需要指定一个特别的mode。在runloop 运行的过程中,只有和这个mode相关联source才能发送事件(同样,只有和这个mode关联的观察者才能收到通知)。关联了其他mode的source会被暂停一切新事件的发送直到runloop运行在该mode上。

1
2
3
4
5
6
7
8
struct __CFRunLoopMode {
CFStringRef _name; // Mode Name, 例如 @"kCFRunLoopDefaultMode"
CFMutableSetRef _sources0; // Set
CFMutableSetRef _sources1; // Set
CFMutableArrayRef _observers; // Array
CFMutableArrayRef _timers; // Array
...
};

modes通过name来区分,可用通过指定mode的name来自定义一个mode,虽然name在自定义的时候可以任意指定,但是其他内容却不行,当你自定义一个mode的时候,必须添加一个或者多个source(input source 或 timer source) ,或者观察者。

Input Sources

Input sources 给线程发送异步事件,事件的类型和input source的类型相关。一般有2种:Port-based input sources 用来监控Mach ports自定义 input sources 用来监控自定义事件。2者的唯一不同在于如何发送信号:Port-based input sources是kernel内核自动发送信号;自定义 input sources是从其他线程手动发送信号。

Port-Based Sources
  • NSMachPort
  • NSMessagePort

mach 操作系统微内核 在mac os和ios系统中采用。虚拟内存的分配,进程间的通信(基于port)。

每一种服务都是一个进程(http 8080 https 443 ftp 20 21 rtmp 1935),每一个进程都分配一个port(虚拟端口),

Custom Input Sources

自定义一个Input source需要满足如下定义:

  • 需要input source处理的信息
  • 让感兴趣的客户端知道怎么联系你的input source
  • 一个处理程序例程来执行任何客户端的发送请求
  • 取消程序

Cocoa Perform Selector Sources

Perform Selector Sources 在执行完以后会从runloop的mode中移除。

当调用这个方法时,target线程必须包含一个活跃的runloop,runloop会在一次loop中处理所有的排队Perform事件而不是只处理一个。

Timer Sources

timer需要关联一个mode,如果timer不在当前活动的mode上,则不会被触发。如果timer所在的mode执行过程中被切换,则该timer也不会暂停直到mode重新切换回来,这就决定了NSTimer的触发并不是十分可靠的。

Run Loop Observers

1
2
3
4
5
6
7
8
9
10
11
12
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),// 即将进入Loop 0x1
kCFRunLoopBeforeTimers = (1UL << 1),// 即将处理 Timer
kCFRunLoopBeforeSources = (1UL << 2),// 即将处理 Source
kCFRunLoopBeforeWaiting = (1UL << 5),// 即将进入休眠 0x20
kCFRunLoopAfterWaiting = (1UL << 6),// 刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7),// 即将退出Loop
kCFRunLoopAllActivities = 0x0FFFFFFFU
};

Runloop使用场景

  • 使用mach port或者自定义input source 来与其他线程通信
  • 使用NSTimer
  • 使用performSelector
  • 线程保活
  • 系统默认使用

源码解析

源码下载https://opensource.apple.com/tarballs/CF/

Input Source && CFRunLoopSource 的结构
  • source0/自定义 source
1
2
3
4
5
6
7
8
9
10
11
12
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;
  • source1/(mach port source+自定义 source)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
  • CFRunLoopSource
1
2
3
4
5
6
7
8
9
10
11
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order; /* immutable */
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
observer && CFRunLoopObserver 的结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct {
CFIndex version;
void * info;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopObserverContext;
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 */
};
NSTimer && CFRunloopTimer 的结构
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;
const void *(*retain)(const void *info);
void (*release)(const void *info);
CFStringRef (*copyDescription)(const void *info);
} CFRunLoopTimerContext;
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop;
CFMutableSetRef _rlModes;
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval; /* immutable */
CFTimeInterval _tolerance; /* mutable */
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; /* immutable */
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
Mode 的结构
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
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
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; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;//如果是MK_TIMER的话,会通过这个端口唤醒线程
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};

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
struct _block_item {
struct _block_item *_next;
CFTypeRef _mode; // CFString or CFSet
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; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp source0的手动唤醒就是通过给这个端口发消息实现的。
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop 个人理解为runloop的一个配置文件
pthread_t _pthread;
uint32_t _winthread;
CFMutableSetRef _commonModes;//存放 common mode 的集合
CFMutableSetRef _commonModeItems;//每个 common mode 都有的 item (source, timer and observer) 集合
CFRunLoopModeRef _currentMode;
CFMutableSetRef _modes;//这个 run loop 所有的 mode 集合
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFAbsoluteTime _runTime;
CFAbsoluteTime _sleepTime;
CFTypeRef _counterpart;
};

Runloop的创建和销毁 CFRunLoopCreate() && CFRunLoopGet0() && CFRunLoopGetMain() && CFRunLoopGetCurrent() && CFFinalizeRunLoop()

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//获取主线程runloop
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
//获取当前线程runloop
CFRunLoopRef CFRunLoopGetCurrent(void) {
CHECK_FOR_FORK();
CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
if (rl) return rl;
return _CFRunLoopGet0(pthread_self());
}
//保存runloop和pthread的全局字典。key = pthreadPointer(t); value = runloop.
static CFMutableDictionaryRef __CFRunLoops = NULL;
static CFLock_t loopsLock = CFLockInit;
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
//如果当前线程为0 则取主线程.
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
//全局字典为空,则创建字典
if (!__CFRunLoops) {
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
//创建主线程的runloop
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
//将runloop和pthread set到一个临时字典中
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
//将临时字典复制到全局字典,这个是一个原子操作。
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
CFRelease(mainLoop);
__CFLock(&loopsLock);
}
//从全局字典中取出当前线程对应的runloop
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
__CFUnlock(&loopsLock);
//如果runloop为空,新建runloop,并保存到全局字典中
if (!loop) {
CFRunLoopRef newLoop = __CFRunLoopCreate(t);
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);
loop = newLoop;
}
// don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
__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;
}
//入参为一个线程
static CFRunLoopRef __CFRunLoopCreate(pthread_t t) {
CFRunLoopRef loop = NULL;
CFRunLoopModeRef rlm;
uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase);
//创建runloop实例
loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFRunLoopGetTypeID(), size, NULL);
if (NULL == loop) {
return NULL;
}
//初始化配置
(void)__CFRunLoopPushPerRunData(loop);
__CFRunLoopLockInit(&loop->_lock);
//初始化唤醒port
loop->_wakeUpPort = __CFPortAllocate();
if (CFPORT_NULL == loop->_wakeUpPort) HALT;
__CFRunLoopSetIgnoreWakeUps(loop);
//初始化commonModes 并 add kCFRunLoopDefaultMode
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;
}
// 线程退出时调用
CF_PRIVATE void __CFFinalizeRunLoop(uintptr_t data) {
CFRunLoopRef rl = NULL;
if (data <= 1) {
__CFLock(&loopsLock);
if (__CFRunLoops) {
//在全局字典中移除该runloop
rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self()));
if (rl) CFRetain(rl);
CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self()));
}
__CFUnlock(&loopsLock);
} else {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(data - 1), (void (*)(void *))__CFFinalizeRunLoop);
}
if (rl && CFRunLoopGetMain() != rl) { // protect against cooperative threads
if (NULL != rl->_counterpart) {
CFRelease(rl->_counterpart);
rl->_counterpart = NULL;
}
// purge all sources before deallocation
CFArrayRef array = CFRunLoopCopyAllModes(rl);
//移除该runloop的所有source
for (CFIndex idx = CFArrayGetCount(array); idx--;) {
CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
__CFRunLoopRemoveAllSources(rl, modeName);
}
__CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes);
CFRelease(array);
}
if (rl) CFRelease(rl);
}
总结
  • runloop的创建是懒加载的方式创建,在第一次获取该runloop的时候才会去创建,所以子线程如果没有手动的去获取并运行runloop,是不会自动创建的。
  • runloop和线程是一一对应的关系,保存在一个全局的字典中。key是线程的指针,value是对应的runloop.
  • runloop的销毁发生在线程退出时。

Runloop的运行 CFRunLoopRun && CFRunLoopRunSpecific && CFRunLoopRun

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
struct __timeout_context {
dispatch_source_t ds;
CFRunLoopRef rl;
uint64_t termTSR;
};
static void __CFRunLoopTimeoutCancel(void *arg) {
struct __timeout_context *context = (struct __timeout_context *)arg;
CFRelease(context->rl);
dispatch_release(context->ds);
free(context);
}
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
}
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 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */
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;
// 1.通知观察者runloop即将进入loop
if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
//run
result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode);
// 10. 通知观察者runLoop即将退出
if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
__CFRunLoopModeUnlock(currentMode);
__CFRunLoopPopPerRunData(rl, previousPerRun);
rl->_currentMode = previousMode;
__CFRunLoopUnlock(rl);
return result;
}
/**
* 运行run loop
*
* @param rl 运行的RunLoop对象
* @param rlm 运行的mode
* @param seconds run loop超时时间
* @param stopAfterHandle true:run loop处理完事件就退出 false:一直运行直到超时或者被手动终止
* @param previousMode 上一次运行的mode
*
* @return 返回4种状态
*/
static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) {
uint64_t startTSR = mach_absolute_time();
//如果该runloop已停止,直接退出。
if (__CFRunLoopIsStopped(rl)) {
__CFRunLoopUnsetStopped(rl);
return kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
rlm->_stopped = false;
return kCFRunLoopRunStopped;
}
//获取GCD的消息端口
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)));
//看判断条件,只有当前是主线程,才获取端口。(GCD只能唤醒主线程的runloop)
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF();
//使用GCD的source来实现NSTimer
#if USE_DISPATCH_SOURCE_FOR_TIMERS
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
//设置runloop的超时时间,second是参数。
dispatch_source_t timeout_timer = NULL;
struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context));
if (seconds <= 0.0) { // instant timeout
seconds = 0.0;
timeout_context->termTSR = 0ULL;
} else if (seconds <= TIMER_INTERVAL_LIMIT) {
dispatch_queue_t queue = pthread_main_np() ? __CFDispatchQueueGetGenericMatchingMain() : __CFDispatchQueueGetGenericBackground();
timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_retain(timeout_timer);
timeout_context->ds = timeout_timer;
timeout_context->rl = (CFRunLoopRef)CFRetain(rl);
timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds);
dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context
//调用__CFRunLoopTimeout
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
seconds = 9999999999.0;
timeout_context->termTSR = UINT64_MAX;
}
//初始化为true
Boolean didDispatchPortLastTime = true;
int32_t retVal = 0;//返回状态
//do while循环
do {
//runloop睡眠的时候会注册这个端口用来接口消息
__CFPortSet waitSet = rlm->_portSet;
// 设置RunLoop为可以被唤醒状态
__CFRunLoopUnsetIgnoreWakeUps(rl);
// 2.通知observer,即将触发timer回调,处理timer事件
if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
// 3.通知observer,即将触发Source0回调
if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
// 执行加入当前 runloop 的 block
__CFRunLoopDoBlocks(rl, rlm);
// 4.处理 source0 事件 有事件处理返回 true,没有事件返回 false
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
// 如果实际处理了 sources 0,再一次处理 blocks(有可能是source0的回调中又给runloop添加了block)
if (sourceHandledThisLoop) {
__CFRunLoopDoBlocks(rl, rlm);
}
// 如果没有 Sources0 事件处理 并且 没有超时,poll 为 false
// 如果有 Sources0 事件处理 或者 超时,poll 都为 true
Boolean poll = sourceHandledThisLoop || (0ULL == timeout_context->termTSR);
if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) {
//如果收到source1的消息
msg = (mach_msg_header_t *)msg_buffer;
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
goto handle_msg;
}
}
didDispatchPortLastTime = false;
// 6.通知观察者RunLoop即将进入休眠
if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
// 7.设置RunLoop为休眠状态
__CFRunLoopSetSleeping(rl);
// do not do any user callouts after this point (after notifying of sleeping)
// 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.
//将睡眠等待端口添加到当前mach port活跃列表
__CFPortSetInsert(dispatchPort, waitSet);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
//记录开始睡眠时间
CFAbsoluteTime sleepStart = poll ? 0.0 : CFAbsoluteTimeGetCurrent();
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// 等待被唤醒,可以被 sources0、source1、Mach port source,timers、CFRunLoopWakeUp 函数和 GCD 事件(如果在主线程)
do {
//清理消息缓存区
if (kCFUseCollectableAllocator) {
// objc_clear_stack(0);
// <rdar://problem/16393959>
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
// 接收waitSet端口的消息
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
// 如果是 timer 端口唤醒的,进行一下善后处理,之后再处理 timer
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 {
// 不是 timer 端口唤醒的,跳出循环,进行接下来的处理
// Go ahead and leave the inner loop.
break;
}
} while (1);
#else
// 不使用 GCD timer 作为 timer 实现的情况
if (kCFUseCollectableAllocator) {
// objc_clear_stack(0);
// <rdar://problem/16393959>
//清理消息缓存区
memset(msg_buffer, 0, sizeof(msg_buffer));
}
msg = (mach_msg_header_t *)msg_buffer;
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
#endif
//被唤醒了。。。
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
// 记录增加的睡眠时间
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.
//将等待唤醒的端口从mach port活跃端口列表移除
__CFPortSetRemove(dispatchPort, waitSet);
//设置为忽略唤醒状态
__CFRunLoopSetIgnoreWakeUps(rl);
// 取消runloop的休眠状态
// user callouts now OK again
__CFRunLoopUnsetSleeping(rl);
// 8.通知观察者runloop被唤醒
if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
// 9.处理通过端口收到的消息
handle_msg:;
__CFRunLoopSetIgnoreWakeUps(rl);
if (MACH_PORT_NULL == livePort) {
// 不知道哪个端口唤醒的(或者根本没睡),啥也不干
CFRUNLOOP_WAKEUP_FOR_NOTHING();
// handle nothing
} else if (livePort == rl->_wakeUpPort) {
// 被 CFRunLoopWakeUp 函数唤醒的,啥也不干
CFRUNLOOP_WAKEUP_FOR_WAKEUP();
// do nothing on Mac OS
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
else if (modeQueuePort != MACH_PORT_NULL && livePort == modeQueuePort) {
// 被 timers 唤醒,处理 timers
CFRUNLOOP_WAKEUP_FOR_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
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
// 被 timers 唤醒,处理 timers
if (!__CFRunLoopDoTimers(rl, rlm, mach_absolute_time())) {
// Re-arm the next timer
__CFArmNextTimerInMode(rlm, rl);
}
}
#endif
//被GCD唤醒
else if (livePort == dispatchPort) {
CFRUNLOOP_WAKEUP_FOR_DISPATCH();
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL);
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);
_CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
sourceHandledThisLoop = true;
didDispatchPortLastTime = true;
} else {
//以上都不是则是被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
CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort);
mach_msg_header_t *reply = NULL;
//处理source1
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);
}
// 再一次处理 blocks
__CFRunLoopDoBlocks(rl, rlm);
// 善后
if (sourceHandledThisLoop && stopAfterHandle) {
// 处理完当前事件 & runloop 执行完就退出
retVal = kCFRunLoopRunHandledSource;
} else if (timeout_context->termTSR < mach_absolute_time()) {
// run loop超时
retVal = kCFRunLoopRunTimedOut;
} else if (__CFRunLoopIsStopped(rl)) {
// run loop被手动终止
__CFRunLoopUnsetStopped(rl);
retVal = kCFRunLoopRunStopped;
} else if (rlm->_stopped) {
// mode被终止
rlm->_stopped = false;
retVal = kCFRunLoopRunStopped;
} else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
// mode中的Items都为空,退出。
retVal = kCFRunLoopRunFinished;
}
} while (0 == retVal);
if (timeout_timer) {
dispatch_source_cancel(timeout_timer);
dispatch_release(timeout_timer);
} else {
free(timeout_context);
}
return retVal;
}
//接收mach port消息
static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_port_t *livePort, mach_msg_timeout_t timeout, voucher_mach_msg_state_t *voucherState, voucher_t *voucherCopy) {
Boolean originalBuffer = true;
kern_return_t ret = KERN_SUCCESS;
for (;;) { /* In that sleep of death what nightmares may come ... */
mach_msg_header_t *msg = (mach_msg_header_t *)*buffer;
msg->msgh_bits = 0;
msg->msgh_local_port = port;
msg->msgh_remote_port = MACH_PORT_NULL;
msg->msgh_size = buffer_size;
msg->msgh_id = 0;
if (TIMEOUT_INFINITY == timeout) { CFRUNLOOP_SLEEP(); } else { CFRUNLOOP_POLL(); }
//接收或发送消息
ret = mach_msg(msg, MACH_RCV_MSG|(voucherState ? MACH_RCV_VOUCHER : 0)|MACH_RCV_LARGE|((TIMEOUT_INFINITY != timeout) ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, timeout, MACH_PORT_NULL);
// Take care of all voucher-related work right after mach_msg.
// If we don't release the previous voucher we're going to leak it.
voucher_mach_msg_revert(*voucherState);
// Someone will be responsible for calling voucher_mach_msg_revert. This call makes the received voucher the current one.
*voucherState = voucher_mach_msg_adopt(msg);
if (voucherCopy) {
if (*voucherState != VOUCHER_MACH_MSG_STATE_UNCHANGED) {
// Caller requested a copy of the voucher at this point. By doing this right next to mach_msg we make sure that no voucher has been set in between the return of mach_msg and the use of the voucher copy.
// CFMachPortBoost uses the voucher to drop importance explicitly. However, we want to make sure we only drop importance for a new voucher (not unchanged), so we only set the TSD when the voucher is not state_unchanged.
*voucherCopy = voucher_copy();
} else {
*voucherCopy = NULL;
}
}
CFRUNLOOP_WAKEUP(ret);
//接收消息成功
if (MACH_MSG_SUCCESS == ret) {
*livePort = msg ? msg->msgh_local_port : MACH_PORT_NULL;
return true;
}
if (MACH_RCV_TIMED_OUT == ret) {
if (!originalBuffer) free(msg);
*buffer = NULL;
*livePort = MACH_PORT_NULL;
return false;
}
if (MACH_RCV_TOO_LARGE != ret) break;
buffer_size = round_msg(msg->msgh_size + MAX_TRAILER_SIZE);
if (originalBuffer) *buffer = NULL;
originalBuffer = false;
*buffer = realloc(*buffer, buffer_size);
}
HALT;
return false;
}
runloop运行流程总结入下图

runloop内部其实就是一个do while()的循环。只是在没有事件需要处理的时候,runloop会调用__CFRunLoopSetSleeping 方法将当前线程置为睡眠状态,同时会调用 __CFRunLoopServiceMachPort 方法来睡眠线程并等待接收mach发来的唤醒消息。收到消息后,该线程会被唤醒,唤醒后runloop除了处理唤醒它的事件,还需要处理一遍所有等待处理的事件,包括(timer,observer,source,block)。

runloop唤醒事件总结
  • mach port source
  • 手动唤醒Custom Input Source(CFRunLoopSourceSignal(source)/CFRunLoopWakeUp(runloop))
  • dispatch_async(dispatch_get_main_queue)/dispatch_sync(dispatch_get_main_queue)(不要在主线程同步任务,会死锁);
  • timer

Mode和它的四大大王(Source,Timer,Observer,Block)

Mode

Mode的创建也是懒加载

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
struct __CFRunLoopMode srlm;
memset(&srlm, 0, sizeof(srlm));
_CFRuntimeSetInstanceTypeIDAndIsa(&srlm, __kCFRunLoopModeTypeID);
srlm._name = modeName;
rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm);
//mode不为空直接返回,为空则创建新的
if (NULL != rlm) {
__CFRunLoopModeLock(rlm);
return rlm;
}
if (!create) {
return NULL;
}
rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL);
if (NULL == rlm) {
return NULL;
}
//参数的初始化
__CFRunLoopLockInit(&rlm->_lock);
rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName);
rlm->_stopped = false;
rlm->_portToV1SourceMap = NULL;
rlm->_sources0 = NULL;
rlm->_sources1 = NULL;
rlm->_observers = NULL;
rlm->_timers = NULL;
rlm->_observerMask = 0;
rlm->_portSet = __CFPortSetAllocate();
rlm->_timerSoftDeadline = UINT64_MAX;
rlm->_timerHardDeadline = UINT64_MAX;
kern_return_t ret = KERN_SUCCESS;
//初始化timer相关内容
#if USE_DISPATCH_SOURCE_FOR_TIMERS
rlm->_timerFired = false;
rlm->_queue = _dispatch_runloop_root_queue_create_4CF("Run Loop Mode Queue", 0);
//用来唤醒的端口
mach_port_t queuePort = _dispatch_runloop_root_queue_get_port_4CF(rlm->_queue);
if (queuePort == MACH_PORT_NULL) CRASH("*** Unable to create run loop mode queue port. (%d) ***", -1);
rlm->_timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, rlm->_queue);
__block Boolean *timerFiredPointer = &(rlm->_timerFired);
dispatch_source_set_event_handler(rlm->_timerSource, ^{
*timerFiredPointer = true;
});
// Set timer to far out there. The unique leeway makes this timer easy to spot in debug output.
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 321);
dispatch_resume(rlm->_timerSource);
ret = __CFPortSetInsert(queuePort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
#endif
#if USE_MK_TIMER_TOO
//用来唤醒的端口
rlm->_timerPort = mk_timer_create();
ret = __CFPortSetInsert(rlm->_timerPort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert timer port into port set. (%d) ***", ret);
#endif
ret = __CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet);
if (KERN_SUCCESS != ret) CRASH("*** Unable to insert wake up port into port set. (%d) ***", ret);
#if DEPLOYMENT_TARGET_WINDOWS
rlm->_msgQMask = 0;
rlm->_msgPump = NULL;
#endif
CFSetAddValue(rl->_modes, rlm);
CFRelease(rlm);
__CFRunLoopModeLock(rlm); /* return mode locked */
return rlm;
}
//判断mode是否为空 通过这个函数可以看到,只有当source0、source1、timer和block都为空,mode才会被标记为空(这么看observer应该是低等屁民了,没有什么存在感)
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
CHECK_FOR_FORK();
if (NULL == rlm) return true;
#if DEPLOYMENT_TARGET_WINDOWS
if (0 != rlm->_msgQMask) return false;
#endif
Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
//主线程且当前Mode也在CommonMode中,不可能为空,应该是系统有往CommonMode里面添加了东西,会被同步到该Mode中。
if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false;
if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false;
if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false;
struct _block_item *item = rl->_blocks_head;
while (item) {
struct _block_item *curr = item;
item = item->_next;
Boolean doit = false;
if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
} else {
doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
}
if (doit) return false;
}
return true;
}
Source
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//source的创建
CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) {
CHECK_FOR_FORK();
CFRunLoopSourceRef memory;
uint32_t size;
if (NULL == context) CRASH("*** NULL context value passed to CFRunLoopSourceCreate(). (%d) ***", -1);
size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase);
memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, CFRunLoopSourceGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopSourceUnsetSignaled(memory);
__CFRunLoopLockInit(&memory->_lock);
memory->_bits = 0;
memory->_order = order;
memory->_runLoops = NULL;
size = 0;
switch (context->version) {
case 0:
size = sizeof(CFRunLoopSourceContext);
break;
case 1:
size = sizeof(CFRunLoopSourceContext1);
break;
}
objc_memmove_collectable(&memory->_context, context, size);
if (context->retain) {
memory->_context.version0.info = (void *)context->retain(context->info);
}
return memory;
}
//给mode添加source
void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rls)) return;
Boolean doVer0Callout = false;
__CFRunLoopLock(rl);
//如果是common 直接添加到_commonModeItems数组
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rls);
if (NULL != set) {
CFTypeRef context[2] = {rl, rls};
/* add new item to all common-modes */
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
//创建source0和source1的集合
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm && NULL == rlm->_sources0) {
rlm->_sources0 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
rlm->_sources1 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
rlm->_portToV1SourceMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
}
if (NULL != rlm && !CFSetContainsValue(rlm->_sources0, rls) && !CFSetContainsValue(rlm->_sources1, rls)) {
//按source类型添加到不同的集合中
if (0 == rls->_context.version0.version) {
CFSetAddValue(rlm->_sources0, rls);
} else if (1 == rls->_context.version0.version) {
CFSetAddValue(rlm->_sources1, rls);
__CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info);
//如果是source1 还需要把source1对应的port添加到mach port的列表中
if (CFPORT_NULL != src_port) {
CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls);
__CFPortSetInsert(src_port, rlm->_portSet);
}
}
__CFRunLoopSourceLock(rls);
if (NULL == rls->_runLoops) {
rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops!
}
CFBagAddValue(rls->_runLoops, rl);
__CFRunLoopSourceUnlock(rls);
if (0 == rls->_context.version0.version) {
if (NULL != rls->_context.version0.schedule) {
doVer0Callout = true;
}
}
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
if (doVer0Callout) {
// although it looses some protection for the source, we have no choice but
// to do this after unlocking the run loop and mode locks, to avoid deadlocks
// where the source wants to take a lock which is already held in another
// thread which is itself waiting for a run loop/mode lock
rls->_context.version0.schedule(rls->_context.version0.info, rl, modeName); /* CALLOUT */
}
}
//处理source0
static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */
CHECK_FOR_FORK();
CFTypeRef sources = NULL;
Boolean sourceHandled = false;
/* Fire the version 0 sources */
//获取当前mode的source0集合
if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) {
CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources);
}
if (NULL != sources) {
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
// sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
//如果是单个事件
if (CFGetTypeID(sources) == CFRunLoopSourceGetTypeID()) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources;
__CFRunLoopSourceLock(rls);
//这里在处理完这个source之后,会把这个source标记为不再处理!!!!后面demo里有应用。
if (__CFRunLoopSourceIsSignaled(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
//调用source0对应的回调
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
//如果是一个事件列表
CFIndex cnt = CFArrayGetCount((CFArrayRef)sources);
CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL);
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx);
__CFRunLoopSourceLock(rls);
if (__CFRunLoopSourceIsSignaled(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnlock(rls);
//调用source0对应的回调 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info);
CHECK_FOR_FORK();
sourceHandled = true;
} else {
__CFRunLoopSourceUnlock(rls);
}
} else {
__CFRunLoopSourceUnlock(rls);
}
if (stopAfterHandle && sourceHandled) {
break;
}
}
}
CFRelease(sources);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
}
return sourceHandled;
}
//处理source1
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();
Boolean sourceHandled = false;
/* Fire a version 1 source */
CFRetain(rls);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
__CFRunLoopSourceLock(rls);
if (__CFIsValid(rls)) {
__CFRunLoopSourceUnsetSignaled(rls);
__CFRunLoopSourceUnlock(rls);
__CFRunLoopDebugInfoForRunLoopSource(rls);
//调用source1对应的回调
__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 {
if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); }
__CFRunLoopSourceUnlock(rls);
}
CFRelease(rls);
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
return sourceHandled;
}
source总结

通过对比source0和source1的处理函数发现,source0有2种情况,单个事件和事件列表,而source1只有单个事件的处理,个人理解是因为source1的事件是即时处理的,因为source1可以唤醒runloop,只要有source1事件runloop就会去处理,所有不存在处理事件列表的情况,而source0有可能只是标记为待处理而没有手动唤醒runloop,当标记为待处理source0事件后,只会被添加到mode的source0集合中,在runloop被唤醒后统一处理。

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) {
CHECK_FOR_FORK();
if (isnan(interval)) {
CRSetCrashLogMessage("NaN was used as an interval for a CFRunLoopTimer");
HALT;
}
CFRunLoopTimerRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase);
memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, CFRunLoopTimerGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopTimerUnsetFiring(memory);
__CFRunLoopLockInit(&memory->_lock);
memory->_runLoop = NULL;
memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
memory->_order = order;
if (interval < 0.0) interval = 0.0;
memory->_interval = interval;
memory->_tolerance = 0.0;
//fireDate 首次触发的绝对时间
if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT;
memory->_nextFireDate = fireDate;
memory->_fireTSR = 0ULL;
//获取mach内核和CF内核的绝对时间
uint64_t now2 = mach_absolute_time();
CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent();
//_fireTSR为本次应触发的绝对时间点
if (fireDate < now1) {
memory->_fireTSR = now2;
} else if (TIMER_INTERVAL_LIMIT < fireDate - now1) {
memory->_fireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT);
} else {
memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1);
}
memory->_callout = callout;
if (NULL != context) {
if (context->retain) {
memory->_context.info = (void *)context->retain(context->info);
} else {
memory->_context.info = context->info;
}
memory->_context.retain = context->retain;
memory->_context.release = context->release;
memory->_context.copyDescription = context->copyDescription;
} else {
memory->_context.info = 0;
memory->_context.retain = 0;
memory->_context.release = 0;
memory->_context.copyDescription = 0;
}
return memory;
}
void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) {
CHECK_FOR_FORK();
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return;
__CFRunLoopLock(rl);
//如果是common mode直接加到_commonModeItems
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlt);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlt};
/* add new item to all common-modes */
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
//创建timers的数组
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm) {
if (NULL == rlm->_timers) {
CFArrayCallBacks cb = kCFTypeArrayCallBacks;
cb.equal = NULL;
rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
}
}
//判断timer是否被添加到当前mode
if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) {
__CFRunLoopTimerLock(rlt);
if (NULL == rlt->_runLoop) {
rlt->_runLoop = rl;
} else if (rl != rlt->_runLoop) {
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
return;
}
//timer将当前mode标记为已添加
CFSetAddValue(rlt->_rlModes, rlm->_name);
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
//添加timer到mode
__CFRepositionTimerInMode(rlm, rlt, false);
__CFRunLoopTimerFireTSRUnlock();
if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) {
// Normally we don't do this on behalf of clients, but for
// backwards compatibility due to the change in timer handling...
if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl);
}
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
//重新排列这个mode中的所有timer触发时刻
static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) {
if (!rlt) return;
CFMutableArrayRef timerArray = rlm->_timers;
if (!timerArray) return;
Boolean found = false;
// If we know in advance that the timer is not in the array (just being added now) then we can skip this search
if (isInArray) {
CFIndex idx = CFArrayGetFirstIndexOfValue(timerArray, CFRangeMake(0, CFArrayGetCount(timerArray)), rlt);
if (kCFNotFound != idx) {
CFRetain(rlt);
CFArrayRemoveValueAtIndex(timerArray, idx);
found = true;
}
}
if (!found && isInArray) return;
CFIndex newIdx = __CFRunLoopInsertionIndexInTimerArray(timerArray, rlt);
CFArrayInsertValueAtIndex(timerArray, newIdx, rlt);
__CFArmNextTimerInMode(rlm, rlt->_runLoop);
if (isInArray) CFRelease(rlt);
}
//返回timer需要插入的索引
static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) {
CFIndex cnt = CFArrayGetCount(array);
if (cnt <= 0) {
return 0;
}
//timer大于256 如果最后一个item的fireTSR小于待插入的timer,直接插入到最后一个位置否则如果第一个item的fireTSR大于带插入的timer,直接插入第一个位置。
if (256 < cnt) {
CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, cnt - 1);
if (item->_fireTSR <= rlt->_fireTSR) {
return cnt;
}
item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, 0);
if (rlt->_fireTSR < item->_fireTSR) {
return 0;
}
}
//二分查找一个合适的位置。
CFIndex add = (1 << flsl(cnt)) * 2;
CFIndex idx = 0;
Boolean lastTestLEQ;
do {
add = add / 2;
lastTestLEQ = false;
CFIndex testIdx = idx + add;
if (testIdx < cnt) {
CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, testIdx);
if (item->_fireTSR <= rlt->_fireTSR) {
idx = testIdx;
lastTestLEQ = true;
}
}
} while (0 < add);
return lastTestLEQ ? idx + 1 : idx;
}
static void __CFArmNextTimerInMode(CFRunLoopModeRef rlm, CFRunLoopRef rl) {
uint64_t nextHardDeadline = UINT64_MAX;//最晚的时间点
uint64_t nextSoftDeadline = UINT64_MAX;//应该触发的时间点
if (rlm->_timers) {
// Look at the list of timers. We will calculate two TSR values; the next soft and next hard deadline.
// The next soft deadline is the first time we can fire any timer. This is the fire date of the first timer in our sorted list of timers.
// The next hard deadline is the last time at which we can fire the timer before we've moved out of the allowable tolerance of the timers in our list.
for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) {
CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers , idx);
// discount timers currently firing
if (__CFRunLoopTimerIsFiring(t)) continue;
int32_t err = CHECKINT_NO_ERROR;
//SoftDeadline是理应触发的时间
uint64_t oneTimerSoftDeadline = t->_fireTSR;
//HardDeadline是理应触发的时间加上tolerance(即最晚触发时间)
uint64_t oneTimerHardDeadline = check_uint64_add(t->_fireTSR, __CFTimeIntervalToTSR(t->_tolerance), &err);
if (err != CHECKINT_NO_ERROR) oneTimerHardDeadline = UINT64_MAX;
// We can stop searching if the soft deadline for this timer exceeds the current hard deadline. Otherwise, later timers with lower tolerance could still have earlier hard deadlines.
//通过这几行代码对deadline进行修正,保证前边的长tolerance的timer不会影响后面的timer的触发
//应触发的时间点 > 下次最晚触发时间点 直接退出
if (oneTimerSoftDeadline > nextHardDeadline) {
break;
}
//应触发的时间点 < 下次最晚触发时间点
if (oneTimerSoftDeadline < nextSoftDeadline) {
nextSoftDeadline = oneTimerSoftDeadline;
}
//最晚触发时间点 < 下次最晚触发时间点
if (oneTimerHardDeadline < nextHardDeadline) {
nextHardDeadline = oneTimerHardDeadline;
}
}
if (nextSoftDeadline < UINT64_MAX && (nextHardDeadline != rlm->_timerHardDeadline || nextSoftDeadline != rlm->_timerSoftDeadline)) {
if (CFRUNLOOP_NEXT_TIMER_ARMED_ENABLED()) {
CFRUNLOOP_NEXT_TIMER_ARMED((unsigned long)(nextSoftDeadline - mach_absolute_time()));
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
// We're going to hand off the range of allowable timer fire date to dispatch and let it fire when appropriate for the system.
uint64_t leeway = __CFTSRToNanoseconds(nextHardDeadline - nextSoftDeadline);
dispatch_time_t deadline = __CFTSRToDispatchTime(nextSoftDeadline);
#if USE_MK_TIMER_TOO
//对于有leeway的情况(有tolerance的情况),只采用_dispatch_source_set_runloop_timer_4CF的方法
if (leeway > 0) {
// Only use the dispatch timer if we have any leeway
// <rdar://problem/14447675>
// Cancel the mk timer
if (rlm->_mkTimerArmed && rlm->_timerPort) {
AbsoluteTime dummy;
mk_timer_cancel(rlm->_timerPort, &dummy);
rlm->_mkTimerArmed = false;
}
// Arm the dispatch timer
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
rlm->_dispatchTimerArmed = true;
} else {
// 对于leeway为0的情况(无tolerance的情况),采用mk_timer的方式
// Cancel the dispatch timer
if (rlm->_dispatchTimerArmed) {
// Cancel the dispatch timer
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 888);
rlm->_dispatchTimerArmed = false;
}
// Arm the mk timer
if (rlm->_timerPort) {
mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
rlm->_mkTimerArmed = true;
}
}
#else
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, deadline, DISPATCH_TIME_FOREVER, leeway);
#endif
#else
if (rlm->_timerPort) {
mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(nextSoftDeadline));
}
#endif
} else if (nextSoftDeadline == UINT64_MAX) {
// Disarm the timers - there is no timer scheduled
// 移除timer
if (rlm->_mkTimerArmed && rlm->_timerPort) {
AbsoluteTime dummy;
mk_timer_cancel(rlm->_timerPort, &dummy);
rlm->_mkTimerArmed = false;
}
#if USE_DISPATCH_SOURCE_FOR_TIMERS
if (rlm->_dispatchTimerArmed) {
_dispatch_source_set_runloop_timer_4CF(rlm->_timerSource, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, 333);
rlm->_dispatchTimerArmed = false;
}
#endif
}
}
rlm->_timerHardDeadline = nextHardDeadline;
rlm->_timerSoftDeadline = nextSoftDeadline;
}
//处理timer
// mode and rl are locked on entry and exit
static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */
Boolean timerHandled = false;
uint64_t oldFireTSR = 0;
/* Fire a timer */
CFRetain(rlt);
__CFRunLoopTimerLock(rlt);
//一堆判断条件
if (__CFIsValid(rlt) && rlt->_fireTSR <= mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl) {
void *context_info = NULL;
void (*context_release)(const void *) = NULL;
if (rlt->_context.retain) {
context_info = (void *)rlt->_context.retain(rlt->_context.info);
context_release = rlt->_context.release;
} else {
context_info = rlt->_context.info;
}
Boolean doInvalidate = (0.0 == rlt->_interval);
__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.
//重置应触发时间和最晚触发时间
rlm->_timerSoftDeadline = UINT64_MAX;
rlm->_timerHardDeadline = UINT64_MAX;
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
oldFireTSR = rlt->_fireTSR;
__CFRunLoopTimerFireTSRUnlock();
__CFArmNextTimerInMode(rlm, rl);
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
//处理timer的回调
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt->_callout, rlt, context_info);
CHECK_FOR_FORK();
if (doInvalidate) {
CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */
}
if (context_release) {
context_release(context_info);
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
__CFRunLoopTimerLock(rlt);
//timer处理成功的标记
timerHandled = true;
__CFRunLoopTimerUnsetFiring(rlt);
}
//本次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. */
//一下次的触发时间已经设置了 而且比上次的时间大 说明设置的没有问题,直接更新。
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();
//上面算了一堆就是计算一个正确的nextFireTSR,到这里已经拿到正确的值了,可以赋值。
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 {
//timer没有加到一个runloop里面。这个timer应该不会被触发。下面也没有调整下次触发时间的操作。。。
__CFRunLoopTimerUnlock(rlt);
__CFRunLoopTimerFireTSRLock();
rlt->_fireTSR = nextFireTSR;
rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTimeIntervalUntilTSR(nextFireTSR);
__CFRunLoopTimerFireTSRUnlock();
}
}
} else {
__CFRunLoopTimerUnlock(rlt);
}
CFRelease(rlt);
return timerHandled;
}
timer总结

  • 对于重复的NSTimer,其多次触发的时刻不是一开始算好的,而是timer触发后计算的。但是计算时参考的是上次应当触发的时间_fireTSR,因此计算出的下次触发的时刻不会有误差。
  • 设置了tolerance的NSTimer,对于iOS和MacOS系统,实质上会采用GCD timer的形式注册到内核中,GCD timer触发后,再由RunLoop处理其回调逻辑。对于没有设置tolerance的timer,则是用mk_timer的形式注册。
  • RunLoopMode中timer的排序是按照_fireTSR,也就是应当触发的时间排序的。
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//创建observer
CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) {
CHECK_FOR_FORK();
CFRunLoopObserverRef memory;
UInt32 size;
size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase);
memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, CFRunLoopObserverGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
__CFSetValid(memory);
__CFRunLoopObserverUnsetFiring(memory);
if (repeats) {
__CFRunLoopObserverSetRepeats(memory);
} else {
__CFRunLoopObserverUnsetRepeats(memory);
}
__CFRunLoopLockInit(&memory->_lock);
memory->_runLoop = NULL;
memory->_rlCount = 0;
memory->_activities = activities;
memory->_order = order;
memory->_callout = callout;
if (context) {
if (context->retain) {
memory->_context.info = (void *)context->retain(context->info);
} else {
memory->_context.info = context->info;
}
memory->_context.retain = context->retain;
memory->_context.release = context->release;
memory->_context.copyDescription = context->copyDescription;
} else {
memory->_context.info = 0;
memory->_context.retain = 0;
memory->_context.release = 0;
memory->_context.copyDescription = 0;
}
return memory;
}
//给mode添加observer
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
if (__CFRunLoopIsDeallocating(rl)) return;
if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
__CFRunLoopLock(rl);
//如果是common mode直接加到_commonModeItems
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlo);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
/* add new item to all common-modes */
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
//创建_observers数组
rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm && NULL == rlm->_observers) {
rlm->_observers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
}
//判断是否已添加
if (NULL != rlm && !CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo)) {
Boolean inserted = false;
for (CFIndex idx = CFArrayGetCount(rlm->_observers); idx--; ) {
CFRunLoopObserverRef obs = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
//有一个排序,只有order大于已添加的observer 才会被添加到数组中
if (obs->_order <= rlo->_order) {
CFArrayInsertValueAtIndex(rlm->_observers, idx + 1, rlo);
inserted = true;
break;
}
}
//添加失败直接插到第一个位置
if (!inserted) {
CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo);
}
rlm->_observerMask |= rlo->_activities;
__CFRunLoopObserverSchedule(rlo, rl, rlm);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
CHECK_FOR_FORK();
CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
if (cnt < 1) return;
/* Fire the observers */
STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef));
CFIndex obs_cnt = 0;
//将列表中 活动 && 可用 && 未处理 的observer添加到一个临时的数组中
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo);
}
}
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
for (CFIndex idx = 0; idx < obs_cnt; idx++) {
CFRunLoopObserverRef rlo = collectedObservers[idx];
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo);
__CFRunLoopObserverSetFiring(rlo);
__CFRunLoopObserverUnlock(rlo);
//调用observer的回调
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info);
if (doInvalidate) {
CFRunLoopObserverInvalidate(rlo);
}
__CFRunLoopObserverUnsetFiring(rlo);
} else {
__CFRunLoopObserverUnlock(rlo);
}
CFRelease(rlo);
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (collectedObservers != buffer) free(collectedObservers);
}
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//给runloop添加一个block
void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) {
CHECK_FOR_FORK();
//保证mode存在
if (CFStringGetTypeID() == CFGetTypeID(mode)) {
mode = CFStringCreateCopy(kCFAllocatorSystemDefault, (CFStringRef)mode);
__CFRunLoopLock(rl);
// ensure mode exists
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)mode, true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
__CFRunLoopUnlock(rl);
} else if (CFArrayGetTypeID() == CFGetTypeID(mode)) {
CFIndex cnt = CFArrayGetCount((CFArrayRef)mode);
const void **values = (const void **)malloc(sizeof(const void *) * cnt);
CFArrayGetValues((CFArrayRef)mode, CFRangeMake(0, cnt), values);
mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
__CFRunLoopLock(rl);
// ensure modes exist
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
}
__CFRunLoopUnlock(rl);
free(values);
} else if (CFSetGetTypeID() == CFGetTypeID(mode)) {
CFIndex cnt = CFSetGetCount((CFSetRef)mode);
const void **values = (const void **)malloc(sizeof(const void *) * cnt);
CFSetGetValues((CFSetRef)mode, values);
mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks);
__CFRunLoopLock(rl);
// ensure modes exist
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true);
if (currentMode) __CFRunLoopModeUnlock(currentMode);
}
__CFRunLoopUnlock(rl);
free(values);
} else {
mode = NULL;
}
block = Block_copy(block);
//如果mode或者block为空 直接返回
if (!mode || !block) {
if (mode) CFRelease(mode);
if (block) Block_release(block);
return;
}
//将block添加到列表中
__CFRunLoopLock(rl);
struct _block_item *new_item = (struct _block_item *)malloc(sizeof(struct _block_item));
new_item->_next = NULL;
new_item->_mode = mode;
new_item->_block = block;
if (!rl->_blocks_tail) {
rl->_blocks_head = new_item;
} else {
rl->_blocks_tail->_next = new_item;
}
rl->_blocks_tail = new_item;
__CFRunLoopUnlock(rl);
}
//处理block
static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm) { // Call with rl and rlm locked
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;
//遍历block列表
while (item) {
struct _block_item *curr = item;
item = item->_next;
Boolean doit = false;
//当前mode是block所属的mode一样 || 当前mode是common mode且commons中包含了当前mode
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) {
//调用block
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block);
did = true;
}
Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc
}
}
__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;
}
block总结
  • 可以直接给runloop添加block.添加成功后,block会在下一次runloop运行时被触发。
  • block不能唤醒runloop,只会被添加到链表中,等待下一次runloop被唤醒后才会被执行。

Runloop实践

查看Main Runloop的结构

1
2
NSRunLoop *runloop = [NSRunLoop mainRunLoop];
NSLog(@"runloop = %@",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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<CFRunLoop 0x60c0001e7800 [0x10805cc80]>{
//唤醒端口 && 当前状态 && 是否忽略唤醒
wakeup port = 0x1803, stopped = false, ignoreWakeUps = false,
//current mode
current mode = kCFRunLoopDefaultMode,
//common mode 包含2个子mode
common modes = <CFBasicHash 0x60c00004db90 [0x10805cc80]>{type = mutable set, count = 2,
entries =>
0 : <CFString 0x1093cce88 [0x10805cc80]>{contents = "UITrackingRunLoopMode"}
2 : <CFString 0x108032818 [0x10805cc80]>{contents = "kCFRunLoopDefaultMode"}
}
,
//common mode 的items(包括 timer && source && observer)
//observer activities (0x20 == kCFRunLoopBeforeWaiting) (0x1 == kCFRunLoopEntry) (0xa0 == kCFRunLoopBeforeWaiting || kCFRunLoopExit)
common mode items = <CFBasicHash 0x60c00004df50 [0x10805cc80]>{type = mutable set, count = 13,
entries =>
//source0 系统事件
0 : <CFRunLoopSource 0x60c000167a40 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10cf0675a)}}
//处理手势的通知
1 : <CFRunLoopObserver 0x608000122bc0 [0x10805cc80]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x1087f06b3), context = <CFRunLoopObserver context 0x6080000dfa30>}
//autoreleasepool相关通知
2 : <CFRunLoopObserver 0x6040001226c0 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (
0 : <0x7fa8a2802048>
)}}
3 : <CFRunLoopObserver 0x604000122940 [0x10805cc80]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (
0 : <0x7fa8a2802048>
)}}
//mach port source
4 : <CFRunLoopSource 0x60c000168b80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 22787, subsystem = 0x10939e668, context = 0x60000003adc0}}
//处理事件队列的source
6 : <CFRunLoopSource 0x604000167ec0 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x60c000141fa0, callout = __handleEventQueue (0x108b67bb2)}}
//处理动画事务的通知
16 : <CFRunLoopObserver 0x604000122b20 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x10dd374ce), context = <CFRunLoopObserver context 0x0>}
//mach port source
17 : <CFRunLoopSource 0x604000167f80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 14599, subsystem = 0x109383fe8, context = 0x0}}
//CA动画提交前的通知
18 : <CFRunLoopObserver 0x604000122a80 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x108239da1), context = <CFRunLoopObserver context 0x7fa8a3100000>}
//处理系统事件 source0
19 : <CFRunLoopSource 0x604000167e00 [0x10805cc80]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x60c00004e400, callout = __handleHIDEventFetcherDrain (0x108b67bbe)}}
//处理系统事件 source1
20 : <CFRunLoopSource 0x60c000167b00 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x2c03, callout = PurpleEventCallback (0x10cf08bf7)}}
//CA动画提交后的通知
21 : <CFRunLoopObserver 0x604000122800 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x108239e1c), context = <CFRunLoopObserver context 0x7fa8a3100000>}
//Front Board Services(前台服务)
22 : <CFRunLoopSource 0x6040001687c0 [0x10805cc80]>{signalled = Yes, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x6040000a8d00, callout = FBSSerialQueueRunLoopSourceHandler (0x10c67182f)}}
}
,
modes = <CFBasicHash 0x60c00004dbc0 [0x10805cc80]>{type = mutable set, count = 4,
entries =>
//UITrackingRunLoopMode 的 items
2 : <CFRunLoopMode 0x60c0001869a0 [0x10805cc80]>{name = UITrackingRunLoopMode, port set = 0x1c03, queue = 0x60c000141e40, source = 0x60c000186a70 (not fired), timer port = 0x5403,
//source0
sources0 = <CFBasicHash 0x60c00004dfb0 [0x10805cc80]>{type = mutable set, count = 4,
entries =>
0 : <CFRunLoopSource 0x60c000167a40 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10cf0675a)}}
3 : <CFRunLoopSource 0x604000167ec0 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x60c000141fa0, callout = __handleEventQueue (0x108b67bb2)}}
4 : <CFRunLoopSource 0x6040001687c0 [0x10805cc80]>{signalled = Yes, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x6040000a8d00, callout = FBSSerialQueueRunLoopSourceHandler (0x10c67182f)}}
5 : <CFRunLoopSource 0x604000167e00 [0x10805cc80]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x60c00004e400, callout = __handleHIDEventFetcherDrain (0x108b67bbe)}}
}
,
//source1
sources1 = <CFBasicHash 0x60c00004dfe0 [0x10805cc80]>{type = mutable set, count = 3,
entries =>
0 : <CFRunLoopSource 0x60c000168b80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 22787, subsystem = 0x10939e668, context = 0x60000003adc0}}
1 : <CFRunLoopSource 0x604000167f80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 14599, subsystem = 0x109383fe8, context = 0x0}}
2 : <CFRunLoopSource 0x60c000167b00 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x2c03, callout = PurpleEventCallback (0x10cf08bf7)}}
}
,
//observer
observers = (
"<CFRunLoopObserver 0x604000122940 [0x10805cc80]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fa8a2802048>\n)}}",
"<CFRunLoopObserver 0x608000122bc0 [0x10805cc80]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x1087f06b3), context = <CFRunLoopObserver context 0x6080000dfa30>}",
"<CFRunLoopObserver 0x604000122a80 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x108239da1), context = <CFRunLoopObserver context 0x7fa8a3100000>}",
"<CFRunLoopObserver 0x604000122b20 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x10dd374ce), context = <CFRunLoopObserver context 0x0>}",
"<CFRunLoopObserver 0x604000122800 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x108239e1c), context = <CFRunLoopObserver context 0x7fa8a3100000>}",
"<CFRunLoopObserver 0x6040001226c0 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fa8a2802048>\n)}}"
),
timers = (null),
currently 558352445 (30290423333420) / soft deadline in: 1.84467138e+10 sec (@ -1) / hard deadline in: 1.84467138e+10 sec (@ -1)
},
//GSEventReceiveRunLoopMode 接受系统事件的内部 Mode
3 : <CFRunLoopMode 0x60c000186b40 [0x10805cc80]>{name = GSEventReceiveRunLoopMode, port set = 0x5203, queue = 0x60c000141ef0, source = 0x60c000186c10 (not fired), timer port = 0x5103,
sources0 = <CFBasicHash 0x60c00004e070 [0x10805cc80]>{type = mutable set, count = 1,
entries =>
0 : <CFRunLoopSource 0x60c000167a40 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10cf0675a)}}
}
,
sources1 = <CFBasicHash 0x60c00004e0a0 [0x10805cc80]>{type = mutable set, count = 1,
entries =>
2 : <CFRunLoopSource 0x60c000167bc0 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x2c03, callout = PurpleEventCallback (0x10cf08bf7)}}
}
,
observers = (null),
timers = (null),
currently 558352445 (30290424620943) / soft deadline in: 1.84467138e+10 sec (@ -1) / hard deadline in: 1.84467138e+10 sec (@ -1)
},
//kCFRunLoopDefaultMode
4 : <CFRunLoopMode 0x60c000186660 [0x10805cc80]>{name = kCFRunLoopDefaultMode, port set = 0x2503, queue = 0x60c000141ce0, source = 0x60c000186730 (not fired), timer port = 0x2303,
sources0 = <CFBasicHash 0x60c00004e010 [0x10805cc80]>{type = mutable set, count = 4,
entries =>
0 : <CFRunLoopSource 0x60c000167a40 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x0, callout = PurpleEventSignalCallback (0x10cf0675a)}}
3 : <CFRunLoopSource 0x604000167ec0 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 0, info = 0x60c000141fa0, callout = __handleEventQueue (0x108b67bb2)}}
4 : <CFRunLoopSource 0x6040001687c0 [0x10805cc80]>{signalled = Yes, valid = Yes, order = 0, context = <CFRunLoopSource context>{version = 0, info = 0x6040000a8d00, callout = FBSSerialQueueRunLoopSourceHandler (0x10c67182f)}}
5 : <CFRunLoopSource 0x604000167e00 [0x10805cc80]>{signalled = No, valid = Yes, order = -2, context = <CFRunLoopSource context>{version = 0, info = 0x60c00004e400, callout = __handleHIDEventFetcherDrain (0x108b67bbe)}}
}
,
sources1 = <CFBasicHash 0x60c00004e040 [0x10805cc80]>{type = mutable set, count = 3,
entries =>
0 : <CFRunLoopSource 0x60c000168b80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 22787, subsystem = 0x10939e668, context = 0x60000003adc0}}
1 : <CFRunLoopSource 0x604000167f80 [0x10805cc80]>{signalled = No, valid = Yes, order = 0, context = <CFRunLoopSource MIG Server> {port = 14599, subsystem = 0x109383fe8, context = 0x0}}
2 : <CFRunLoopSource 0x60c000167b00 [0x10805cc80]>{signalled = No, valid = Yes, order = -1, context = <CFRunLoopSource context>{version = 1, info = 0x2c03, callout = PurpleEventCallback (0x10cf08bf7)}}
}
,
observers = (
"<CFRunLoopObserver 0x604000122940 [0x10805cc80]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fa8a2802048>\n)}}",
"<CFRunLoopObserver 0x608000122bc0 [0x10805cc80]>{valid = Yes, activities = 0x20, repeats = Yes, order = 0, callout = _UIGestureRecognizerUpdateObserver (0x1087f06b3), context = <CFRunLoopObserver context 0x6080000dfa30>}",
"<CFRunLoopObserver 0x604000122a80 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 1999000, callout = _beforeCACommitHandler (0x108239da1), context = <CFRunLoopObserver context 0x7fa8a3100000>}",
"<CFRunLoopObserver 0x604000122b20 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x10dd374ce), context = <CFRunLoopObserver context 0x0>}",
"<CFRunLoopObserver 0x604000122800 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2001000, callout = _afterCACommitHandler (0x108239e1c), context = <CFRunLoopObserver context 0x7fa8a3100000>}",
"<CFRunLoopObserver 0x6040001226c0 [0x10805cc80]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x10820ad92), context = <CFArray 0x604000044890 [0x10805cc80]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fa8a2802048>\n)}}"
),
timers = <CFArray 0x6080000aa5c0 [0x10805cc80]>{type = mutable-small, count = 1, values = (
0 : <CFRunLoopTimer 0x600000168ac0 [0x10805cc80]>{valid = Yes, firing = No, interval = 0, tolerance = 0, next fire date = 558352446 (1.35804296 @ 30291784384812), callout = (Delayed Perform) UIApplication _accessibilitySetUpQuickSpeak (0x106e7e849 / 0x1086fb31b) (/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/UIKit.framework/UIKit), context = <CFRunLoopTimer context 0x600000076700>}
)},
currently 558352445 (30290424667708) / soft deadline in: 1.35971708 sec (@ 30291784384812) / hard deadline in: 1.35971705 sec (@ 30291784384812)
},
//kCFRunLoopCommonModes
5 : <CFRunLoopMode 0x60c000186e80 [0x10805cc80]>{name = kCFRunLoopCommonModes, port set = 0x420b, queue = 0x60c000142520, source = 0x60c000186db0 (not fired), timer port = 0x350b,
sources0 = (null),
sources1 = (null),
observers = (null),
timers = (null),
currently 558352445 (30290426387800) / soft deadline in: 1.84467138e+10 sec (@ -1) / hard deadline in: 1.84467138e+10 sec (@ -1)
},
}
}

给系统mode添加自定义items(timer && source && observer)

为了方便观察添加是否成功,我们不在主线程的runloop中添加,自定义一个新的线程。

添加Custom Input Source注意事项
  • custom input source 默认状态为不处理,需要手动唤醒,手动唤醒需要先标记为待处理状态,每次runloop处理完后状态会被置回不处理。
  • 在子线程添加source需要在runloop run的代码之前添加,因为run后该线程会马上休眠(当前runloop中没有能唤醒自己的source),不再这行run后面的代码。
添加Mach Port Input Source注意事项
  • 需要同时记录主线程端口和子线程端口号,需要唤醒对应线程时直接使用该端口发送消息即可,不需要像Custom Input Source那样做标记。

给runloop添加自定义mode和items

  • 需要注意的是不能直接调用run这个方法,因为这个方法是运行在DefaultMode下的,不会触发自定义mode中的source,需要调用runMode:beforeDate方法开启runloop.

这里是demo

Runloop在iOS中的应用

这块直接看YY博客吧,已经没法再补充更多了。。。

博客链接https://blog.ibireme.com/2015/05/18/runloop/

最后的总结

Runloop是一个事件处理的循环。Runloop的目标是让线程在有事情做的时候保持忙碌、没有事情做的时候保持睡眠。

Runloop使用Mach内核实现线程的睡眠,通过Source和Timer来唤醒线程,Source和Timer最终都是通过Mach Port来唤醒的线程。

Source有CustomSource和Mach Port Source2种,CustomSource唤醒线程前需要先被标注为待处理,MachPortSource则直接使用端口号发送唤醒消息。

Timer有两种实现方式分别是MK_Timer和GCD Timer,在runloop中Timer被转为了一个存了触发时间的列表,这个触发时间是一个绝对时间,会按时间大小升序排序,在最小的时间被触发后,Runloop会更新列表保证时间始终是升序排列。如果Runloop在某次运行中阻塞了很长时间,Timer的触发会受到影响。过期的时间点会被移除而不会去触发。

Runloop的状态都可以通过添加Observer来得到。Observer在Runloop中是按order优先级升序排序的,排在前面的通知会先被触发(order越小优先级反而越高)。

Mode表示当前Runloop运行在哪个模式上,Runloop必须运行在一种Mode上,Runloop在创建时会有一个DefaultMode,可以通过runmode:beforeDate 切换Runloop当前运行的Mode。

Mode中包含了上面的Source,Timer和Observer三种Items。Runloop运行的时候其实就是在处理这些Items中的内容,如果这三种Items都没有要处理的内容,Runloop就要开始睡了,而当Mode的items为空时,当前Runloop会退出。

CommonMode不是一种真正的Mode,它是一个所有Mode的集合,如果把上面三种Items添加到CommonMode,那这些Items会被添加到集合中所有的Mode中。所以添加到CommonMode中Items,不管当前Runloop运行在哪种Mode上,Items中需要处理的事件都会被触发。(前提是这个Mode已经被添加到了CommonMode集合中)。