coroutine *coro_new(struct pool *pool, void (*entry_point)(void *arg), void *arg);
void coro_suspend(void);
void coro_resume(coroutine *c);
+void coro_done(void *retval) NORET;
struct birdsock;
int coro_sk_read(struct birdsock *s);
return c;
}
+void
+coro_done(void *retval)
+{
+ ASSERT(coro_inited);
+ ASSERT(coro_current);
+ coroutine *c = coro_current;
+ c->retval = retval;
+ coro_suspend();
+ bug("Coroutine suspend after coro_done() should never return");
+}
+
void
coro_suspend(void)
{
#include <pthread.h>
#include <semaphore.h>
+#define CORO_STOP 1 /* The coroutine should stop at first coro_suspend(). */
+#define CORO_DONE 2 /* The coroutine has already stopped. */
+
struct coroutine {
resource r;
pthread_t thread;
void (*entry_point)(void *arg);
void *arg;
sem_t sem;
+ uint flags;
};
static coroutine *coro_current; // NULL for main context
{
coroutine *c = (coroutine *) r;
ASSERT(coro_current != c);
- pthread_cancel(c->thread);
+
+ c->flags |= CORO_STOP;
+ coro_resume(c);
+
+ ASSERT(c->flags & CORO_DONE);
pthread_join(c->thread, NULL);
}
return c;
}
+static inline void
+coro_check_stop(void)
+{
+ ASSERT(coro_inited);
+ ASSERT(coro_current);
+ coroutine *c = coro_current;
+ if (c->flags & CORO_STOP)
+ coro_done(NULL);
+}
+
+void
+coro_done(void *retval)
+{
+ ASSERT(coro_inited);
+ ASSERT(coro_current);
+ coroutine *c = coro_current;
+ c->flags |= CORO_DONE;
+ sem_post(&coro_main_sem);
+ pthread_exit(retval);
+ bug("pthread_exit should never return");
+}
+
void
coro_suspend(void)
{
ASSERT(coro_inited);
ASSERT(coro_current);
coroutine *c = coro_current;
+ coro_check_stop();
sem_post(&coro_main_sem);
while (sem_wait(&c->sem) < 0)
;
coro_current = c;
+ coro_check_stop();
}
void