--- libcoro/coro.h 2001/07/23 17:13:08 1.1 +++ libcoro/coro.h 2006/10/26 07:27:50 1.15 @@ -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: @@ -30,50 +30,149 @@ * go to Ralf S. Engelschall . * * This coroutine library is very much stripped down. You should either - * build your own process avstraction using it or - better - just use GNU + * build your own process abstraction using it or - better - just use GNU * Portable Threads, http://www.gnu.org/software/pth/. + * + */ + +/* + * 2006-10-26 Include stddef.h on OS X to work around one of its bugs. + * Reported by Michael_G_Schwern. */ #ifndef CORO_H #define CORO_H +#define CORO_VERSION 2 + +/* + * Changes since API version 1: + * replaced bogus -DCORO_LOOSE with gramatically more correct -DCORO_LOSER + */ + +/* + * This library consists of only three files + * coro.h, coro.c and LICENSE (and optionally README) + * + * It implements what is known as coroutines, in a hopefully + * portable way. At the moment you have to define which kind + * of implementation flavour you want: + * + * -DCORO_UCONTEXT + * + * This flavour uses SUSv2's get/set/swap/makecontext functions that + * unfortunately only newer unices support. + * Use this for GNU/Linux + glibc-2.2.3 and possibly higher. + * + * -DCORO_SJLJ + * + * This flavour uses SUSv2's setjmp/longjmp and sigaltstack functions to + * do it's job. Coroutine creation is much slower than UCONTEXT, but + * context switching is often a bit cheaper. It should work on almost + * all unices. Use this for GNU/Linux + glibc-2.2. glibc-2.1 and below + * do not work with any sane model (neither sigaltstack nor context + * functions are implemented) + * + * -DCORO_LINUX + * + * Old GNU/Linux systems (<= glibc-2.1) work with this implementation + * (it is very fast and therefore recommended over other methods). + * + * -DCORO_LOSER + * + * Microsoft's highly proprietary platform doesn't support sigaltstack, and + * this automatically selects a suitable workaround for this platform. + * (untested) + * + * -DCORO_IRIX + * + * SGI's version of Microsoft's NT ;) + * + * If you define neither of these symbols, coro.h will try to autodetect + * the model. This currently works for CORO_LOSER only. For the other + * alternatives you should check (e.g. using autoconf) and define the + * following symbols: HAVE_UCONTEXT_H / HAVE_SETJMP_H / HAVE_SIGALTSTACK. + */ + +/* + * This is the type for the initialization function of a new coroutine. + */ typedef void (*coro_func)(void *); -#if defined(WINDOWS) -# define CORO_LOOSE 1 /* you don't win with windoze */ -#elif defined(HAVE_UCONTEXT_H) -# define CORO_UCONTEXT 1 -#elif defined(HAVE_SETJMP_H) && defined(HAVE_SIGALTSTACK) -# define CORO_SJLJ 1 -#else +/* + * A coroutine state is saved in the following structure. Treat it as a + * opaque type. errno and sigmask might be saved, but don't rely on it, + * implement your own switching primitive if you need it. + */ +typedef struct coro_context coro_context; + +/* + * This function creates a new coroutine. Apart from a pointer to an + * uninitialised coro_context, it expects a pointer to the entry function + * and the single pointer value that is given to it as argument. + * + * Allocating/deallocating the stack is your own responsibility, so there is + * no coro_destroy function. + */ +void coro_create (coro_context *ctx, + coro_func coro, void *arg, + void *sptr, long ssize); + +/* + * The following prototype defines the coroutine switching function. It is + * usually implemented as a macro, so watch out. + * +void coro_transfer(coro_context *prev, coro_context *next); + */ + +/* + * That was it. No other user-visible functions are implemented here. + */ + +/*****************************************************************************/ + +#if !defined(CORO_LOSER) && !defined(CORO_UCONTEXT) \ + && !defined(CORO_SJLJ) && !defined(CORO_LINUX) \ + && !defined(CORO_IRIX) +# if defined(WINDOWS) +# define CORO_LOSER 1 /* you don't win with windoze */ +# elif defined(__linux) && defined(__x86) +# elif defined(HAVE_UCONTEXT_H) +# define CORO_UCONTEXT 1 +# elif defined(HAVE_SETJMP_H) && defined(HAVE_SIGALTSTACK) +# define CORO_SJLJ 1 +# else error unknown or unsupported architecture +# endif #endif +/*****************************************************************************/ + #if CORO_UCONTEXT #include -typedef struct { +struct coro_context { ucontext_t uc; -} coro_context; +}; -#define coro_transfer(p,n) swapcontext(&((p)->uc), &((n)->uc)) +#define coro_transfer(p,n) swapcontext (&((p)->uc), &((n)->uc)) -#elif CORO_SJLJ || CORO_LOOSE +#elif CORO_SJLJ || CORO_LOSER || CORO_LINUX || CORO_IRIX + +#if defined(CORO_LINUX) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE // for linux libc +#endif #include -typedef struct { +struct coro_context { jmp_buf env; -} coro_context; +}; -#define coro_transfer(p,n) if (!setjmp ((p)->env)) longjmp ((n)->env, 1) +#define coro_transfer(p,n) do { if (!setjmp ((p)->env)) longjmp ((n)->env, 1); } while(0) #endif -void coro_create(coro_context *ctx, - coro_func coro, void *arg, - void *sptr, long ssize); - #endif