Coro
view release on metacpan or search on metacpan
Coro/libcoro/coro.c view on Meta::CPAN
#error "linux libc or architecture not supported"
#endif
# elif CORO_IRIX
coro_setjmp (ctx->env, 0);
ctx->env[JB_PC] = (__uint64_t)coro_init;
ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
# elif CORO_ASM
#if __i386__ || __x86_64__
ctx->sp = (void **)(ssize + (char *)sptr);
*--ctx->sp = (void *)abort; /* needed for alignment only */
*--ctx->sp = (void *)coro_init;
#if CORO_WIN_TIB
*--ctx->sp = 0; /* ExceptionList */
*--ctx->sp = (char *)sptr + ssize; /* StackBase */
*--ctx->sp = sptr; /* StackLimit */
#endif
#elif CORO_ARM
/* return address stored in lr register, don't push anything */
#else
#error unsupported architecture
#endif
ctx->sp -= NUM_SAVED;
memset (ctx->sp, 0, sizeof (*ctx->sp) * NUM_SAVED);
#if __i386__ || __x86_64__
/* done already */
#elif CORO_ARM
ctx->sp[0] = coro; /* r4 */
ctx->sp[1] = arg; /* r5 */
ctx->sp[8] = (char *)coro_init; /* lr */
#else
#error unsupported architecture
#endif
# elif CORO_UCONTEXT
getcontext (&(ctx->uc));
ctx->uc.uc_link = 0;
ctx->uc.uc_stack.ss_sp = sptr;
ctx->uc.uc_stack.ss_size = (size_t)ssize;
ctx->uc.uc_stack.ss_flags = 0;
makecontext (&(ctx->uc), (void (*)())coro_init, 0);
# endif
coro_transfer (create_coro, new_coro);
}
/*****************************************************************************/
/* pthread backend */
/*****************************************************************************/
#elif CORO_PTHREAD
/* this mutex will be locked by the running coroutine */
pthread_mutex_t coro_mutex = PTHREAD_MUTEX_INITIALIZER;
struct coro_init_args
{
coro_func func;
void *arg;
coro_context *self, *main;
};
static pthread_t null_tid;
/* I'd so love to cast pthread_mutex_unlock to void (*)(void *)... */
static void
mutex_unlock_wrapper (void *arg)
{
pthread_mutex_unlock ((pthread_mutex_t *)arg);
}
static void *
coro_init (void *args_)
{
struct coro_init_args *args = (struct coro_init_args *)args_;
coro_func func = args->func;
void *arg = args->arg;
pthread_mutex_lock (&coro_mutex);
/* we try to be good citizens and use deferred cancellation and cleanup handlers */
pthread_cleanup_push (mutex_unlock_wrapper, &coro_mutex);
coro_transfer (args->self, args->main);
func (arg);
pthread_cleanup_pop (1);
return 0;
}
void
coro_transfer (coro_context *prev, coro_context *next)
{
pthread_cond_signal (&next->cv);
pthread_cond_wait (&prev->cv, &coro_mutex);
#if __FreeBSD__ /* freebsd is of course broken and needs manual testcancel calls... yay... */
pthread_testcancel ();
#endif
}
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, size_t ssize)
{
static coro_context nctx;
static int once;
if (!once)
{
once = 1;
pthread_mutex_lock (&coro_mutex);
pthread_cond_init (&nctx.cv, 0);
null_tid = pthread_self ();
}
( run in 1.176 second using v1.01-cache-2.11-cpan-97f6503c9c8 )