实现C协程

来源:互联网 发布:淘宝最新赚钱漏洞 编辑:程序博客网 时间:2024/05/22 13:50

协程的概念就不介绍了,不清楚的同学可以自己google,windows和unix like系统
本身就提供了协程的支持,windows下叫fiber,unix like系统下叫ucontext.

在这里重复制造轮子,一是为了更清楚了解协程的实现,二是为了在windows和
unix like系统下都提供一套统一的协程接口.

首先介绍下接口,很简单,只有几个函数:

复制代码
#ifndef _UTHREAD_H#define _UTHREAD_Htypedef void (*start_fun)(void *); typedef struct uthread* uthread_t;uthread_t uthread_create(void *stack,uint32_t stack_size);void uthread_destroy(uthread_t*);void uthread_run(uthread_t p,uthread_t u,start_fun st_fun,void *arg);void uthread_switch(uthread_t from,uthread_t to);#endif
复制代码

下面主要介绍uthread_run:
uthread_run启动一个协程的运行,协程运行后会马上执行st_fun函数.
这里需要注意的地方是uthread_run的前两个参数,p和u,u是将被启动
的协程,而p是u的父协程.

如果p为空,则u执行完后将从uthread_run中返回,否则u执行完将调用
uthread_switch(u,p),将执行权交回给p.

uthead.c

复制代码
#include <stdint.h>#include "uthread.h"#include <stdlib.h>#include <stdio.h>struct uthread{    //0:ebp,1:esp,2:ebx,3:edi,4:esi    uint32_t reg[5];    uint32_t parent_reg[5];    struct uthread *parent;//如果_parent非空,则_start_fun结束后返回到_parent中    uint32_t __exit;//主函数调用完成设置    void *stack;    start_fun _start_fun;    void *start_arg;    uint32_t stack_size;};uthread_t uthread_create(void *stack,uint32_t stack_size){    uthread_t u = calloc(1,sizeof(*u));    u->stack = stack;    u->stack_size = stack_size;    u->reg[0] = (uint32_t)stack+stack_size;    u->reg[4] = (uint32_t)stack+stack_size;    u->__exit = 0;    return u;}extern void uthread_run1(uthread_t u,start_fun st_fun,void *arg);extern void uthread_run2(uthread_t p,uthread_t u,start_fun st_fun,void *arg);void uthread_run(uthread_t p,uthread_t u,start_fun st_fun,void *arg){    u->parent = p;    if(u->parent)    {        uthread_run2(p,u,st_fun,arg);        if(u->__exit)            uthread_switch(u,p);    }    else    {        uthread_run1(u,st_fun,arg);    }}void uthread_destroy(uthread_t *u){    free(*u);    *u = 0;}
复制代码

协程的启动和执行权切换无法用c语言完成,下面是用汇编代码实现的切换和启动函数:

switch.s

复制代码
.align    4.globl    uthread_switch.globl    _uthread_switchuthread_switch:_uthread_switch: ##arg from to    movl 4(%esp), %eax     movl %ebp, 0(%eax)    movl %esp, 4(%eax)    movl %ebx, 8(%eax)    movl %edi, 12(%eax)    movl %esi, 16(%eax)    movl 8(%esp), %eax    movl 0(%eax), %ebp     movl 4(%eax), %esp    movl 8(%eax), %ebx    movl 12(%eax),%edi    movl 16(%eax),%esi    ret.align    4.globl    uthread_run1.globl    _uthread_run1uthread_run1:_uthread_run1: ##arg u_context    movl 4(%esp),%eax    movl %ebp,20(%eax) #save register    movl %esp,24(%eax)    movl %ebx,28(%eax)    movl %edi,32(%eax)    movl %esi,36(%eax)    movl 12(%esp),%ecx #get arg    movl 8(%esp),%edx #get st_fun    movl 0(%eax),%esp  #change stack    movl %esp,%ebp    pushl %eax    pushl %ecx     #push arg    call  *%edx    #call st_fun    popl  %eax    popl  %eax    movl 20(%eax),%ebp    #restore register    movl 24(%eax),%esp    movl 28(%eax),%ebx    movl 32(%eax),%edi    movl 36(%eax),%esi    movl $1,44(%eax)    ret.align    4.globl    uthread_run2.globl    _uthread_run2uthread_run2:#param p,u,start_fun,arg_uthread_run2:    movl 4(%esp),%eax  #get p    movl %ebp,0(%eax) #save register of p    movl %esp,4(%eax)    movl %ebx,8(%eax)    movl %edi,12(%eax)    movl %esi,16(%eax)    movl 8(%esp),%eax  #get u    movl 16(%esp),%ecx #get arg    movl 12(%esp),%edx #get st_fun    movl 0(%eax),%esp  #change stack    movl %esp,%ebp    pushl %eax    pushl %ecx     #push arg    call  *%edx    #call st_fun    popl  %eax    popl  %eax    movl $1,44(%eax)    movl 40(%eax),%eax   #get parent    movl 0(%eax),%ebp    #restore register    movl 4(%eax),%esp    movl 8(%eax),%ebx    movl 12(%eax),%edi    movl 16(%eax),%esi    ret            
复制代码

test.c

复制代码
#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include "uthread.h"struct pair{    uthread_t self;    uthread_t other;};void fun2(void *arg){    int i = 0;    struct pair *p = (struct pair*)arg;    printf("fun2\n");    uthread_switch(p->self,p->other);    printf("fun2 end\n");}void fun1(void *arg){    int i = 0;    struct pair *p = (struct pair*)arg;    char *s = malloc(4096);     uthread_t u2 = uthread_create(s,4096);    struct pair _p = {u2,p->self};        uthread_run(p->self,u2,fun2,&_p);    printf("here\n");    uthread_switch(p->self,u2);    printf("fun1 end\n");}int main(){    char *s = malloc(4096);     uthread_t u1 = uthread_create(s,4096);    struct pair p = {u1,0};    uthread_run(0,u1,fun1,&p);    printf("return here\n");    return 0;}
复制代码

 更新:

调整了协程接口,支持在uthread_swtch间传递和返回数据,使用方式更接近lua coroutine

接口如下:

复制代码
#ifndef _UTHREAD_H#define _UTHREAD_Htypedef void* (*start_fun)(void *); typedef struct uthread* uthread_t;uthread_t uthread_create(void *stack,uint32_t stack_size);void uthread_destroy(uthread_t*);void uthread_make(uthread_t u,uthread_t p,start_fun st_fun);void* uthread_swtch(uthread_t from,uthread_t to,void *arg);#endif
复制代码

 

转载自:http://www.cnblogs.com/sniperHW/archive/2012/06/19/2554574.html

0 0
原创粉丝点击