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的協程框架

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章