--- libcoro/coro.c 2001/09/03 02:50:18 1.5 +++ libcoro/coro.c 2007/04/27 19:35:28 1.26 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Marc Alexander Lehmann + * Copyright (c) 2001-2006 Marc Alexander Lehmann * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: @@ -32,21 +32,47 @@ #include "coro.h" -#if CORO_SJLJ || CORO_LOOSE || CORO_LINUX || CORO_IRIX - +#if !defined(STACK_ADJUST_PTR) /* IRIX is decidedly NON-unix */ -#if __sgi -# define STACK_ADJUST(sp,ss) ((ss) - sizeof (long) + (char *)(sp)) -#else -# define STACK_ADJUST(sp,ss) (ss) +# if __sgi +# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss) - 8) +# define STACK_ADJUST_SIZE(sp,ss) ((ss) - 8) +# elif __i386__ && CORO_LINUX +# define STACK_ADJUST_PTR(sp,ss) ((char *)(sp) + (ss)) +# define STACK_ADJUST_SIZE(sp,ss) (ss) +# elif __amd64__ && CORO_LINUX +# 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 +#if CORO_UCONTEXT +# include +#endif + +#if CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX + +#include + +#if CORO_SJLJ +# include +# include +# include +#endif static volatile coro_func coro_init_func; 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 and ELF and hope for the best */ +#if __GNUC__ >= 3 && __ELF__ +# define HAVE_CFI 1 +#endif + static void coro_init (void) { @@ -67,10 +93,18 @@ /* trampoline signal handler */ static void -trampoline(int sig) +trampoline (int sig) { if (setjmp (((coro_context *)new_coro)->env)) - coro_init (); /* start it */ + { +#if HAVE_CFI + asm (".cfi_startproc"); +#endif + coro_init (); /* start it */ +#if HAVE_CFI + asm (".cfi_endproc"); +#endif + } else trampoline_count++; } @@ -80,22 +114,22 @@ #endif /* initialize a machine state */ -void coro_create(coro_context *ctx, - coro_func coro, void *arg, - void *sptr, long ssize) +void coro_create (coro_context *ctx, + coro_func coro, void *arg, + void *sptr, long ssize) { #if CORO_UCONTEXT getcontext (&(ctx->uc)); ctx->uc.uc_link = 0; - ctx->uc.uc_stack.ss_sp = STACK_ADJUST(sptr,ssize); - ctx->uc.uc_stack.ss_size = (size_t) ssize; + 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_LOOSE || CORO_LINUX || CORO_IRIX +#elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX # if CORO_SJLJ stack_t ostk, nstk; @@ -122,15 +156,21 @@ nsa.sa_flags = SA_ONSTACK; if (sigaction (SIGUSR2, &nsa, &osa)) - perror ("sigaction"); + { + perror ("sigaction"); + abort (); + } /* set the new stack */ - nstk.ss_sp = STACK_ADJUST(sptr,ssize); /* yes, some platforms (IRIX) get this wrong. */ - nstk.ss_size = ssize; + nstk.ss_sp = STACK_ADJUST_PTR (sptr,ssize); /* yes, some platforms (IRIX) get this wrong. */ + nstk.ss_size = STACK_ADJUST_SIZE (sptr,ssize); nstk.ss_flags = 0; if (sigaltstack (&nstk, &ostk) < 0) - perror ("sigaltstack"); + { + perror ("sigaltstack"); + abort (); + } trampoline_count = 0; kill (getpid (), SIGUSR2); @@ -151,30 +191,44 @@ if (~ostk.ss_flags & SS_DISABLE) sigaltstack (&ostk, 0); - sigaction (SIGUSR1, &osa, 0); + sigaction (SIGUSR2, &osa, 0); sigprocmask (SIG_SETMASK, &osig, 0); -# elif CORO_LOOSE +# elif CORO_LOSER setjmp (ctx->env); - ctx->env[7] = (int)((char *)sptr + ssize); - ctx->env[8] = (int)coro_init; +#if __CYGWIN__ + ctx->env[7] = (long)((char *)sptr + ssize); + 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); +#elif defined(_M_AMD64) + ((_JUMP_BUFFER *)&ctx->env)->Rip = (__int64)coro_init; + ((_JUMP_BUFFER *)&ctx->env)->Rsp = (__int64)STACK_ADJUST_PTR (sptr,ssize); +#elif defined(_M_IA64) + ((_JUMP_BUFFER *)&ctx->env)->StIIP = (__int64)coro_init; + ((_JUMP_BUFFER *)&ctx->env)->IntSp = (__int64)STACK_ADJUST_PTR (sptr,ssize); +#else +#error "microsoft libc or architecture not supported" +#endif # elif CORO_LINUX - setjmp (ctx->env); -#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(JB_PC) && defined(JB_SP) - ctx->env[0].__jmpbuf[JB_PC] = (int)coro_init; - ctx->env[0].__jmpbuf[JB_SP] = (int)((char *)sptr + ssize); -#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) \ - && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 0 && defined(__mc68000__) + _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); +#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); -#elif defined(__GNU_LIBRARY__) && defined(__i386__) +#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); +#elif defined (__GNU_LIBRARY__) && defined (__amd64__) + ctx->env[0].__jmpbuf[JB_PC] = (long)coro_init; + ctx->env[0].__jmpbuf[JB_RSP] = (long)STACK_ADJUST_PTR (sptr, ssize); #else #error "linux libc or architecture not supported" #endif @@ -182,8 +236,8 @@ # elif CORO_IRIX setjmp (ctx->env); - ctx->env[JB_PC] = (int)coro_init; - ctx->env[JB_SP] = (int)((char *)sptr + ssize); + ctx->env[JB_PC] = (__uint64_t)coro_init; + ctx->env[JB_SP] = (__uint64_t)STACK_ADJUST_PTR (sptr, ssize); # endif