libco协程

libco协程框架

协程简介

协程简称用户态线程,是在线程下自己实现的切换的用户态程序切换。实现方式大致分为以下方式:

  1. 使用glibc ucontext
  2. 使用汇编实现
  3. c switch-case
  4. c setjmp longjmp

libco程切使用汇编实现, 支持独立128k大小)和共享()模式。支持hook socket族函数来完成网动协程的框架包装。

 

Libco协程切换

Libco使用void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co)协程切换内部调用汇编实现函数coctx_swap做切换,以__x86_x64__的汇编coctx_swap简单注释如下:

用到的一些基础知识:

            x86-64 下函数调用及栈帧原理” 中指出,调用子函数时,父函数会把调用参数放入了寄存器中,并且把返回地址压入了栈中。即在进入 coctx_swap 时,第一个参数值已经放到了 %rdi 寄存器中,第二个参数值已经放到了 %rsi 寄存器中,并且栈指针 %rsp 指向的位置即栈顶中存储的是父函数的返回地址。

ret指令用栈中的数据,修改IP的内容,从而实现近转移。

 

/*

父函数栈帧中除返回地址外栈帧顶的位置放到rax
*/
   leaq 8(%rsp),%rax
   leaq 112(%rdi),%rsp   //当前协程地址放到rsp 下面保存14个寄存器
   pushq %rax
   pushq %rbx
   pushq %rcx
   pushq %rdx

   pushq -8(%rax) //ret func addr 第一句放入的返回地址

   pushq %rsi
   pushq %rdi
   pushq %rbp
   pushq %r8
   pushq %r9
   pushq %r12
   pushq %r13
   pushq %r14
   pushq %r15
 //至此当前协程的寄存器放入了当前的数据coctx_t结构体中


   movq %rsi, %rsp     //第2个参数即新协程coctx_t作为堆栈指针 然后出栈恢复寄存器
   popq %r15
   popq %r14
   popq %r13
   popq %r12
   popq %r9
   popq %r8
   popq %rbp
   popq %rdi
   popq %rsi
   popq %rax //ret func addr
   popq %rdx
   popq %rcx
   popq %rbx
   popq %rsp

   pushq %rax        //返回地址压入rsp ret指令使用 rsp -> ip寄存器

   xorl %eax, %eax
   ret              //回到新协程

 

libco基础框架

  1. 创建协程co_create

检测协程环境文是否初始化(每个线程一个协程环境,没有则初始化)->创建协程结构。

  1. 运行co_resume

判断当前协程是否是已运行的协程没有则构建上下文

获取正在执行的协程

切换到参数的协程

  1. 挂起co_yield

将此协程移除执行列表,切换到上一个协程

可以使用co_resume再次运行并放入协程运行环境

  1. 销毁co_release

libco hook模式下的阻塞函数自动协程切换

注意所有的这类函数需要在协程里面调用

  1. 检测到系统调用socket hook函数会把当前fd放到一个列表里面。
  2. 调用其他相关函数会查找这个列表并完成相关操作。
  3. 以read为例说明hook流程

libco协程_第1张图片

基于libco的协程框架

你可能感兴趣的:(TCP/IP与网络编程)