├── Coro.cpp ├── Coro.h ├── README.md └── main.cpp /Coro.cpp: -------------------------------------------------------------------------------- 1 | #include "Coro.h" 2 | #include 3 | #include 4 | #include 5 | 6 | // stack size 2M 7 | #define CORO_STACK_SIZE 1024 * 1024 * 2 8 | 9 | #define CORO_FUN_INIT 0 10 | #define CORO_FUN_END 1 11 | #define CORO_FUN_YIELD 2 12 | 13 | struct Coro; 14 | 15 | static struct Coro* current_coro = NULL; 16 | static struct Coro* coro_list = NULL; 17 | static int coro_num = 0; 18 | 19 | jmp_buf main_env; 20 | 21 | struct Coro 22 | { 23 | struct Coro *prev, *next; 24 | 25 | int co_id; 26 | CoroFunType co_fun; 27 | void* co_arg; 28 | void* co_stack; 29 | 30 | jmp_buf co_env; 31 | }; 32 | 33 | static void _start_coro() 34 | { 35 | current_coro->co_fun(current_coro->co_arg); 36 | longjmp(main_env, CORO_FUN_END); 37 | } 38 | 39 | void coro_new(CoroFunType f, void* arg) 40 | { 41 | struct Coro* co = (struct Coro*) malloc(sizeof(struct Coro)); 42 | assert(co); 43 | 44 | if (coro_list) 45 | { 46 | co->prev = coro_list->prev; 47 | co->next = coro_list; 48 | coro_list->prev->next = co; 49 | coro_list->prev = co; 50 | } 51 | else 52 | { 53 | co->prev = co; 54 | co->next = co; 55 | } 56 | coro_list = co; 57 | 58 | // init struct Coro 59 | co->co_id = ++coro_num; 60 | co->co_fun = f; 61 | co->co_arg = arg; 62 | co->co_stack = malloc(CORO_STACK_SIZE); 63 | assert(co->co_stack); 64 | 65 | // init jmp buf 66 | setjmp(co->co_env); 67 | _JUMP_BUFFER* jmp_buf = (_JUMP_BUFFER*)&(co->co_env); 68 | 69 | jmp_buf->Eip = (unsigned long)(_start_coro); 70 | jmp_buf->Esp = (unsigned long)((char*)(co->co_stack) + CORO_STACK_SIZE - 16); 71 | } 72 | 73 | void coro_main() 74 | { 75 | if (!coro_list) 76 | return; 77 | 78 | struct Coro *co; 79 | switch (setjmp(main_env)) 80 | { 81 | case CORO_FUN_INIT: 82 | // scheduling 83 | current_coro = coro_list; 84 | break; 85 | 86 | case CORO_FUN_END: 87 | co = current_coro; 88 | if (co->next == co) 89 | { 90 | coro_list = NULL; 91 | free(co->co_stack); 92 | free(co); 93 | return; 94 | } 95 | // scheduling 96 | current_coro = current_coro->next; 97 | co->prev->next = co->next; 98 | co->next->prev = co->prev; 99 | free(co->co_stack); 100 | free(co); 101 | break; 102 | 103 | case CORO_FUN_YIELD: 104 | // scheduling 105 | current_coro = current_coro->next; 106 | } 107 | assert(current_coro); 108 | longjmp(current_coro->co_env, 1); 109 | } 110 | 111 | void coro_yield() 112 | { 113 | if (setjmp(current_coro->co_env)) 114 | return; 115 | longjmp(main_env, CORO_FUN_YIELD); 116 | } -------------------------------------------------------------------------------- /Coro.h: -------------------------------------------------------------------------------- 1 | #ifndef _CORO_H_ 2 | #define _CORO_H_ 3 | 4 | typedef void (*CoroFunType)(void*); 5 | 6 | void coro_new(CoroFunType f, void* arg); 7 | void coro_yield(); 8 | void coro_main(); 9 | 10 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coro 2 | 用c语言setjmp和longjmp实现的一个最基本的协程,详见[blog](http://www.cnblogs.com/adinosaur/p/5889014.html)。 3 | 4 | ## Usage 5 | 使用包含头文件`#include"Coro.h"`,模块只有三个接口: 6 | 7 | 1. coro_new创建一个协程。 8 | 2. coro_yield将控制返回给主(调度)协程。 9 | 3. coro_main运行主(调度协程)。 10 | ``` 11 | void co1(void* msg) 12 | { 13 | for (int i = 0; i != 5; ++i) 14 | { 15 | printf("%s\n", (char*)msg); 16 | coro_yield(); 17 | } 18 | } 19 | 20 | int main(int ac, char** av) 21 | { 22 | coro_new(co1, "hello"); 23 | coro_new(co1, "world"); 24 | coro_main(); 25 | return 0; 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Coro.h" 3 | #include 4 | #include 5 | 6 | void co1(void* msg) 7 | { 8 | for (int i = 0; i != 5; ++i) 9 | { 10 | printf("%s\n", (char*)msg); 11 | coro_yield(); 12 | } 13 | } 14 | 15 | int main(int ac, char** av) 16 | { 17 | assert(sizeof(void*) == sizeof(unsigned long)); 18 | 19 | coro_new(co1, "hello"); 20 | coro_new(co1, "world"); 21 | coro_main(); 22 | return 0; 23 | } --------------------------------------------------------------------------------