summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2008-11-08 04:31:28 +0000
committerroot <root>2008-11-08 04:31:28 +0000
commit930f681be412f20ef67d9aa0d40ae44cbf682814 (patch)
treebd5f5455a4cff6c08552840c1d332a0b0a0bce17
parent6fa667820989d543780fbd67a1ee94b74474cbd7 (diff)
*** empty log message ***
-rw-r--r--coro.c373
-rw-r--r--coro.h11
2 files changed, 197 insertions, 187 deletions
diff --git a/coro.c b/coro.c
index 625eb3e..decb7f6 100644
--- a/coro.c
+++ b/coro.c
@@ -42,28 +42,31 @@
#include <string.h>
-#if !defined(STACK_ADJUST_PTR)
-/* IRIX is decidedly NON-unix */
-# if __sgi
-# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8)
-# define STACK_ADJUST_SIZE(sp,ss) ((ss) - 8)
-# elif (__i386__ && CORO_LINUX) || (_M_IX86 && CORO_LOSER)
-# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss))
-# define STACK_ADJUST_SIZE(sp,ss) (ss)
-# elif (__amd64__ && CORO_LINUX) || ((_M_AMD64 || _M_IA64) && CORO_LOSER)
-# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8)
-# define STACK_ADJUST_SIZE(sp,ss) (ss)
-# else
-# define STACK_ADJUST_PTR(sp,ss) (sp)
-# define STACK_ADJUST_SIZE(sp,ss) (ss)
-# endif
-#endif
+/*****************************************************************************/
+/* ucontext/setjmp/asm backends */
+/*****************************************************************************/
+#if CORO_UCONTEXT || CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM
-#if CORO_UCONTEXT
-# include <stddef.h>
-#endif
+# if CORO_UCONTEXT
+# include <stddef.h>
+# endif
-#if CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM
+# if !defined(STACK_ADJUST_PTR)
+# if __sgi
+/* IRIX is decidedly NON-unix */
+# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8)
+# define STACK_ADJUST_SIZE(sp,ss) ((ss) - 8)
+# elif (__i386__ && CORO_LINUX) || (_M_IX86 && CORO_LOSER)
+# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss))
+# define STACK_ADJUST_SIZE(sp,ss) (ss)
+# elif (__amd64__ && CORO_LINUX) || ((_M_AMD64 || _M_IA64) && CORO_LOSER)
+# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8)
+# define STACK_ADJUST_SIZE(sp,ss) (ss)
+# else
+# define STACK_ADJUST_PTR(sp,ss) (sp)
+# define STACK_ADJUST_SIZE(sp,ss) (ss)
+# endif
+# endif
# include <stdlib.h>
@@ -78,7 +81,7 @@ static volatile void *coro_init_arg;
static volatile coro_context *new_coro, *create_coro;
/* what we really want to detect here is wether we use a new-enough version of GAS */
-/* instead, check for gcc 3, ELF and GNU/Linux and hope for the best */
+/* with dwarf debug info. instead, check for gcc 3, ELF and GNU/Linux and hope for the best */
# if __GNUC__ >= 3 && __ELF__ && __linux__
# define HAVE_CFI 1
# endif
@@ -99,161 +102,85 @@ coro_init (void)
# if CORO_SJLJ
-static volatile int trampoline_count;
+static volatile int trampoline_done;
/* trampoline signal handler */
static void
trampoline (int sig)
{
- if (setjmp (((coro_context *)new_coro)->env))
- {
-# if HAVE_CFI
- asm (".cfi_startproc");
-# endif
+ if (
+ #if _XOPEN_UNIX > 0
+ _setjmp (new_coro->env)
+ #else
+ setjmp (new_coro->env)
+ #endif
+ ) {
+ #if HAVE_CFI
+ asm (".cfi_startproc");
+ #endif
coro_init (); /* start it */
-# if HAVE_CFI
- asm (".cfi_endproc");
-# endif
+ #if HAVE_CFI
+ asm (".cfi_endproc");
+ #endif
}
else
- trampoline_count++;
+ trampoline_done = 1;
}
# endif
-#endif
-
-#if CORO_ASM
+# if CORO_ASM
asm (
".text\n"
".globl coro_transfer\n"
".type coro_transfer, @function\n"
"coro_transfer:\n"
-# if __amd64
-# define NUM_SAVED 6
- "\tpush %rbp\n"
- "\tpush %rbx\n"
- "\tpush %r12\n"
- "\tpush %r13\n"
- "\tpush %r14\n"
- "\tpush %r15\n"
- "\tmov %rsp, (%rdi)\n"
- "\tmov (%rsi), %rsp\n"
- "\tpop %r15\n"
- "\tpop %r14\n"
- "\tpop %r13\n"
- "\tpop %r12\n"
- "\tpop %rbx\n"
- "\tpop %rbp\n"
-# elif __i386
-# define NUM_SAVED 4
- "\tpush %ebp\n"
- "\tpush %ebx\n"
- "\tpush %esi\n"
- "\tpush %edi\n"
- "\tmov %esp, (%eax)\n"
- "\tmov (%edx), %esp\n"
- "\tpop %edi\n"
- "\tpop %esi\n"
- "\tpop %ebx\n"
- "\tpop %ebp\n"
-# else
-# error unsupported architecture
-# endif
+ #if __amd64
+ #define NUM_SAVED 6
+ "\tpush %rbp\n"
+ "\tpush %rbx\n"
+ "\tpush %r12\n"
+ "\tpush %r13\n"
+ "\tpush %r14\n"
+ "\tpush %r15\n"
+ "\tmov %rsp, (%rdi)\n"
+ "\tmov (%rsi), %rsp\n"
+ "\tpop %r15\n"
+ "\tpop %r14\n"
+ "\tpop %r13\n"
+ "\tpop %r12\n"
+ "\tpop %rbx\n"
+ "\tpop %rbp\n"
+ #elif __i386
+ #define NUM_SAVED 4
+ "\tpush %ebp\n"
+ "\tpush %ebx\n"
+ "\tpush %esi\n"
+ "\tpush %edi\n"
+ "\tmov %esp, (%eax)\n"
+ "\tmov (%edx), %esp\n"
+ "\tpop %edi\n"
+ "\tpop %esi\n"
+ "\tpop %ebx\n"
+ "\tpop %ebp\n"
+ #else
+ #error unsupported architecture
+ #endif
"\tret\n"
);
-#endif
-
-#if 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 *
-trampoline (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);
-}
-
-void
-coro_destroy (coro_context *ctx)
-{
- if (!pthread_equal (ctx->id, null_tid))
- {
- pthread_cancel (ctx->id);
- pthread_mutex_unlock (&coro_mutex);
- pthread_join (ctx->id, 0);
- pthread_mutex_lock (&coro_mutex);
- }
-
- pthread_cond_destroy (&ctx->cv);
-}
-
-#endif
+# endif
-/* initialize a machine state */
void
coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssize)
{
-#if CORO_UCONTEXT
-
- if (!coro)
- return;
-
- getcontext (&(ctx->uc));
-
- ctx->uc.uc_link = 0;
- ctx->uc.uc_stack.ss_sp = STACK_ADJUST_PTR (sptr,ssize);
- ctx->uc.uc_stack.ss_size = (size_t)STACK_ADJUST_SIZE (sptr,ssize);
- ctx->uc.uc_stack.ss_flags = 0;
-
- makecontext (&(ctx->uc), (void (*)())coro, 1, arg);
-
-#elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX || CORO_ASM
-
+ coro_context nctx;
# if CORO_SJLJ
stack_t ostk, nstk;
struct sigaction osa, nsa;
sigset_t nsig, osig;
# endif
- coro_context nctx;
if (!coro)
return;
@@ -292,11 +219,11 @@ coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssiz
abort ();
}
- trampoline_count = 0;
+ trampoline_done = 0;
kill (getpid (), SIGUSR2);
sigfillset (&nsig); sigdelset (&nsig, SIGUSR2);
- while (!trampoline_count)
+ while (!trampoline_done)
sigsuspend (&nsig);
sigaltstack (0, &nstk);
@@ -312,46 +239,45 @@ coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssiz
sigaltstack (&ostk, 0);
sigaction (SIGUSR2, &osa, 0);
-
sigprocmask (SIG_SETMASK, &osig, 0);
# elif CORO_LOSER
setjmp (ctx->env);
-#if __CYGWIN__
- ctx->env[7] = (long)((char *)sptr + ssize) - sizeof (long);
- ctx->env[8] = (long)coro_init;
-#elif defined(_M_IX86)
- ((_JUMP_BUFFER *)&ctx->env)->Eip = (long)coro_init;
- ((_JUMP_BUFFER *)&ctx->env)->Esp = (long)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
-#elif defined(_M_AMD64)
- ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64)coro_init;
- ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
-#elif defined(_M_IA64)
- ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64)coro_init;
- ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
-#else
-# error "microsoft libc or architecture not supported"
-#endif
+ #if __CYGWIN__
+ ctx->env[7] = (long)((char *)sptr + ssize) - sizeof (long);
+ ctx->env[8] = (long)coro_init;
+ #elif defined(_M_IX86)
+ ((_JUMP_BUFFER *)&ctx->env)->Eip = (long)coro_init;
+ ((_JUMP_BUFFER *)&ctx->env)->Esp = (long)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
+ #elif defined(_M_AMD64)
+ ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64)coro_init;
+ ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
+ #elif defined(_M_IA64)
+ ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64)coro_init;
+ ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
+ #else
+ #error "microsoft libc or architecture not supported"
+ #endif
# elif CORO_LINUX
_setjmp (ctx->env);
-#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP)
- ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init;
- ctx->env[0].__jmpbuf[JB_SP] = (long)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
-#elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__)
- ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init;
- ctx->env[0].__jmpbuf[0].__sp = (int *)((char *)sptr + ssize) - sizeof (long);
-#elif defined (__GNU_LIBRARY__) && defined (__i386__)
- ctx->env[0].__jmpbuf[0].__pc = (char *)coro_init;
- ctx->env[0].__jmpbuf[0].__sp = (void *)((char *)sptr + ssize) - sizeof (long);
-#elif defined (__GNU_LIBRARY__) && defined (__amd64__)
- ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init;
- ctx->env[0].__jmpbuf[0].__sp = (void *)((char *)sptr + ssize) - sizeof (long);
-#else
-# error "linux libc or architecture not supported"
-#endif
+ #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (JB_PC) && defined (JB_SP)
+ ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init;
+ ctx->env[0].__jmpbuf[JB_SP] = (long)STACK_ADJUST_PTR (sptr, ssize) - sizeof (long);
+ #elif __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined (__mc68000__)
+ ctx->env[0].__jmpbuf[0].__aregs[0] = (long int)coro_init;
+ ctx->env[0].__jmpbuf[0].__sp = (int *)((char *)sptr + ssize) - sizeof (long);
+ #elif defined (__GNU_LIBRARY__) && defined (__i386__)
+ ctx->env[0].__jmpbuf[0].__pc = (char *)coro_init;
+ ctx->env[0].__jmpbuf[0].__sp = (void *)((char *)sptr + ssize) - sizeof (long);
+ #elif defined (__GNU_LIBRARY__) && defined (__amd64__)
+ ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init;
+ ctx->env[0].__jmpbuf[0].__sp = (void *)((char *)sptr + ssize) - sizeof (long);
+ #else
+ #error "linux libc or architecture not supported"
+ #endif
# elif CORO_IRIX
@@ -366,12 +292,77 @@ coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssiz
*--ctx->sp = (void *)coro_init;
ctx->sp -= NUM_SAVED;
+# 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 ((coro_context *)create_coro, (coro_context *)new_coro);
+ coro_transfer (create_coro, new_coro);
+}
+
+#endif
+
+/*****************************************************************************/
+/* pthread backend */
+/*****************************************************************************/
+
+#if CORO_PTHREAD
-# 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);
+}
+
+void
+coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssize)
+{
static coro_context nctx;
static int once;
@@ -399,15 +390,27 @@ coro_create (coro_context *ctx, coro_func coro, void *arg, void *sptr, long ssiz
pthread_attr_init (&attr);
pthread_attr_setstack (&attr, sptr, (size_t)ssize);
pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
- pthread_create (&ctx->id, &attr, trampoline, &args);
+ pthread_create (&ctx->id, &attr, coro_init, &args);
coro_transfer (args.main, args.self);
}
else
ctx->id = null_tid;
+}
-#else
-# error unsupported backend
-#endif
+void
+coro_destroy (coro_context *ctx)
+{
+ if (!pthread_equal (ctx->id, null_tid))
+ {
+ pthread_cancel (ctx->id);
+ pthread_mutex_unlock (&coro_mutex);
+ pthread_join (ctx->id, 0);
+ pthread_mutex_lock (&coro_mutex);
+ }
+
+ pthread_cond_destroy (&ctx->cv);
}
+#endif
+
diff --git a/coro.h b/coro.h
index 2a907b0..45c8e92 100644
--- a/coro.h
+++ b/coro.h
@@ -62,6 +62,9 @@
* introduce coro_destroy, which is a nop except for pthreads.
* speed up CORO_PTHREAD. Do no longer leak threads either.
* coro_create now allows one to create source coro_contexts.
+ * do not rely on makecontext passing a void * correctly.
+ * try harder to get _setjmp/_longjmp.
+ * major code cleanup/restructuring.
*/
#ifndef CORO_H
@@ -220,16 +223,20 @@ struct coro_context {
# define _GNU_SOURCE /* for linux libc */
# endif
+# if !CORO_LOSER
+# include <unistd.h>
+# endif
+
# include <setjmp.h>
struct coro_context {
jmp_buf env;
};
-# if CORO_LINUX || (_XOPEN_SOURCE >= 600)
+# if _XOPEN_UNIX > 0
# define coro_transfer(p,n) do { if (!_setjmp ((p)->env)) _longjmp ((n)->env, 1); } while (0)
# else
-# define coro_transfer(p,n) do { if (!setjmp ((p)->env)) longjmp ((n)->env, 1); } while (0)
+# define coro_transfer(p,n) do { if (! setjmp ((p)->env)) longjmp ((n)->env, 1); } while (0)
# endif
# define coro_destroy(ctx) (void *)(ctx)