协程切换,实际上有点像偷梁换柱,将寄存器的环境改变来实现协程的切换,在用户的角度去切换。
有一种说法,协程是非抢占式切换。首先明确什么是抢占式切换:就是当低优先性任务遇到高优先性任务,将会被迫让出CPU,供高优先级任务执行。而对于用户态实现的协程来说,什么时候切换,是由我用户决定,所以就没有被迫让出协程这一回事。
只看 x86 代码
# copy from https://github.com/Tencent/libco/blob/master/coctx_swap.S
.globl coctx_swap
coctx_swap:
leaq (%rsp),%rax # 栈指针 赋值给 ras
movq %rax, 104(%rdi) # 13 栈顶
movq %rbx, 96(%rdi) # 12
movq %rcx, 88(%rdi) # 11 第三个参数
movq %rdx, 80(%rdi) # 10 第四个参数
movq 0(%rax), %rax
movq %rax, 72(%rdi) # 9 返回 时的状态
movq %rsi, 64(%rdi) # 8 第二个参数 。 实际上就是第二个指针参数的 coctx数组
movq %rdi, 56(%rdi) # 7 第一个参数 第一个指针参数的 coctx数组
movq %rbp, 48(%rdi) # 6 栈底
movq %r8, 40(%rdi) # 5 第五个参数
movq %r9, 32(%rdi) # 4 第六个参数
movq %r12, 24(%rdi) # 3 是内部调用暂时寄存器 ip。
movq %r13, 16(%rdi) # 2 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
movq %r14, 8(%rdi) # 1 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
movq %r15, (%rdi) # 0 r15 PC寄存器
xorq %rax, %rax # 把rax 置为零
movq 48(%rsi), %rbp # 栈底
movq 104(%rsi), %rsp # 栈顶
movq (%rsi), %r15 # PC 指针
movq 8(%rsi), %r14
movq 16(%rsi), %r13
movq 24(%rsi), %r12
movq 32(%rsi), %r9
movq 40(%rsi), %r8
movq 56(%rsi), %rdi
movq 80(%rsi), %rdx
movq 88(%rsi), %rcx
movq 96(%rsi), %rbx
leaq 8(%rsp), %rsp # 栈顶指针 rsp的 -8 ?
pushq 72(%rsi) # 把返回时的状态压栈 (这样就能够 恢复之前的状态
movq 64(%rsi), %rsi # 恢复第二个参数
ret
- 该函数的参数是两个 char [14]数组,用该数组去保存当前程序的状态,和即将跳转的下一个状态
- 指令后面带 q,是指8个字节,