C语言的协程实现

coroutine.h文件

#ifndef C_COROUTINE_H #define C_COROUTINE_H#define COROUTINE_DEAD 0 #define COROUTINE_READY 1 #define COROUTINE_RUNNING 2 #define COROUTINE_SUSPEND 3struct schedule; typedef void (*coroutine_func)(struct schedule *, void *ud); struct schedule * coroutine_open(void); void coroutine_close(struct schedule *); int coroutine_new(struct schedule *, coroutine_func, void *ud); void coroutine_resume(struct schedule *, int id); int coroutine_status(struct schedule *, int id); int coroutine_running(struct schedule *); void coroutine_yield(struct schedule *); #endif

coroutine.c文件
#include "coroutine.h" #include #include #include #include #include #include #if __APPLE__ && __MACH__ #include #else #include #endif #define STACK_SIZE (1024*1024) #define DEFAULT_COROUTINE 16struct coroutine; struct schedule { char stack[STACK_SIZE]; ucontext_t main; int nco; int cap; int running; struct coroutine **co; }; struct coroutine { coroutine_func func; void *ud; ucontext_t ctx; struct schedule * sch; ptrdiff_t cap; ptrdiff_t size; int status; char *stack; }; struct coroutine * _co_new(struct schedule *S , coroutine_func func, void *ud) { struct coroutine * co = malloc(sizeof(*co)); co->func = func; co->ud = ud; co->sch = S; co->cap = 0; co->size = 0; co->status = COROUTINE_READY; co->stack = NULL; return co; }void _co_delete(struct coroutine *co) { free(co->stack); free(co); }struct schedule * coroutine_open(void) { struct schedule *S = malloc(sizeof(*S)); S->nco = 0; S->cap = DEFAULT_COROUTINE; S->running = -1; S->co = malloc(sizeof(struct coroutine *) * S->cap); memset(S->co, 0, sizeof(struct coroutine *) * S->cap); return S; }void coroutine_close(struct schedule *S) { int i; for (i=0; icap; i++) { struct coroutine * co = S->co[i]; if (co) { _co_delete(co); } } free(S->co); S->co = NULL; free(S); }int coroutine_new(struct schedule *S, coroutine_func func, void *ud) { struct coroutine *co = _co_new(S, func , ud); if (S->nco >= S->cap) { int id = S->cap; S->co = realloc(S->co, S->cap * 2 * sizeof(struct coroutine *)); memset(S->co + S->cap , 0 , sizeof(struct coroutine *) * S->cap); S->co[S->cap] = co; S->cap *= 2; ++S->nco; return id; } else { int i; for (i=0; icap; i++) { int id = (i+S->nco) % S->cap; if (S->co[id] == NULL) { S->co[id] = co; ++S->nco; return id; } } } assert(0); return -1; }static void mainfunc(uint32_t low32, uint32_t hi32) { uintptr_t ptr = (uintptr_t)low32 | ((uintptr_t)hi32 << 32); struct schedule *S = (struct schedule *)ptr; int id = S->running; struct coroutine *C = S->co[id]; C->func(S,C->ud); _co_delete(C); S->co[id] = NULL; --S->nco; S->running = -1; }void coroutine_resume(struct schedule * S, int id) { assert(S->running == -1); assert(id >=0 && id < S->cap); struct coroutine *C = S->co[id]; if (C == NULL) return; int status = C->status; switch(status) { case COROUTINE_READY: getcontext(&C->ctx); C->ctx.uc_stack.ss_sp = S->stack; C->ctx.uc_stack.ss_size = STACK_SIZE; C->ctx.uc_link = &S->main; S->running = id; C->status = COROUTINE_RUNNING; uintptr_t ptr = (uintptr_t)S; makecontext(&C->ctx, (void (*)(void)) mainfunc, 2, (uint32_t)ptr, (uint32_t)(ptr>>32)); swapcontext(&S->main, &C->ctx); break; case COROUTINE_SUSPEND: memcpy(S->stack + STACK_SIZE - C->size, C->stack, C->size); S->running = id; C->status = COROUTINE_RUNNING; swapcontext(&S->main, &C->ctx); break; default: assert(0); } }static void _save_stack(struct coroutine *C, char *top) { char dummy = 0; assert(top - &dummy <= STACK_SIZE); if (C->cap < top - &dummy) { free(C->stack); C->cap = top-&dummy; C->stack = malloc(C->cap); } C->size = top - &dummy; memcpy(C->stack, &dummy, C->size); }void coroutine_yield(struct schedule * S) { int id = S->running; assert(id >= 0); struct coroutine * C = S->co[id]; assert((char *)&C > S->stack); _save_stack(C,S->stack + STACK_SIZE); C->status = COROUTINE_SUSPEND; S->running = -1; swapcontext(&C->ctx , &S->main); }int coroutine_status(struct schedule * S, int id) { assert(id>=0 && id < S->cap); if (S->co[id] == NULL) { return COROUTINE_DEAD; } return S->co[id]->status; }int coroutine_running(struct schedule * S) { return S->running; }

main.c 文件:
#include "coroutine.h" #include struct args { int n; }; static void foo(struct schedule * S, void *ud) { struct args * arg = ud; int start = arg->n; int i; for (i=0; i<5; i++) { printf("coroutine %d : %d\n",coroutine_running(S) , start + i); coroutine_yield(S); } }static void test(struct schedule *S) { struct args arg1 = { 0 }; struct args arg2 = { 100 }; int co1 = coroutine_new(S, foo, &arg1); int co2 = coroutine_new(S, foo, &arg2); printf("main start\n"); while (coroutine_status(S,co1) && coroutine_status(S,co2)) { coroutine_resume(S,co1); coroutine_resume(S,co2); } printf("main end\n"); }int main() { struct schedule * S = coroutine_open(); test(S); coroutine_close(S); return 0; }

【C语言的协程实现】输出:
main start coroutine 0 : 0 coroutine 1 : 100 coroutine 0 : 1 coroutine 1 : 101 coroutine 0 : 2 coroutine 1 : 102 coroutine 0 : 3 coroutine 1 : 103 coroutine 0 : 4 coroutine 1 : 104 main end

    推荐阅读