Skip to content

Instantly share code, notes, and snippets.

@JackyYin
Created September 12, 2021 14:34
Show Gist options
  • Save JackyYin/95bfc704fb9319ec1cbf48aa77d64256 to your computer and use it in GitHub Desktop.
Save JackyYin/95bfc704fb9319ec1cbf48aa77d64256 to your computer and use it in GitHub Desktop.
a simple coroutine implementation using ucontext
#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