目录
- 向量图的绘制
- 协程模型
- 节点调度模型
协程的概念
维基百科是这样定义的
协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务的子例程,允许执行被挂起与被恢复。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。协程更适合于用来实现彼此熟悉的程序组件,如协作式多任务、异常处理、事件循环、迭代器、无限列表和管道。
协程有多种语言的实现方式,对于C语言来说,C标准库里有“非局部跳转”函数setjmp和longjmp,它们分别保存和恢复:栈指针、程序计数器、被调用者保存的寄存器和ABI要求的任何其他内部状态。
VPP协程模型
VPP的协程便是由setjmp/longjmp实现。使用longjmp/setjmp的轻量级多任务协程,由应用进程自行进行调度,不受操作系统调度机制的影响,上下文切换只损耗调用longjmp/setjmp的时间。
代码使用汇编编写,只关注一下对应的API接口,
clib_longjmp_t 保存CPU寄存器状态 stack 保存堆栈信息
代码语言:javascript复制/* Return given value to saved context. */
跳转到setjmp设置点,reurn_value 就是跳转到clib—setjmp返回数值
void clib_longjmp (clib_longjmp_t * save, uword return_value);
/* Save context. Returns given value if jump is not taken;
otherwise returns value from clib_longjmp if long jump is taken. */
设置跳转返回点,默认返回
uword clib_setjmp (clib_longjmp_t * save, uword return_value_not_taken);
/* Call function on given stack. */
在设置的stack区中跳转,运行fuc函数,函数返回值就是func的返回值
uword clib_calljmp (uword (*func) (uword func_arg),
uword func_arg, void *stack);
VPP是一个多线程程序,包括main线程,worker线程,协程。协程只能由main线程调度。
协程初始化流程:
在 vlib_main_or_worker_loop 函数中 main线程 遍历process数组,调用 dispatch_process 完成对process类型node的初始化调度。
在 vlib_process_startup 函数中,设置跳转返回点,在process的栈空间调用 vlib_process_bootstrap
vlib_process_bootstrap 函数中,执行 process类型node的function, 执行完之后跳转到返回点。此时的跳转返回点见process调度状态图。
每个 VLIB_NODE_TYPE_PROCESS 类型 node的function都遵循相同的模式:
- 在while循环中等待事件、或者事件超时;
- 获取事件类型,执行不同的事件;
以上便是协程初始化调度流程。此时每个process处于挂起状态。
process调度状态图如下: