From f9cbd6205175ad6300b6f6f3ee1d1516bef72d92 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Wed, 19 Jul 2017 00:21:42 +0200 Subject: [PATCH] Another implementation of coroutines using pthreads --- sysdep/unix/coroutine.c | 125 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/sysdep/unix/coroutine.c b/sysdep/unix/coroutine.c index 3d648eb4..5e986a7c 100644 --- a/sysdep/unix/coroutine.c +++ b/sysdep/unix/coroutine.c @@ -11,7 +11,6 @@ #endif #include -#include #include "nest/bird.h" #include "lib/coroutine.h" @@ -19,6 +18,16 @@ #include "lib/socket.h" #include "sysdep/unix/unix.h" +#define CORO_STACK_SIZE 65536 + +#if 1 + +/* + * Implementation of coroutines based on + */ + +#include + struct coroutine { resource r; ucontext_t ctx; @@ -30,8 +39,6 @@ struct coroutine { static ucontext_t *main_context; static coroutine *coro_current; // NULL for main context -#define CORO_STACK_SIZE 65536 - static void coro_free(resource *r) { @@ -112,6 +119,118 @@ coro_resume(coroutine *c) ASSERT(!coro_current); } +#else + +/* + * Implementation of coroutines based on POSIX threads + */ + +#include +#include + +struct coroutine { + resource r; + pthread_t thread; + void (*entry_point)(void *arg); + void *arg; + sem_t sem; +}; + +static coroutine *coro_current; // NULL for main context +static int coro_inited; +static sem_t coro_main_sem; +static pthread_attr_t coro_thread_attrs; + +static void +coro_free(resource *r) +{ + coroutine *c = (coroutine *) r; + pthread_cancel(c->thread); + pthread_join(c->thread, NULL); +} + +static void +coro_dump(resource *r UNUSED) +{ + debug("\n"); +} + +static size_t +coro_memsize(resource *r) +{ + coroutine *c = (coroutine *) r; + return sizeof(*c) + CORO_STACK_SIZE + 2*ALLOC_OVERHEAD; +} + +static struct resclass coro_class = { + .name = "Coroutine", + .size = sizeof(struct coroutine), + .free = coro_free, + .dump = coro_dump, + .memsize = coro_memsize, +}; + +static void * +coro_do_start(void *c_) +{ + coroutine *c = c_; + while (sem_wait(&c->sem) < 0) + ; + coro_current = c; + c->entry_point(c->arg); + bug("Coroutine returned unexpectedly"); +} + +struct coroutine * +coro_new(pool *p, void (*entry_point)(void *), void *arg) +{ + if (!coro_inited) + { + if (sem_init(&coro_main_sem, 0, 0) < 0) + bug("sem_init() failed"); + if (pthread_attr_init(&coro_thread_attrs)) + bug("pthread_attr_init() failed"); + if (pthread_attr_setstacksize(&coro_thread_attrs, CORO_STACK_SIZE)) + bug("pthread_attr_setstacksize() failed"); + coro_inited = 1; + } + + coroutine *c = ralloc(p, &coro_class); + c->entry_point = entry_point; + c->arg = arg; + if (sem_init(&c->sem, 0, 0) < 0) + bug("sem_init() failed"); + if (pthread_create(&c->thread, &coro_thread_attrs, coro_do_start, c)) + bug("pthread_create() failed"); + + return c; +} + +void +coro_suspend(void) +{ + ASSERT(coro_inited); + ASSERT(coro_current); + coroutine *c = coro_current; + sem_post(&coro_main_sem); + while (sem_wait(&c->sem) < 0) + ; + coro_current = c; +} + +void +coro_resume(coroutine *c) +{ + ASSERT(coro_inited); + ASSERT(!coro_current); + sem_post(&c->sem); + while (sem_wait(&coro_main_sem) < 0) + ; + coro_current = NULL; +} + +#endif + /* Coroutine-based I/O */ static int