
Mach
Mach是XNU的核心,被BSD層包裝。XNU由以下幾個(gè)組件組成:
- MACH內(nèi)核
- 進(jìn)程和線程抽象
- 虛擬內(nèi)存管理
- 任務(wù)調(diào)度
- 進(jìn)程間通信和消息傳遞機(jī)制
- BSD
- UNIX進(jìn)程模型
- POSIX線程模型
- UNIX用戶與組
- 網(wǎng)絡(luò)協(xié)議棧
- 文件系統(tǒng)訪問
- 設(shè)備訪問
- libKern
- I/O Kit
Mach的獨(dú)特之處在于選擇了通過消息傳遞的方式實(shí)現(xiàn)對象與對象之間的通信。而其他架構(gòu)一個(gè)對象要訪問另一個(gè)對象需要通過一個(gè)大家都知道的接口,而Mach對象不能直接調(diào)用另一個(gè)對象,而是必須傳遞消息。
一條消息就像網(wǎng)絡(luò)包一樣,定義為透明的blob(binary larger object,二進(jìn)制大對象),通過固定的包頭進(jìn)行分裝
typedef struct
{
mach_msg_header_t header;
mach_msg_body_t body;
} mach_msg_base_t;
typedef struct
{
mach_msg_bits_t msgh_bits; // 消息頭標(biāo)志位
mach_msg_size_t msgh_size; // 大小
mach_port_t msgh_remote_port; // 目標(biāo)(發(fā)消息)或源(接消息)
mach_port_t msgh_local_port; // 源(發(fā)消息)或目標(biāo)(接消息)
mach_port_name_t msgh_voucher_port;
mach_msg_id_t msgh_id; // 唯一id
} mach_msg_header_t;
Mach消息的發(fā)送和接收都是通過同一個(gè)API函數(shù)mach_msg()進(jìn)行的。這個(gè)函數(shù)在用戶態(tài)和內(nèi)核態(tài)都有實(shí)現(xiàn)。為了實(shí)現(xiàn)消息的發(fā)送和接收,mach_msg()函數(shù)調(diào)用了一個(gè)Mach陷阱(trap)。Mach陷阱就是Mach中和系統(tǒng)調(diào)用等同的概念。在用戶態(tài)調(diào)用mach_msg_trap()會引發(fā)陷阱機(jī)制,切換到內(nèi)核態(tài),在內(nèi)核態(tài)中,內(nèi)核實(shí)現(xiàn)的mach_msg()會完成實(shí)際的工作。這個(gè)函數(shù)也將會在下面的源碼分析中遇到。
每一個(gè)BSD進(jìn)程都在底層關(guān)聯(lián)一個(gè)Mach任務(wù)對象,因?yàn)?code>Mach提供的都是非常底層的抽象,提供的API從設(shè)計(jì)上講很基礎(chǔ)且不完整,所以需要在這之上提供一個(gè)更高的層次以實(shí)現(xiàn)完整的功能。我們開發(fā)層遇到的進(jìn)程和線程就是BSD層對Mach的任務(wù)和線程的復(fù)雜包裝。
進(jìn)程填充的是線程,而線程是二進(jìn)制代碼的實(shí)際執(zhí)行單元。用戶態(tài)的線程始于對pthread_create的調(diào)用。這個(gè)函數(shù)的又由bsdthread_create系統(tǒng)調(diào)用完成,而bsdthread_create又其實(shí)是Mach中的thread_create的復(fù)雜包裝,說到底真正的線程創(chuàng)建還是有Mach層完成。
在UNIX中,進(jìn)程不能被創(chuàng)建出來,都是通過fork()系統(tǒng)調(diào)用復(fù)制出來的。復(fù)制出來的進(jìn)程都會被要加載的執(zhí)行程序覆蓋整個(gè)內(nèi)存空間。
接著,了解下常用的宏和常用的數(shù)據(jù)結(jié)構(gòu)體。
源碼中常見的宏
1. __builtin_expect
這個(gè)其實(shí)是個(gè)函數(shù),針對編譯器優(yōu)化的一個(gè)函數(shù),后面幾個(gè)宏是對這個(gè)函數(shù)的封裝,所以提前拎出來說一下。寫代碼中我們經(jīng)常會遇到條件判斷語句
if(今天是工作日) {
printf("好好上班");
}else{
printf("好好睡覺");
}
CPU讀取指令的時(shí)候并非一條一條的來讀,而是多條一起加載進(jìn)來,比如已經(jīng)加載了if(今天是工作日) printf(“好好上班”);的指令,這時(shí)候條件式如果為非,也就是非工作日,那么CPU繼續(xù)把printf(“好好睡覺”);這條指令加載進(jìn)來,這樣就造成了性能浪費(fèi)的現(xiàn)象。
__builtin_expect的第一個(gè)參數(shù)是實(shí)際值,第二個(gè)參數(shù)是預(yù)測值。使用這個(gè)目的是告訴編譯器if條件式是不是有更大的可能被滿足。
2. likely和unlikely
解開這個(gè)宏后其實(shí)是對__builtin_expect封裝,likely表示更大可能成立,unlikely表示更大可能不成立。
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
遇到這樣的,if(likely(a == 0))理解成if(a==0)即可,unlikely也是同樣的。
3. fastpath和slowpath
跟上面也是差不多的,fastpath表示更大可能成立,slowpath表示更大可能不成立
#define fastpath(x) ((typeof(x))__builtin_expect(_safe_cast_to_long(x), ~0l))
#define slowpath(x) ((typeof(x))__builtin_expect(_safe_cast_to_long(x), 0l))
這兩個(gè)理解起來跟likely和unlikely一樣,只需要關(guān)注里面的條件式是否滿足即可。
4. os_atomic_cmpxchg
其內(nèi)部就是atomic_compare_exchange_strong_explicit函數(shù),這個(gè)函數(shù)的作用是:第二個(gè)參數(shù)與第一個(gè)參數(shù)值比較,如果相等,第三個(gè)參數(shù)的值替換第一個(gè)參數(shù)的值。如果不相等,把第一個(gè)參數(shù)的值賦值到第二個(gè)參數(shù)上。
#define os_atomic_cmpxchg(p, e, v, m) \
({ _os_atomic_basetypeof(p) _r = (e); \
atomic_compare_exchange_strong_explicit(_os_atomic_c11_atomic(p), \
&_r, v, memory_order_##m, memory_order_relaxed); })
5. os_atomic_store2o
將第二個(gè)參數(shù),保存到第一個(gè)參數(shù)
#define os_atomic_store2o(p, f, v, m) os_atomic_store(&(p)->f, (v), m)
#define os_atomic_store(p, v, m) \
atomic_store_explicit(_os_atomic_c11_atomic(p), v, memory_order_##m)
6. os_atomic_inc_orig
將1保存到第一個(gè)參數(shù)中
#define os_atomic_inc_orig(p, m) os_atomic_add_orig((p), 1, m)
#define os_atomic_add_orig(p, v, m) _os_atomic_c11_op_orig((p), (v), m, add, +)
#define _os_atomic_c11_op_orig(p, v, m, o, op) \
atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), v, \
memory_order_##m)
數(shù)據(jù)結(jié)構(gòu)體
接著,了解一些常用數(shù)據(jù)結(jié)構(gòu)體。
1. dispatch_queue_t
typedef struct dispatch_queue_s *dispatch_queue_t;
??我們看下dispatch_queue_s怎么定義的。發(fā)現(xiàn)其內(nèi)部有個(gè)_DISPATCH_QUEUE_HEADER宏定義。
struct dispatch_queue_s {
_DISPATCH_QUEUE_HEADER(queue);
DISPATCH_QUEUE_CACHELINE_PADDING;
} DISPATCH_ATOMIC64_ALIGN;
??解開_DISPATCH_QUEUE_HEADER后發(fā)現(xiàn)又一個(gè)DISPATCH_OBJECT_HEADER宏定義,繼續(xù)拆解
#define _DISPATCH_QUEUE_HEADER(x) \
struct os_mpsc_queue_s _as_oq[0]; \
DISPATCH_OBJECT_HEADER(x); \
_OS_MPSC_QUEUE_FIELDS(dq, dq_state); \
uint32_t dq_side_suspend_cnt; \
dispatch_unfair_lock_s dq_sidelock; \
union { \
dispatch_queue_t dq_specific_q; \
struct dispatch_source_refs_s *ds_refs; \
struct dispatch_timer_source_refs_s *ds_timer_refs; \
struct dispatch_mach_recv_refs_s *dm_recv_refs; \
}; \
DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags, \
const uint16_t dq_width, \
const uint16_t __dq_opaque \
); \
DISPATCH_INTROSPECTION_QUEUE_HEADER
??還有一層宏_DISPATCH_OBJECT_HEADER
#define DISPATCH_OBJECT_HEADER(x) \
struct dispatch_object_s _as_do[0]; \
_DISPATCH_OBJECT_HEADER(x)
不熟悉##的作用的同學(xué),這里先說明下這個(gè)作用就拼接成字符串,比如x為group的話,下面就會拼接為dispatch_group這樣的。
#define _DISPATCH_OBJECT_HEADER(x) \
struct _os_object_s _as_os_obj[0]; \
OS_OBJECT_STRUCT_HEADER(dispatch_##x); \
struct dispatch_##x##_s *volatile do_next; \
struct dispatch_queue_s *do_targetq; \
void *do_ctxt; \
void *do_finalizer
來到OS_OBJECT_STRUCT_HEADER之后,我們需要注意一個(gè)成員變量,記住這個(gè)成員變量名字叫做do_vtable。再繼續(xù)拆解_OS_OBJECT_HEADER發(fā)現(xiàn)里面起就是一個(gè)isa指針和引用計(jì)數(shù)一些信息。
#define OS_OBJECT_STRUCT_HEADER(x) \
_OS_OBJECT_HEADER(\
const void *_objc_isa, \
do_ref_cnt, \
do_xref_cnt); \
// 注意這個(gè)成員變量,后面將任務(wù)Push到隊(duì)列就是通過這個(gè)變量
const struct x##_vtable_s *do_vtable
#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
isa; /* must be pointer-sized */ \
int volatile ref_cnt; \
int volatile xref_cnt
2. dispatch_continuation_t
說到這個(gè)結(jié)構(gòu)體,如果沒看過源碼的話,肯定對這個(gè)結(jié)構(gòu)體很陌生,因?yàn)閷ν獾腶pi里面沒有跟continuation有關(guān)的。所以這里先說下這個(gè)結(jié)構(gòu)體就是用來封裝block對象的,保存block的上下文環(huán)境和block執(zhí)行函數(shù)等。
typedef struct dispatch_continuation_s {
struct dispatch_object_s _as_do[0];
DISPATCH_CONTINUATION_HEADER(continuation);
} *dispatch_continuation_t;
看下里面的宏:DISPATCH_CONTINUATION_HEADER
#define DISPATCH_CONTINUATION_HEADER(x) \
union { \
const void *do_vtable; \
uintptr_t dc_flags; \
}; \
union { \
pthread_priority_t dc_priority; \
int dc_cache_cnt; \
uintptr_t dc_pad; \
}; \
struct dispatch_##x##_s *volatile do_next; \
struct voucher_s *dc_voucher; \
dispatch_function_t dc_func; \
void *dc_ctxt; \
void *dc_data; \
void *dc_other
3. dispatch_object_t
typedef union {
struct _os_object_s *_os_obj;
struct dispatch_object_s *_do;
struct dispatch_continuation_s *_dc;
struct dispatch_queue_s *_dq;
struct dispatch_queue_attr_s *_dqa;
struct dispatch_group_s *_dg;
struct dispatch_source_s *_ds;
struct dispatch_mach_s *_dm;
struct dispatch_mach_msg_s *_dmsg;
struct dispatch_source_attr_s *_dsa;
struct dispatch_semaphore_s *_dsema;
struct dispatch_data_s *_ddata;
struct dispatch_io_s *_dchannel;
struct dispatch_operation_s *_doperation;
struct dispatch_disk_s *_ddisk;
} dispatch_object_t DISPATCH_TRANSPARENT_UNION;
4. dispatch_function_t
dispatch_function_t只是一個(gè)函數(shù)指針
typedef void (*dispatch_function_t)(void *_Nullable);
至此,一些常用的宏和數(shù)據(jù)結(jié)構(gòu)體介紹完畢,接下來,我們真正的要一起閱讀GCD相關(guān)的源碼了。
創(chuàng)建隊(duì)列
首先我們先從創(chuàng)建隊(duì)列講起。我們已經(jīng)很熟悉,創(chuàng)建隊(duì)列的方法是調(diào)用dispatch_queue_create函數(shù)。
其內(nèi)部又調(diào)用了_dispatch_queue_create_with_target函數(shù)
DISPATCH_TARGET_QUEUE_DEFAULT這個(gè)宏其實(shí)就是null
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{ // attr一般我們都是傳DISPATCH_QUEUE_SERIAL、DISPATCH_QUEUE_CONCURRENT或者nil
// 而DISPATCH_QUEUE_SERIAL其實(shí)就是null
return _dispatch_queue_create_with_target(label, attr,
DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
_dispatch_queue_create_with_target函數(shù),這里會創(chuàng)建一個(gè)root隊(duì)列,并將自己新建的隊(duì)列綁定到所對應(yīng)的root隊(duì)列上。
static dispatch_queue_t _dispatch_queue_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{ // 根據(jù)上文代碼注釋里提到的,作者認(rèn)為調(diào)用者傳入DISPATCH_QUEUE_SERIAL和nil的幾率要大于傳DISPATCH_QUEUE_CONCURRENT。所以這里設(shè)置個(gè)默認(rèn)值。
// 這里怎么理解呢?只要看做if(!dqa)即可
if (!slowpath(dqa)) {
// _dispatch_get_default_queue_attr里面會將dqa的dqa_autorelease_frequency指定為DISPATCH_AUTORELEASE_FREQUENCY_INHERIT的,inactive也指定為false。這里就不展開了,只需要知道賦了哪些值。因?yàn)楹竺鏁玫健? dqa = _dispatch_get_default_queue_attr();
} else if (dqa->do_vtable != DISPATCH_VTABLE(queue_attr)) {
DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
}
// 取出優(yōu)先級
dispatch_qos_t qos = _dispatch_priority_qos(dqa->dqa_qos_and_relpri);
// overcommit單純從英文理解表示過量使用的意思,那這里這個(gè)overcommit就是一個(gè)標(biāo)識符,表示是不是就算負(fù)荷很高了,但還是得給我新開一個(gè)線程出來給我執(zhí)行任務(wù)。
_dispatch_queue_attr_overcommit_t overcommit = dqa->dqa_overcommit;
if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) {
if (tq->do_targetq) {
DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and "
"a non-global target queue");
}
}
// 如果overcommit沒有被指定
if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
// 所以對于overcommit,如果是串行的話默認(rèn)是開啟的,而并行是關(guān)閉的
overcommit = dqa->dqa_concurrent ?
_dispatch_queue_attr_overcommit_disabled :
_dispatch_queue_attr_overcommit_enabled;
}
// 之前說過初始化隊(duì)列默認(rèn)傳了DISPATCH_TARGET_QUEUE_DEFAULT,也就是null,所以進(jìn)入if語句。
if (!tq) {
// 獲取一個(gè)管理自己隊(duì)列的root隊(duì)列。
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled);
if (slowpath(!tq)) {
DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
}
}
// legacy默認(rèn)是true的
if (legacy) {
// 之前說過,默認(rèn)是會給dqa_autorelease_frequency指定為DISPATCH_AUTORELEASE_FREQUENCY_INHERIT,所以這個(gè)判斷式是成立的
if (dqa->dqa_inactive || dqa->dqa_autorelease_frequency) {
legacy = false;
}
}
// vtable變量很重要,之后會被賦值到之前說的dispatch_queue_t結(jié)構(gòu)體里的do_vtable變量上
const void *vtable;
dispatch_queue_flags_t dqf = 0;
// legacy變?yōu)閒alse了
if (legacy) {
vtable = DISPATCH_VTABLE(queue);
} else if (dqa->dqa_concurrent) {
// 如果創(chuàng)建隊(duì)列的時(shí)候傳了DISPATCH_QUEUE_CONCURRENT,就是走這里
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
// 如果創(chuàng)建線程沒有指定為并行隊(duì)列,無論你傳DISPATCH_QUEUE_SERIAL還是nil,都會創(chuàng)建一個(gè)串行隊(duì)列。
vtable = DISPATCH_VTABLE(queue_serial);
}
if (label) {
// 判斷傳進(jìn)來的字符串是否可變的,如果可變的copy成一份不可變的
const char *tmp = _dispatch_strdup_if_mutable(label);
if (tmp != label) {
dqf |= DQF_LABEL_NEEDS_FREE;
label = tmp;
}
}
// _dispatch_object_alloc里面就將vtable賦值給do_vtable變量上了。
dispatch_queue_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_queue_s) - DISPATCH_QUEUE_CACHELINE_PAD);
// 第三個(gè)參數(shù)根據(jù)是否并行隊(duì)列,如果不是則最多開一個(gè)線程,如果是則最多開0x1000 - 2個(gè)線程,這個(gè)數(shù)量很驚人了已經(jīng),換成十進(jìn)制就是(4096 - 2)個(gè)。
// dqa_inactive之前說串行是false的
// DISPATCH_QUEUE_ROLE_INNER 也是0,所以這里串行隊(duì)列的話dqa->dqa_state是0
_dispatch_queue_init(dq, dqf, dqa->dqa_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqa->dqa_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
dq->dq_label = label;
#if HAVE_PTHREAD_WORKQUEUE_QOS
dq->dq_priority = dqa->dqa_qos_and_relpri;
if (overcommit == _dispatch_queue_attr_overcommit_enabled) {
dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
}
#endif
_dispatch_retain(tq);
if (qos == QOS_CLASS_UNSPECIFIED) {
_dispatch_queue_priority_inherit_from_target(dq, tq);
}
if (!dqa->dqa_inactive) {
_dispatch_queue_inherit_wlh_from_target(dq, tq);
}
// 自定義的queue的目標(biāo)隊(duì)列是root隊(duì)列
dq->do_targetq = tq;
_dispatch_object_debug(dq, "%s", __func__);
return _dispatch_introspection_queue_create(dq);
}
這個(gè)函數(shù)里面還是有幾個(gè)重要的地方拆出來看下,首先是創(chuàng)建一個(gè)root隊(duì)列_dispatch_get_root_queue函數(shù)。取root隊(duì)列,一般是從一個(gè)裝有12個(gè)root隊(duì)列數(shù)組里面取。
static inline dispatch_queue_t
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
if (unlikely(qos == DISPATCH_QOS_UNSPECIFIED || qos > DISPATCH_QOS_MAX)) {
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
}
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}
看下這個(gè)_dispatch_root_queues數(shù)組。我們可以看到,每一個(gè)優(yōu)先級都有對應(yīng)的root隊(duì)列,每一個(gè)優(yōu)先級又分為是不是可以過載的隊(duì)列。
struct dispatch_queue_s _dispatch_root_queues[] = {
#define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
DISPATCH_GLOBAL_OBJECT_HEADER(queue_root), \
.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
.do_ctxt = &_dispatch_root_queue_contexts[ \
_DISPATCH_ROOT_QUEUE_IDX(n, flags)], \
.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
.dq_priority = _dispatch_priority_make(DISPATCH_QOS_##n, 0) | flags | \
DISPATCH_PRIORITY_FLAG_ROOTQUEUE | \
((flags & DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE) ? 0 : \
DISPATCH_QOS_##n << DISPATCH_PRIORITY_OVERRIDE_SHIFT), \
__VA_ARGS__ \
}
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
.dq_label = "com.apple.root.maintenance-qos",
.dq_serialnum = 4,
),
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.maintenance-qos.overcommit",
.dq_serialnum = 5,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
.dq_label = "com.apple.root.background-qos",
.dq_serialnum = 6,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.background-qos.overcommit",
.dq_serialnum = 7,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
.dq_label = "com.apple.root.utility-qos",
.dq_serialnum = 8,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.utility-qos.overcommit",
.dq_serialnum = 9,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE,
.dq_label = "com.apple.root.default-qos",
.dq_serialnum = 10,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.default-qos.overcommit",
.dq_serialnum = 11,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
.dq_label = "com.apple.root.user-initiated-qos",
.dq_serialnum = 12,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-initiated-qos.overcommit",
.dq_serialnum = 13,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
.dq_label = "com.apple.root.user-interactive-qos",
.dq_serialnum = 14,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-interactive-qos.overcommit",
.dq_serialnum = 15,
),
};
其中DISPATCH_GLOBAL_OBJECT_HEADER(queue_root),解析到最后是OSdispatch##name##_class這樣的這樣的,對應(yīng)的實(shí)例對象是如下代碼,指定了root隊(duì)列各個(gè)操作對應(yīng)的函數(shù)。
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_root, queue,
.do_type = DISPATCH_QUEUE_GLOBAL_ROOT_TYPE,
.do_kind = "global-queue",
.do_dispose = _dispatch_pthread_root_queue_dispose,
.do_push = _dispatch_root_queue_push,
.do_invoke = NULL,
.do_wakeup = _dispatch_root_queue_wakeup,
.do_debug = dispatch_queue_debug,
);
其次看下DISPATCH_VTABLE這個(gè)宏,這個(gè)宏很重要。最后解封也是&OSdispatch##name##_class這樣的。其實(shí)就是取dispatch_object_t對象。
??如下代碼,這里再舉個(gè)VTABLE的串行對象,里面有各個(gè)狀態(tài)該執(zhí)行的函數(shù):銷毀函、掛起、恢復(fù)、push等函數(shù)都是在這里指定的。所以這里的do_push我們需要特別留意,后面push block任務(wù)到隊(duì)列,就是通過調(diào)用do_push。
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial, queue,
.do_type = DISPATCH_QUEUE_SERIAL_TYPE,
.do_kind = "serial-queue",
.do_dispose = _dispatch_queue_dispose,
.do_suspend = _dispatch_queue_suspend,
.do_resume = _dispatch_queue_resume,
.do_finalize_activation = _dispatch_queue_finalize_activation,
.do_push = _dispatch_queue_push,
.do_invoke = _dispatch_queue_invoke,
.do_wakeup = _dispatch_queue_wakeup,
.do_debug = dispatch_queue_debug,
.do_set_targetq = _dispatch_queue_set_target_queue,
);
??繼續(xù)看下_dispatch_object_alloc和_dispatch_queue_init兩個(gè)函數(shù),首先看下_dispatch_object_alloc函數(shù)
void * _dispatch_object_alloc(const void *vtable, size_t size)
{
// OS_OBJECT_HAVE_OBJC1為1的滿足式是:
// #if TARGET_OS_MAC && !TARGET_OS_SIMULATOR && defined(__i386__)
// 所以對于iOS并不滿足
#if OS_OBJECT_HAVE_OBJC1
const struct dispatch_object_vtable_s *_vtable = vtable;
dispatch_object_t dou;
dou._os_obj = _os_object_alloc_realized(_vtable->_os_obj_objc_isa, size);
dou._do->do_vtable = vtable;
return dou._do;
#else
return _os_object_alloc_realized(vtable, size);
#endif
}
inline _os_object_t _os_object_alloc_realized(const void *cls, size_t size)
{
_os_object_t obj;
dispatch_assert(size >= sizeof(struct _os_object_s));
while (!fastpath(obj = calloc(1u, size))) {
_dispatch_temporary_resource_shortage();
}
obj->os_obj_isa = cls;
return obj;
}
void _dispatch_temporary_resource_shortage(void)
{
sleep(1);
asm(""); // prevent tailcall
}
??再看下_dispatch_queue_init函數(shù),這里也就是做些初始化工作了
static inline void _dispatch_queue_init(dispatch_queue_t dq, dispatch_queue_flags_t dqf,
uint16_t width, uint64_t initial_state_bits)
{
uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
DISPATCH_QUEUE_INACTIVE)) == 0);
if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
dq_state |= DISPATCH_QUEUE_INACTIVE + DISPATCH_QUEUE_NEEDS_ACTIVATION;
dq_state |= DLOCK_OWNER_MASK;
dq->do_ref_cnt += 2;
}
dq_state |= (initial_state_bits & DISPATCH_QUEUE_ROLE_MASK);
// 指向DISPATCH_OBJECT_LISTLESS是優(yōu)化編譯器的作用。只是為了生成更好的指令讓CPU更好的編碼
dq->do_next = (struct dispatch_queue_s *)DISPATCH_OBJECT_LISTLESS;
dqf |= DQF_WIDTH(width);
// dqf 保存進(jìn) dq->dq_atomic_flags
os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
dq->dq_state = dq_state;
dq->dq_serialnum =
os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);
}
??最后是_dispatch_introspection_queue_create函數(shù),一個(gè)內(nèi)省函數(shù)。
dispatch_queue_t _dispatch_introspection_queue_create(dispatch_queue_t dq)
{
TAILQ_INIT(&dq->diq_order_top_head);
TAILQ_INIT(&dq->diq_order_bottom_head);
_dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);
TAILQ_INSERT_TAIL(&_dispatch_introspection.queues, dq, diq_list);
_dispatch_unfair_lock_unlock(&_dispatch_introspection.queues_lock);
DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
_dispatch_introspection_queue_create_hook(dq);
}
return dq;
}
??至此,一個(gè)隊(duì)列的創(chuàng)建過程我們大致了解了。大致可以分為這么幾點(diǎn)
設(shè)置隊(duì)列優(yōu)先級
默認(rèn)創(chuàng)建的是一個(gè)串行隊(duì)列
設(shè)置隊(duì)列掛載的根隊(duì)列。優(yōu)先級不同根隊(duì)列也不同
實(shí)例化vtable對象,這個(gè)對象給不同隊(duì)列指定了push、wakeup等函數(shù)。
0x04 dispatch_sync
dispatch_sync直接調(diào)用的是dispatch_sync_f
void dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
// 很大可能不會走if分支,看做if(_dispatch_block_has_private_data(work))
if (unlikely(_dispatch_block_has_private_data(work))) {
return _dispatch_sync_block_with_private_data(dq, work, 0);
}
dispatch_sync_f(dq, work, _dispatch_Block_invoke(work));
}
void
dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
{
// 串行隊(duì)列會走到這個(gè)if分支
if (likely(dq->dq_width == 1)) {
return dispatch_barrier_sync_f(dq, ctxt, func);
}
// 全局獲取的并行隊(duì)列或者綁定的是非調(diào)度線程的隊(duì)列會走進(jìn)這個(gè)if分支
if (unlikely(!_dispatch_queue_try_reserve_sync_width(dq))) {
return _dispatch_sync_f_slow(dq, ctxt, func, 0);
}
_dispatch_introspection_sync_begin(dq);
if (unlikely(dq->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dq, ctxt, func, 0);
}
// 自定義并行隊(duì)列會來到這個(gè)函數(shù)
_dispatch_sync_invoke_and_complete(dq, ctxt, func);
}
先說第一種情況,串行隊(duì)列。
void dispatch_barrier_sync_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func)
{
dispatch_tid tid = _dispatch_tid_self();
// 隊(duì)列綁定的是非調(diào)度線程就會走這里
if (unlikely(!_dispatch_queue_try_acquire_barrier_sync(dq, tid))) {
return _dispatch_sync_f_slow(dq, ctxt, func, DISPATCH_OBJ_BARRIER_BIT);
}
_dispatch_introspection_sync_begin(dq);
if (unlikely(dq->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dq, ctxt, func, DISPATCH_OBJ_BARRIER_BIT);
}
// 一般會走到這里
_dispatch_queue_barrier_sync_invoke_and_complete(dq, ctxt, func);
}
static void _dispatch_queue_barrier_sync_invoke_and_complete(dispatch_queue_t dq,
void *ctxt, dispatch_function_t func)
{
// 首先會執(zhí)行這個(gè)函數(shù)
_dispatch_sync_function_invoke_inline(dq, ctxt, func);
// 如果后面還有別的任務(wù)
if (unlikely(dq->dq_items_tail || dq->dq_width > 1)) {
// 內(nèi)部其實(shí)就是喚醒隊(duì)列
return _dispatch_queue_barrier_complete(dq, 0, 0);
}
const uint64_t fail_unlock_mask = DISPATCH_QUEUE_SUSPEND_BITS_MASK |
DISPATCH_QUEUE_ENQUEUED | DISPATCH_QUEUE_DIRTY |
DISPATCH_QUEUE_RECEIVED_OVERRIDE | DISPATCH_QUEUE_SYNC_TRANSFER |
DISPATCH_QUEUE_RECEIVED_SYNC_WAIT;
uint64_t old_state, new_state;
// 原子鎖。檢查dq->dq_state與old_state是否相等,如果相等把new_state賦值給dq->dq_state,如果不相等,把dq_state賦值給old_state。
// 串行隊(duì)列走到這里,dq->dq_state與old_state是相等的,會把new_state也就是閉包里的賦值的值給dq->dq_state
os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, release, {
new_state = old_state - DISPATCH_QUEUE_SERIAL_DRAIN_OWNED;
new_state &= ~DISPATCH_QUEUE_DRAIN_UNLOCK_MASK;
new_state &= ~DISPATCH_QUEUE_MAX_QOS_MASK;
if (unlikely(old_state & fail_unlock_mask)) {
os_atomic_rmw_loop_give_up({
return _dispatch_queue_barrier_complete(dq, 0, 0);
});
}
});
if (_dq_state_is_base_wlh(old_state)) {
_dispatch_event_loop_assert_not_owned((dispatch_wlh_t)dq);
}
}
static inline void _dispatch_sync_function_invoke_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func)
{
// 保護(hù)現(xiàn)場 -> 調(diào)用函數(shù) -> 恢復(fù)現(xiàn)場
dispatch_thread_frame_s dtf;
_dispatch_thread_frame_push(&dtf, dq);
_dispatch_client_callout(ctxt, func);
_dispatch_perfmon_workitem_inc();
_dispatch_thread_frame_pop(&dtf);
}
??然后另一種情況,自定義并行隊(duì)列會走_(dá)dispatch_sync_invoke_and_complete函數(shù)。
static void _dispatch_sync_invoke_and_complete(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func)
{
_dispatch_sync_function_invoke_inline(dq, ctxt, func);
// 將自定義隊(duì)列加入到root隊(duì)列里去
// dispatch_async也會調(diào)用此方法,之前我們初始化的時(shí)候會綁定一個(gè)root隊(duì)列,這里就將我們新建的隊(duì)列交給root隊(duì)列進(jìn)行管理
_dispatch_queue_non_barrier_complete(dq);
}
static inline void _dispatch_sync_function_invoke_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func)
{
dispatch_thread_frame_s dtf;
_dispatch_thread_frame_push(&dtf, dq);
// 執(zhí)行任務(wù)
_dispatch_client_callout(ctxt, func);
_dispatch_perfmon_workitem_inc();
_dispatch_thread_frame_pop(&dtf);
}
## dispatch_async
??內(nèi)部就是兩個(gè)函數(shù)_dispatch_continuation_init和_dispatch_continuation_async
void dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
// 設(shè)置標(biāo)識位
uintptr_t dc_flags = DISPATCH_OBJ_CONSUME_BIT;
_dispatch_continuation_init(dc, dq, work, 0, 0, dc_flags);
_dispatch_continuation_async(dq, dc);
}
??_dispatch_continuation_init函數(shù)只是一個(gè)初始化,主要就是保存Block上下文,指定block的執(zhí)行函數(shù)
static inline void _dispatch_continuation_init(dispatch_continuation_t dc,
dispatch_queue_class_t dqu, dispatch_block_t work,
pthread_priority_t pp, dispatch_block_flags_t flags, uintptr_t dc_flags)
{
dc->dc_flags = dc_flags | DISPATCH_OBJ_BLOCK_BIT;
// block對象賦值到dc_ctxt
dc->dc_ctxt = _dispatch_Block_copy(work);
// 設(shè)置默認(rèn)任務(wù)優(yōu)先級
_dispatch_continuation_priority_set(dc, pp, flags);
// 大多數(shù)情況不會走這個(gè)分支
if (unlikely(_dispatch_block_has_private_data(work))) {
return _dispatch_continuation_init_slow(dc, dqu, flags);
}
// 這個(gè)標(biāo)識位多眼熟,就是前面入口賦值的,沒的跑了,指定執(zhí)行函數(shù)就是_dispatch_call_block_and_release了
if (dc_flags & DISPATCH_OBJ_CONSUME_BIT) {
dc->dc_func = _dispatch_call_block_and_release;
} else {
dc->dc_func = _dispatch_Block_invoke(work);
}
_dispatch_continuation_voucher_set(dc, dqu, flags);
}
??_dispatch_call_block_and_release這個(gè)函數(shù)就是直接執(zhí)行block了,所以dc->dc_func被調(diào)用的話就block會被直接執(zhí)行了。
void _dispatch_call_block_and_release(void *block)
{
void (^b)(void) = block;
b();
Block_release(b);
}
??上面的初始化過程就是這樣,接著看下_dispatch_continuation_async函數(shù)
void _dispatch_continuation_async(dispatch_queue_t dq, dispatch_continuation_t dc)
{
// 看看是不是barrier類型的block
_dispatch_continuation_async2(dq, dc,
dc->dc_flags & DISPATCH_OBJ_BARRIER_BIT);
}
static inline void _dispatch_continuation_async2(dispatch_queue_t dq, dispatch_continuation_t dc,
bool barrier)
{
// 如果是用barrier插進(jìn)來的任務(wù)或者是串行隊(duì)列,直接將任務(wù)加入到隊(duì)列
// #define DISPATCH_QUEUE_USES_REDIRECTION(width) \
// ({ uint16_t _width = (width); \
// _width > 1 && _width < DISPATCH_QUEUE_WIDTH_POOL; })
if (fastpath(barrier || !DISPATCH_QUEUE_USES_REDIRECTION(dq->dq_width))) {
return _dispatch_continuation_push(dq, dc);
}
return _dispatch_async_f2(dq, dc);
}
// 可以先看下如果是barrier任務(wù),直接調(diào)用_dispatch_continuation_push函數(shù)
static void _dispatch_continuation_push(dispatch_queue_t dq, dispatch_continuation_t dc)
{
dx_push(dq, dc, _dispatch_continuation_override_qos(dq, dc));
}
// _dispatch_continuation_async2函數(shù)里面調(diào)用_dispatch_async_f2函數(shù)
static void
_dispatch_async_f2(dispatch_queue_t dq, dispatch_continuation_t dc)
{
// 如果還有任務(wù),slowpath表示很大可能隊(duì)尾是沒有任務(wù)的。
// 實(shí)際開發(fā)中也的確如此,一般情況下我們不會dispatch_async之后又馬上跟著一個(gè)dispatch_async
if (slowpath(dq->dq_items_tail)) {
return _dispatch_continuation_push(dq, dc);
}
if (slowpath(!_dispatch_queue_try_acquire_async(dq))) {
return _dispatch_continuation_push(dq, dc);
}
// 一般會直接來到這里,_dispatch_continuation_override_qos函數(shù)里面主要做的是判斷dq有沒有設(shè)置的優(yōu)先級,如果沒有就用block對象的優(yōu)先級,如果有就用自己的
return _dispatch_async_f_redirect(dq, dc,
_dispatch_continuation_override_qos(dq, dc));
}
static void _dispatch_async_f_redirect(dispatch_queue_t dq,
dispatch_object_t dou, dispatch_qos_t qos)
{
// 這里會走進(jìn)if的語句,因?yàn)開dispatch_object_is_redirection內(nèi)部的dx_type(dou._do) == type條件為否
if (!slowpath(_dispatch_object_is_redirection(dou))) {
dou._dc = _dispatch_async_redirect_wrap(dq, dou);
}
// dq換成所綁定的root隊(duì)列
dq = dq->do_targetq;
// 基本不會走里面的循環(huán),主要做的就是找到根root隊(duì)列
while (slowpath(DISPATCH_QUEUE_USES_REDIRECTION(dq->dq_width))) {
if (!fastpath(_dispatch_queue_try_acquire_async(dq))) {
break;
}
if (!dou._dc->dc_ctxt) {
dou._dc->dc_ctxt = (void *)
(uintptr_t)_dispatch_queue_autorelease_frequency(dq);
}
dq = dq->do_targetq;
}
// 把裝有block信息的結(jié)構(gòu)體裝進(jìn)所在隊(duì)列對應(yīng)的root_queue里面
dx_push(dq, dou, qos);
}
// dx_push是個(gè)宏定義,這里做的就是將任務(wù)push到任務(wù)隊(duì)列,我們看到這里,就知道dx_push就是調(diào)用對象的do_push。
#define dx_push(x, y, z) dx_vtable(x)->do_push(x, y, z)
#define dx_vtable(x) (&(x)->do_vtable->_os_obj_vtable)
??_dispatch_async_f_redirect函數(shù)里先看這句dou._dc = _dispatch_async_redirect_wrap(dq, dou);
static inline dispatch_continuation_t _dispatch_async_redirect_wrap(dispatch_queue_t dq, dispatch_object_t dou)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
dou._do->do_next = NULL;
// 所以dispatch_async推進(jìn)的任務(wù)的do_vtable成員變量是有值的
dc->do_vtable = DC_VTABLE(ASYNC_REDIRECT);
dc->dc_func = NULL;
dc->dc_ctxt = (void *)(uintptr_t)_dispatch_queue_autorelease_frequency(dq);
// 所屬隊(duì)列被裝進(jìn)dou._dc->dc_data里面了
dc->dc_data = dq;
dc->dc_other = dou._do;
dc->dc_voucher = DISPATCH_NO_VOUCHER;
dc->dc_priority = DISPATCH_NO_PRIORITY;
_dispatch_retain(dq); // released in _dispatch_async_redirect_invoke
return dc;
}
// dc->do_vtable = DC_VTABLE(ASYNC_REDIRECT); 就是下面指定redirect的invoke函數(shù)是_dispatch_async_redirect_invoke,后面任務(wù)被執(zhí)行就是通過這個(gè)函數(shù)
const struct dispatch_continuation_vtable_s _dispatch_continuation_vtables[] = {
DC_VTABLE_ENTRY(ASYNC_REDIRECT,
.do_kind = "dc-redirect",
.do_invoke = _dispatch_async_redirect_invoke),
#if HAVE_MACH
DC_VTABLE_ENTRY(MACH_SEND_BARRRIER_DRAIN,
.do_kind = "dc-mach-send-drain",
.do_invoke = _dispatch_mach_send_barrier_drain_invoke),
DC_VTABLE_ENTRY(MACH_SEND_BARRIER,
.do_kind = "dc-mach-send-barrier",
.do_invoke = _dispatch_mach_barrier_invoke),
DC_VTABLE_ENTRY(MACH_RECV_BARRIER,
.do_kind = "dc-mach-recv-barrier",
.do_invoke = _dispatch_mach_barrier_invoke),
DC_VTABLE_ENTRY(MACH_ASYNC_REPLY,
.do_kind = "dc-mach-async-reply",
.do_invoke = _dispatch_mach_msg_async_reply_invoke),
#endif
#if HAVE_PTHREAD_WORKQUEUE_QOS
DC_VTABLE_ENTRY(OVERRIDE_STEALING,
.do_kind = "dc-override-stealing",
.do_invoke = _dispatch_queue_override_invoke),
// 留意這個(gè),后面也會被用到
DC_VTABLE_ENTRY(OVERRIDE_OWNING,
.do_kind = "dc-override-owning",
.do_invoke = _dispatch_queue_override_invoke),
#endif
};
??再看dx_push(dq, dou, qos);這句,其實(shí)就是調(diào)用_dispatch_root_queue_push函數(shù)
void _dispatch_root_queue_push(dispatch_queue_t rq, dispatch_object_t dou,
dispatch_qos_t qos)
{
// 一般情況下,無論自定義還是非自定義都會走進(jìn)這個(gè)條件式(比如:dispatch_get_global_queue)
// 里面主要對比的是qos與root隊(duì)列的qos是否一致?;旧隙疾灰恢碌?,如果不一致走進(jìn)這個(gè)if語句
if (_dispatch_root_queue_push_needs_override(rq, qos)) {
return _dispatch_root_queue_push_override(rq, dou, qos);
}
_dispatch_root_queue_push_inline(rq, dou, dou, 1);
}
static void _dispatch_root_queue_push_override(dispatch_queue_t orig_rq,
dispatch_object_t dou, dispatch_qos_t qos)
{
bool overcommit = orig_rq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
dispatch_queue_t rq = _dispatch_get_root_queue(qos, overcommit);
dispatch_continuation_t dc = dou._dc;
// 這個(gè)_dispatch_object_is_redirection函數(shù)其實(shí)就是return _dispatch_object_has_type(dou,DISPATCH_CONTINUATION_TYPE(ASYNC_REDIRECT));
// 所以自定義隊(duì)列會走這個(gè)if語句,如果是dispatch_get_global_queue不會走if語句
if (_dispatch_object_is_redirection(dc)) {
dc->dc_func = (void *)orig_rq;
} else {
// dispatch_get_global_queue來到這里
dc = _dispatch_continuation_alloc();
// 相當(dāng)于是下面的,也就是指定了執(zhí)行函數(shù)為_dispatch_queue_override_invoke,所以有別于自定義隊(duì)列的invoke函數(shù)。
// DC_VTABLE_ENTRY(OVERRIDE_OWNING,
// .do_kind = "dc-override-owning",
// .do_invoke = _dispatch_queue_override_invoke),
dc->do_vtable = DC_VTABLE(OVERRIDE_OWNING);
_dispatch_trace_continuation_push(orig_rq, dou);
dc->dc_ctxt = dc;
dc->dc_other = orig_rq;
dc->dc_data = dou._do;
dc->dc_priority = DISPATCH_NO_PRIORITY;
dc->dc_voucher = DISPATCH_NO_VOUCHER;
}
_dispatch_root_queue_push_inline(rq, dc, dc, 1);
}
static inline void _dispatch_root_queue_push_inline(dispatch_queue_t dq, dispatch_object_t _head,
dispatch_object_t _tail, int n)
{
struct dispatch_object_s *head = _head._do, *tail = _tail._do;
// 把任務(wù)裝進(jìn)隊(duì)列,大多數(shù)不走進(jìn)if語句。但是第一個(gè)任務(wù)進(jìn)來之前還是滿足這個(gè)條件式的,會進(jìn)入這個(gè)條件語句去激活隊(duì)列來執(zhí)行里面的任務(wù),后面再加入的任務(wù)因?yàn)殛?duì)列被激活了,所以也就不太需要再進(jìn)入這個(gè)隊(duì)列了,所以相對來說激活隊(duì)列只要一次,所以作者認(rèn)為大多數(shù)情況下不需要走進(jìn)這個(gè)條件語句
if (unlikely(_dispatch_queue_push_update_tail_list(dq, head, tail))) {
// 保存隊(duì)列頭
_dispatch_queue_push_update_head(dq, head);
return _dispatch_global_queue_poke(dq, n, 0);
}
}
至此,我們可以看到,我們裝入到自定義的任務(wù)都被扔到其掛靠的root隊(duì)列里去了,所以我們我們自己創(chuàng)建的隊(duì)列只是一個(gè)代理人身份,真正的管理人是其對應(yīng)的root隊(duì)列,但同時(shí)這個(gè)隊(duì)列也是被管理的。
繼續(xù)看_dispatch_global_queue_poke函數(shù)
void
_dispatch_global_queue_poke(dispatch_queue_t dq, int n, int floor)
{
return _dispatch_global_queue_poke_slow(dq, n, floor);
}
??繼續(xù)看_dispatch_global_queue_poke函數(shù)調(diào)用了_dispatch_global_queue_poke_slow函數(shù),這里也很關(guān)鍵了,里面執(zhí)行_pthread_workqueue_addthreads函數(shù),把任務(wù)交給內(nèi)核分發(fā)處理
_dispatch_global_queue_poke_slow(dispatch_queue_t dq, int n, int floor)
{
dispatch_root_queue_context_t qc = dq->do_ctxt;
int remaining = n;
int r = ENOSYS;
_dispatch_root_queues_init();
_dispatch_debug_root_queue(dq, __func__);
if (qc->dgq_kworkqueue != (void*)(~0ul))
{
r = _pthread_workqueue_addthreads(remaining,
_dispatch_priority_to_pp(dq->dq_priority));
(void)dispatch_assume_zero(r);
return;
}
}
int
_pthread_workqueue_addthreads(int numthreads, pthread_priority_t priority)
{
int res = 0;
if (__libdispatch_workerfunction == NULL) {
return EPERM;
}
if ((__pthread_supported_features & PTHREAD_FEATURE_FINEPRIO) == 0) {
return ENOTSUP;
}
res = __workq_kernreturn(WQOPS_QUEUE_REQTHREADS, NULL, numthreads, (int)priority);
if (res == -1) {
res = errno;
}
return res;
}
那么,加入到根隊(duì)列的任務(wù)是怎么被運(yùn)行起來的?在此之前,我們先模擬一下在GCD內(nèi)部把程序搞掛掉,這樣我們就可以追溯下調(diào)用棧關(guān)系。
(
0 CoreFoundation 0x00000001093fe12b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000108a92f41 objc_exception_throw + 48
2 CoreFoundation 0x000000010943e0cc _CFThrowFormattedException + 194
3 CoreFoundation 0x000000010930c23d -[__NSPlaceholderArray initWithObjects:count:] + 237
4 CoreFoundation 0x0000000109312e34 +[NSArray arrayWithObjects:count:] + 52
5 HotPatch 0x000000010769df77 __29-[ViewController viewDidLoad]_block_invoke + 87
6 libdispatch.dylib 0x000000010c0a62f7 _dispatch_call_block_and_release + 12
7 libdispatch.dylib 0x000000010c0a733d _dispatch_client_callout + 8
8 libdispatch.dylib 0x000000010c0ad754 _dispatch_continuation_pop + 967
9 libdispatch.dylib 0x000000010c0abb85 _dispatch_async_redirect_invoke + 780
10 libdispatch.dylib 0x000000010c0b3102 _dispatch_root_queue_drain + 772
11 libdispatch.dylib 0x000000010c0b2da0 _dispatch_worker_thread3 + 132
12 libsystem_pthread.dylib 0x000000010c5f95a2 _pthread_wqthread + 1299
13 libsystem_pthread.dylib 0x000000010c5f907d
start_wqthread + 13
)
很明顯,我們已經(jīng)看到加入到隊(duì)列的任務(wù)的調(diào)用關(guān)系是:
start_wqthread -> _pthread_wqthread -> _dispatch_worker_thread3 -> _dispatch_root_queue_drain -> _dispatch_async_redirect_invoke -> _dispatch_continuation_pop -> _dispatch_client_callout -> _dispatch_call_block_and_release
只看調(diào)用關(guān)系也不知道里面做了什么,所以還是上代碼
// 根據(jù)優(yōu)先級取出相應(yīng)的root隊(duì)列,再調(diào)用_dispatch_worker_thread4函數(shù)
static void _dispatch_worker_thread3(pthread_priority_t pp)
{
bool overcommit = pp & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
dispatch_queue_t dq;
pp &= _PTHREAD_PRIORITY_OVERCOMMIT_FLAG | ~_PTHREAD_PRIORITY_FLAGS_MASK;
_dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp);
dq = _dispatch_get_root_queue(_dispatch_qos_from_pp(pp), overcommit);
return _dispatch_worker_thread4(dq);
}
// 開始調(diào)用_dispatch_root_queue_drain函數(shù),取出任務(wù)
static void _dispatch_worker_thread4(void *context)
{
dispatch_queue_t dq = context;
dispatch_root_queue_context_t qc = dq->do_ctxt;
_dispatch_introspection_thread_add();
int pending = os_atomic_dec2o(qc, dgq_pending, relaxed);
dispatch_assert(pending >= 0);
_dispatch_root_queue_drain(dq, _dispatch_get_priority());
_dispatch_voucher_debug("root queue clear", NULL);
_dispatch_reset_voucher(NULL, DISPATCH_THREAD_PARK);
}
// 循環(huán)取出任務(wù)
static void _dispatch_root_queue_drain(dispatch_queue_t dq, pthread_priority_t pp)
{
_dispatch_queue_set_current(dq);
dispatch_priority_t pri = dq->dq_priority;
if (!pri) pri = _dispatch_priority_from_pp(pp);
dispatch_priority_t old_dbp = _dispatch_set_basepri(pri);
_dispatch_adopt_wlh_anon();
struct dispatch_object_s *item;
bool reset = false;
dispatch_invoke_context_s dic = { };
dispatch_invoke_flags_t flags = DISPATCH_INVOKE_WORKER_DRAIN |
DISPATCH_INVOKE_REDIRECTING_DRAIN;
_dispatch_queue_drain_init_narrowing_check_deadline(&dic, pri);
_dispatch_perfmon_start();
while ((item = fastpath(_dispatch_root_queue_drain_one(dq)))) {
if (reset) _dispatch_wqthread_override_reset();
_dispatch_continuation_pop_inline(item, &dic, flags, dq);
reset = _dispatch_reset_basepri_override();
if (unlikely(_dispatch_queue_drain_should_narrow(&dic))) {
break;
}
}
// overcommit or not. worker thread
if (pri & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG) {
_dispatch_perfmon_end(perfmon_thread_worker_oc);
} else {
_dispatch_perfmon_end(perfmon_thread_worker_non_oc);
}
_dispatch_reset_wlh();
_dispatch_reset_basepri(old_dbp);
_dispatch_reset_basepri_override();
_dispatch_queue_set_current(NULL);
}
// 這個(gè)函數(shù)的作用就是調(diào)度出任務(wù)的執(zhí)行函數(shù)
static inline void _dispatch_continuation_pop_inline(dispatch_object_t dou,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags,
dispatch_queue_t dq)
{
dispatch_pthread_root_queue_observer_hooks_t observer_hooks =
_dispatch_get_pthread_root_queue_observer_hooks();
if (observer_hooks) observer_hooks->queue_will_execute(dq);
_dispatch_trace_continuation_pop(dq, dou);
flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
// 之前說過dispatch_async是有do_vtable成員變量的,所以會走進(jìn)這個(gè)if分支,又invoke方法指定為_dispatch_async_redirect_invoke,所以執(zhí)行該函數(shù)
// 相同的,如果是dispatch_get_global_queue也會走這個(gè)分支,執(zhí)行_dispatch_queue_override_invoke方法,這個(gè)之前也說過了
if (_dispatch_object_has_vtable(dou)) {
dx_invoke(dou._do, dic, flags);
} else {
_dispatch_continuation_invoke_inline(dou, DISPATCH_NO_VOUCHER, flags);
}
if (observer_hooks) observer_hooks->queue_did_execute(dq);
}
// 繼續(xù)按自定義隊(duì)列的步驟走
void _dispatch_async_redirect_invoke(dispatch_continuation_t dc,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags)
{
dispatch_thread_frame_s dtf;
struct dispatch_continuation_s *other_dc = dc->dc_other;
dispatch_invoke_flags_t ctxt_flags = (dispatch_invoke_flags_t)dc->dc_ctxt;
dispatch_queue_t assumed_rq = (dispatch_queue_t)dc->dc_func;
dispatch_queue_t dq = dc->dc_data, rq, old_dq;
dispatch_priority_t old_dbp;
if (ctxt_flags) {
flags &= ~_DISPATCH_INVOKE_AUTORELEASE_MASK;
flags |= ctxt_flags;
}
old_dq = _dispatch_get_current_queue();
if (assumed_rq) {
old_dbp = _dispatch_root_queue_identity_assume(assumed_rq);
_dispatch_set_basepri(dq->dq_priority);
} else {
old_dbp = _dispatch_set_basepri(dq->dq_priority);
}
_dispatch_thread_frame_push(&dtf, dq);
// _dispatch_continuation_pop_forwarded里面就是執(zhí)行_dispatch_continuation_pop函數(shù)
_dispatch_continuation_pop_forwarded(dc, DISPATCH_NO_VOUCHER,
DISPATCH_OBJ_CONSUME_BIT, {
_dispatch_continuation_pop(other_dc, dic, flags, dq);
});
_dispatch_thread_frame_pop(&dtf);
if (assumed_rq) _dispatch_queue_set_current(old_dq);
_dispatch_reset_basepri(old_dbp);
rq = dq->do_targetq;
while (slowpath(rq->do_targetq) && rq != old_dq) {
_dispatch_queue_non_barrier_complete(rq);
rq = rq->do_targetq;
}
_dispatch_queue_non_barrier_complete(dq);
_dispatch_release_tailcall(dq);
}
// 順便說下,如果按照的是dispatch_get_global_queue會執(zhí)行_dispatch_queue_override_invoke函數(shù)
void _dispatch_queue_override_invoke(dispatch_continuation_t dc,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags)
{
dispatch_queue_t old_rq = _dispatch_queue_get_current();
dispatch_queue_t assumed_rq = dc->dc_other;
dispatch_priority_t old_dp;
voucher_t ov = DISPATCH_NO_VOUCHER;
dispatch_object_t dou;
dou._do = dc->dc_data;
old_dp = _dispatch_root_queue_identity_assume(assumed_rq);
if (dc_type(dc) == DISPATCH_CONTINUATION_TYPE(OVERRIDE_STEALING)) {
flags |= DISPATCH_INVOKE_STEALING;
} else {
// balance the fake continuation push in
// _dispatch_root_queue_push_override
_dispatch_trace_continuation_pop(assumed_rq, dou._do);
}
// 同樣調(diào)用_dispatch_continuation_pop函數(shù)
_dispatch_continuation_pop_forwarded(dc, ov, DISPATCH_OBJ_CONSUME_BIT, {
if (_dispatch_object_has_vtable(dou._do)) {
dx_invoke(dou._do, dic, flags);
} else {
_dispatch_continuation_invoke_inline(dou, ov, flags);
}
});
_dispatch_reset_basepri(old_dp);
_dispatch_queue_set_current(old_rq);
}
// 回歸正題,無論是自定義的隊(duì)列還是獲取系統(tǒng)的,最終都會調(diào)用這個(gè)函數(shù)
void _dispatch_continuation_pop(dispatch_object_t dou, dispatch_invoke_context_t dic,
dispatch_invoke_flags_t flags, dispatch_queue_t dq)
{
_dispatch_continuation_pop_inline(dou, dic, flags, dq);
}
static inline void _dispatch_continuation_pop_inline(dispatch_object_t dou,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags,
dispatch_queue_t dq)
{
dispatch_pthread_root_queue_observer_hooks_t observer_hooks =
_dispatch_get_pthread_root_queue_observer_hooks();
if (observer_hooks) observer_hooks->queue_will_execute(dq);
_dispatch_trace_continuation_pop(dq, dou);
flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
if (_dispatch_object_has_vtable(dou)) {
dx_invoke(dou._do, dic, flags);
} else {
_dispatch_continuation_invoke_inline(dou, DISPATCH_NO_VOUCHER, flags);
}
if (observer_hooks) observer_hooks->queue_did_execute(dq);
}
static inline void _dispatch_continuation_invoke_inline(dispatch_object_t dou, voucher_t ov,
dispatch_invoke_flags_t flags)
{
dispatch_continuation_t dc = dou._dc, dc1;
dispatch_invoke_with_autoreleasepool(flags, {
uintptr_t dc_flags = dc->dc_flags;
_dispatch_continuation_voucher_adopt(dc, ov, dc_flags);
if (dc_flags & DISPATCH_OBJ_CONSUME_BIT) {
dc1 = _dispatch_continuation_free_cacheonly(dc);
} else {
dc1 = NULL;
}
// 后面分析dispatch_group_async的時(shí)候會走if這個(gè)分支,但這次走的是else分支
if (unlikely(dc_flags & DISPATCH_OBJ_GROUP_BIT)) {
_dispatch_continuation_with_group_invoke(dc);
} else {
// 這次走這里,直接執(zhí)行block函數(shù)
_dispatch_client_callout(dc->dc_ctxt, dc->dc_func);
_dispatch_introspection_queue_item_complete(dou);
}
if (unlikely(dc1)) {
_dispatch_continuation_free_to_cache_limit(dc1);
}
});
_dispatch_perfmon_workitem_inc();
}
至此,任務(wù)怎么被調(diào)度執(zhí)行的已經(jīng)看明白了。start_wqthread是匯編寫的,直接和內(nèi)核交互。雖然我們明確了使用了異步的任務(wù)被執(zhí)行的調(diào)用順序,但是想必還是有這樣的疑問_dispatch_worker_thread3是怎么跟內(nèi)核扯上關(guān)系的。為什么調(diào)用的是_dispatch_worker_thread3,而不是_dispatch_worker_thread或者_dispatch_worker_thread4呢?
??在此之前需要說的是,在GCD中一共有2個(gè)線程池管理著任務(wù),一個(gè)是主線程池,另一個(gè)就是除了主線程任務(wù)的線程池。主線程池由序號1的隊(duì)列管理,其他有序號2的隊(duì)列進(jìn)行管理。加上runloop運(yùn)行的runloop隊(duì)列,一共就有16個(gè)隊(duì)列。
序號 標(biāo)簽
1 com.apple.main-thread
2 com.apple.libdispatch-manager
3 com.apple.root.libdispatch-manager
4 com.apple.root.maintenance-qos
5 com.apple.root.maintenance-qos.overcommit
6 com.apple.root.background-qos
7 com.apple.root.background-qos.overcommit
8 com.apple.root.utility-qos
9 com.apple.root.utility-qos.overcommit
10 com.apple.root.default-qos
11 com.apple.root.default-qos.overcommit
12 com.apple.root.user-initiated-qos
13 com.apple.root.user-initiated-qos.overcommit
14 com.apple.root.user-interactive-qos
15 com.apple.root.user-interactive-qos.overcommit
看圖的話,就如下圖線程池圖
有那么多root隊(duì)列,所以application啟動的時(shí)候就會初始化這些root隊(duì)列的_dispatch_root_queues_init函數(shù)。
void
_dispatch_root_queues_init(void)
{
static dispatch_once_t _dispatch_root_queues_pred;
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
static void
_dispatch_root_queues_init_once(void *context DISPATCH_UNUSED)
{
int wq_supported;
_dispatch_fork_becomes_unsafe();
if (!_dispatch_root_queues_init_workq(&wq_supported)) {
size_t i;
for (i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) {
bool overcommit = true;
_dispatch_root_queue_init_pthread_pool(
&_dispatch_root_queue_contexts[i], 0, overcommit);
}
DISPATCH_INTERNAL_CRASH((errno << 16) | wq_supported,
"Root queue initialization failed");
}
}
static inline bool
_dispatch_root_queues_init_workq(int *wq_supported)
{
int r; (void)r;
bool result = false;
*wq_supported = 0;
bool disable_wq = false; (void)disable_wq;
bool disable_qos = false;
bool disable_kevent_wq = false;
if (!disable_wq && !disable_qos) {
*wq_supported = _pthread_workqueue_supported();
if (!disable_kevent_wq && (*wq_supported & WORKQ_FEATURE_KEVENT)) {
r = _pthread_workqueue_init_with_kevent(_dispatch_worker_thread3,
(pthread_workqueue_function_kevent_t)
_dispatch_kevent_worker_thread,
offsetof(struct dispatch_queue_s, dq_serialnum), 0);
result = !r;
}
}
return result;
}
來到這里,已經(jīng)看到_pthread_workqueue_init_with_kevent函數(shù)就是綁定了_dispatch_worker_thread3函數(shù)去做一些GCD的線程任務(wù),看到源代碼_pthread_workqueue_init_with_kevent做了些什么。
int
_pthread_workqueue_init_with_kevent(pthread_workqueue_function2_t queue_func,
pthread_workqueue_function_kevent_t kevent_func,
int offset, int flags)
{
return _pthread_workqueue_init_with_workloop(queue_func, kevent_func, NULL, offset, flags);
}
int
_pthread_workqueue_init_with_workloop(pthread_workqueue_function2_t queue_func,
pthread_workqueue_function_kevent_t kevent_func,
pthread_workqueue_function_workloop_t workloop_func,
int offset, int flags)
{
if (flags != 0) {
return ENOTSUP;
}
__workq_newapi = true;
__libdispatch_offset = offset;
int rv = pthread_workqueue_setdispatch_with_workloop_np(queue_func, kevent_func, workloop_func);
return rv;
}
static int
pthread_workqueue_setdispatch_with_workloop_np(pthread_workqueue_function2_t queue_func,
pthread_workqueue_function_kevent_t kevent_func,
pthread_workqueue_function_workloop_t workloop_func)
{
int res = EBUSY;
if (__libdispatch_workerfunction == NULL) {
// Check whether the kernel supports new SPIs
res = __workq_kernreturn(WQOPS_QUEUE_NEWSPISUPP, NULL, __libdispatch_offset, kevent_func != NULL ? 0x01 : 0x00);
if (res == -1){
res = ENOTSUP;
} else {
__libdispatch_workerfunction = queue_func;
__libdispatch_keventfunction = kevent_func;
__libdispatch_workloopfunction = workloop_func;
// Prepare the kernel for workq action
(void)__workq_open();
if (__is_threaded == 0) {
__is_threaded = 1;
}
}
}
return res;
}
我們看到了__libdispatch_workerfunction = queue_func;指定了隊(duì)列工作函數(shù)。然后我們往回看之前說的我們制造了一個(gè)人為crash,追溯棧里看到_pthread_wqthread這個(gè)函數(shù)。看下這個(gè)函數(shù)怎么啟用_dispatch_worker_thread3的
// 實(shí)際代碼很多,這里我精簡了下,拿到了__libdispatch_workerfunction對應(yīng)的_dispatch_worker_thread3,然后直接執(zhí)行。
void
_pthread_wqthread(pthread_t self, mach_port_t kport, void *stacklowaddr, void *keventlist, int flags, int nkevents)
{
pthread_workqueue_function_t func = (pthread_workqueue_function_t)__libdispatch_workerfunction;
int options = overcommit ? WORKQ_ADDTHREADS_OPTION_OVERCOMMIT : 0;
// 執(zhí)行函數(shù)
(*func)(thread_class, options, NULL);
__workq_kernreturn(WQOPS_THREAD_RETURN, NULL, 0, 0);
_pthread_exit(self, NULL);
}