Created
September 12, 2021 14:34
-
-
Save JackyYin/95bfc704fb9319ec1cbf48aa77d64256 to your computer and use it in GitHub Desktop.
a simple coroutine implementation using ucontext
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ucontext.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define handle_error(msg) \ | |
do { perror(msg); exit(EXIT_FAILURE); } while (0) | |
#define CO_STACK_SIZE 2048 | |
typedef struct { | |
char stack[CO_STACK_SIZE]; | |
ucontext_t context; | |
ucontext_t from; | |
int yield_value; | |
} coroutine_t; | |
coroutine_t* coro_new(void(*fp)(coroutine_t*)) | |
{ | |
/* printf("%lu\n", sizeof(coroutine_t)); */ | |
coroutine_t *coro = malloc(sizeof(coroutine_t)); | |
printf("%p\n", &coro->stack[0]); | |
if (!coro) | |
handle_error("failed to allocate"); | |
if (getcontext(&coro->context) == -1) | |
handle_error("getcontext"); | |
coro->context.uc_stack.ss_sp = coro->stack; | |
coro->context.uc_stack.ss_size = CO_STACK_SIZE; | |
makecontext(&coro->context, (void (*)()) fp, 1, coro); | |
return coro; | |
} | |
int coro_resume(coroutine_t *coro) | |
{ | |
if (swapcontext(&coro->from, &coro->context) == -1) | |
handle_error("swapcontext"); | |
return coro->yield_value; | |
} | |
void coro_yield(coroutine_t *coro, int value) | |
{ | |
coro->yield_value = value; | |
if (swapcontext(&coro->context, &coro->from) == -1) | |
handle_error("swapcontext"); | |
} | |
static void func2(coroutine_t *coro) | |
{ | |
printf("func2: started\n"); | |
coro_yield(coro, 2); | |
coro_yield(coro, 4); | |
printf("func2: exited\n"); | |
} | |
static void func1(coroutine_t *coro) | |
{ | |
printf("func1: started\n"); | |
coroutine_t *coro2 = coro_new(func2); | |
printf("func1: func2 yielded %d\n", coro_resume(coro2)); | |
printf("func1: func2 yielded %d\n", coro_resume(coro2)); | |
coro_yield(coro, 1); | |
coro_yield(coro, 3); | |
coro_yield(coro, 5); | |
printf("func1: exited\n"); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
coroutine_t *coro1 = coro_new(func1); | |
printf("main: func1 yielded %d\n", coro_resume(coro1)); | |
printf("main: func1 yielded %d\n", coro_resume(coro1)); | |
printf("main: func1 yielded %d\n", coro_resume(coro1)); | |
printf("main: exiting\n"); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment