万字长文 | 漫谈libco协程设计及实现

640?wx_fmt=gif




libco简介

libco是微信后台大规模使用的c/c++协程库,2013年至今稳定运行在微信后台的数万台机器上,使得微信后端服务能同时hold大量请求,被誉为微信服务器稳定性的基石。libco在2013年的时候作为腾讯六大开源项目首次开源。libco源码地址


libco首先能解决CPU利用率与IO利用率不平衡,比用多线程解决IO阻塞CPU问题更高效。因为用户态协程切换比线程切换性能高:线程切换保存恢复的数据更多,需要用户态和内核态切换。其次libco又避免了异步调用和回调分离导致的代码结构破碎。


libco采用epoll多路复用使得一个线程处理多个socket连接,采用钩子函数hook住socket族函数,采用时间轮盘处理等待超时事件,采用协程栈保存、恢复每个协程上下文环境。


为了让大家更容易阅读libco源码,本文以源码为主介绍libco,内容偏底层细节。更多个人文章,欢迎关注作者博客


设计思想

1. 协程切换

1.1 函数栈

首先复习下进程的地址空间,如图1所示,与本文相关的有代码段、堆、栈。代码段包含应用程序的汇编代码,指令寄存器eip存的是代码段中某一条汇编指令地址,cpu从eip中取出汇编指令的地址,并在代码段中找到对应汇编指令开始执行。CPU执行指令时在栈里存参数、局部变量等数据。代码通过malloc、new在堆上申请内存空间。

640

图1


图2所示C代码,通过gcc -m32 test.c -o test.o在i386下编译,然后执行gdb test.o。disas main可看到图3所示的main函数汇编码,disas sum可看到图4所示sum函数的汇编代码。调用sum时,main和sum的函数栈如图5所示。图5的表共有两列,第一列为内存地址,第二列为该地址存的内容,除了用“...”省略的内存地址,其他每一行均比上一行低4byte,因为栈地址从高到低增长。


从图5可以看出:一,每个函数的栈在ebp栈底指针和esp栈顶指针之间;二,存在调用关系的两个函数的栈内存地址是相邻的;三,ebp指针指的位置存储的是上级函数的ebp地址,例如sum的ebp 0xffffd598位置存的是main的ebp0xffffd5c8,目的是sum执行后可恢复main的ebp,而main的esp可通过sum的ebp + 4恢复;四,sum的ebp + 4位置,即main的esp位置存的是sum执行后的返回地址0x08048415,该地址不在图1中的栈(Stack)里,而在图1中的代码段里,sum执行后,leave指令恢复ebp、esp,ret指令将esp处的内容0x08048415放到寄存器eip,cpu从eip里取出下一条待执行的指令地址,并根据指令地址从代码段里获取指令执行;五,sum的参数y、x按高地址到低地址,依次存在sum的ebp + 12、ebp + 8位置处。


640

图2


640

图3 main函数汇编码


640

图4 sum函数汇编码


640

图5 32位系统函数栈


1.2 协程栈

共享栈下文介绍,此处介绍非共享栈。在非共享栈模式下,每个非主协程有自己的栈,而该栈是在堆上分配的,并不是系统栈,但主协程的栈仍然是系统栈,每两个协程的栈地址不相邻。协程栈切换分为第1次、第k次(k>=2)换到目的协程TargetCoroutine。


因为主协程即当前线程的第1次运行是系统调度的,后续才由用户调度,而非主协程每次都由用户调度。所以每次主协程切回的行为都一样,且和非主协程第k次(k>=2)的切回行为一致。


第1次切到TargetCoroutine之前, coctx_make(图6)将函数地址pfn写入协程变量regs[ kEIP ],pfn即为CoRoutineFunc的指针。CoRoutineFunc函数(图7)在第448行调进用户自定义的协程函数UserCoRoutineFunc(图8)。图6中ss_sp为128K协程栈低地址,ss_size为128K将ss_sp+ss_size – sizeof(coctx_param_t)–sizeof(void*)作为esp开始位置,记录在regs[kESP]。因为栈从高到低增长,所以真正的栈空间从高地址ss_sp + ss_size – sizeof(void*) – sizeof(coctx_param_t)增长到低地址ss_sp。这部分空间虽然是协程栈,但实际是通过stack_mem->stack_buffer= (char*)malloc(stack_size)申请的堆空间。CoRoutineFunc、其调用的函数、其调用的函数再调用的函数…的函数栈均在该128K的堆空间里。

640

图6


640

图7

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值