srs(state thread)如何實現(xiàn)協(xié)程切換
srs(state thread)如何實現(xiàn)協(xié)程切換? srs是單線程上運行的協(xié)程模型, 一個線程交替執(zhí)行多個協(xié)程, 那么協(xié)程在用戶空間是如何切換的呢?
首先關(guān)于thread.stack等內(nèi)容可以自行閱讀st thread代碼, 這里只聊協(xié)程上下文切換過程.

417行的宏執(zhí)行協(xié)程A上下文的保存
419行 _st_vp_schedule 在RUNQ中找到一個待執(zhí)行協(xié)程B, 恢復(fù)協(xié)程B的上下文, 切換到該協(xié)程B執(zhí)行.
協(xié)程B執(zhí)行到io阻塞或者sleep事件, 就會重新把協(xié)程B緩存起來, 并尋找一個待執(zhí)行協(xié)程(假設(shè)這里就AB兩個協(xié)程),恢復(fù)協(xié)程A的上下文繼續(xù)執(zhí)行. 完成協(xié)程切換.
協(xié)程上下文保存
#define MD_SETJMP(env) _st_md_cxt_save(env)
/****************************************************************/
/*
* Internal __jmp_buf layout
*/
#define JB_RBX 0
#define JB_RBP 1
#define JB_R12 2
#define JB_R13 3
#define JB_R14 4
#define JB_R15 5
#define JB_RSP 6
#define JB_PC 7
.file "md.S"
.text
/* _st_md_cxt_save(__jmp_buf env) */
.globl _st_md_cxt_save
.type _st_md_cxt_save, @function
.align 16
_st_md_cxt_save:
/*
* Save registers.
* 寄存器數(shù)據(jù)的轉(zhuǎn)存
*/
movq %rbx, (JB_RBX*8)(%rdi)
movq %rbp, (JB_RBP*8)(%rdi)
movq %r12, (JB_R12*8)(%rdi)
movq %r13, (JB_R13*8)(%rdi)
movq %r14, (JB_R14*8)(%rdi)
movq %r15, (JB_R15*8)(%rdi)
/* Save SP */
// 關(guān)于leaq和movq的區(qū)別:
// refs: https://courses.cs.washington.edu/courses/cse374/16wi/lectures/leaq-movq.pdf
// rsp寄存器存放的內(nèi)容是棧頂?shù)牡刂? leaq指令是把rsp+8的地址信息存放到(JB_RSP*8)(%rdi)中.
// 相當(dāng)于是把棧pop之后的棧頂?shù)刂反娣诺搅?JB_RSP*8)(%rdi).
leaq 8(%rsp), %rdx
movq %rdx, (JB_RSP*8)(%rdi)
/* Save PC we are returning to */
// rsp寄存器指向的棧頂?shù)刂飞洗娣诺氖莀st_md_cxt_save函數(shù)的返回地址,
// 把rsp放在(JB_PC*8)(%rdi)中, 等恢復(fù)協(xié)程的時候就可以jump到(JB_PC*8)(%rdi),相當(dāng)于恢復(fù)的時候直接返回了.
// 注意現(xiàn)在只是把協(xié)程上下文保存了, 還沒有切換呢.切回該協(xié)程的時候, 會jump到PC(下面_st_md_cxt_restore函數(shù)寫明)
movq (%rsp), %rax
movq %rax, (JB_PC*8)(%rdi)
// 返回值為rax的異或, 恒為0;
// _st_md_cxt_save返回值什么時候為1呢?
// 在切回該協(xié)程的時候,jump到PC,PC就是_st_md_cxt_save返回的地方(上圖417行), _st_md_cxt_restore根據(jù)輸入的val設(shè)置了eax, eax作為函數(shù)返回值.
xorq %rax, %rax
ret
.size _st_md_cxt_save, .-_st_md_cxt_save
/****************************************************************/

協(xié)程上下文恢復(fù)
#define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val)
/****************************************************************/
/* _st_md_cxt_restore(__jmp_buf env, int val) */
.globl _st_md_cxt_restore
.type _st_md_cxt_restore, @function
.align 16
_st_md_cxt_restore:
/*
* Restore registers.
*/
movq (JB_RBX*8)(%rdi), %rbx
movq (JB_RBP*8)(%rdi), %rbp
movq (JB_R12*8)(%rdi), %r12
movq (JB_R13*8)(%rdi), %r13
movq (JB_R14*8)(%rdi), %r14
movq (JB_R15*8)(%rdi), %r15
/* Set return value */
// 把val參數(shù)作為返回值. jump之后作為了_st_md_cxt_save的返回值.
test %esi, %esi
mov $01, %eax
cmove %eax, %esi
mov %esi, %eax
// 把棧頂寄存器rsp恢復(fù)為(之前_st_md_cxt_save中rsp棧pop之后的棧頂?shù)刂?
// 把PC指針恢復(fù)為_st_md_cxt_save的調(diào)用者, 并跳轉(zhuǎn)到調(diào)用_st_md_cxt_save的地方
movq (JB_PC*8)(%rdi), %rdx
movq (JB_RSP*8)(%rdi), %rsp
/* Jump to saved PC */
jmpq *%rdx
.size _st_md_cxt_restore, .-_st_md_cxt_restore
/****************************************************************/

浙公網(wǎng)安備 33010602011771號