From 2d980f042719e6971d84c3293438b1416b16ffbe Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 18 Mar 2013 21:01:31 +0100 Subject: Mon Mar 18 21:01:31 CET 2013 --- coroutine.h | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ picohttp.c | 1 + 2 files changed, 182 insertions(+) create mode 100644 coroutine.h diff --git a/coroutine.h b/coroutine.h new file mode 100644 index 0000000..d54a718 --- /dev/null +++ b/coroutine.h @@ -0,0 +1,181 @@ +/* coroutine.h + * + * Coroutine mechanics, implemented on top of standard ANSI C. See + * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html for + * a full discussion of the theory behind this. + * + * To use these macros to define a coroutine, you need to write a + * function that looks something like this. + * + * [Simple version using static variables (scr macros)] + * int ascending (void) { + * static int i; + * + * scrBegin; + * for (i=0; i<10; i++) { + * scrReturn(i); + * } + * scrFinish(-1); + * } + * + * [Re-entrant version using an explicit context structure (ccr macros)] + * int ascending (ccrContParam) { + * ccrBeginContext; + * int i; + * ccrEndContext(foo); + * + * ccrBegin(foo); + * for (foo->i=0; foo->i<10; foo->i++) { + * ccrReturn(foo->i); + * } + * ccrFinish(-1); + * } + * + * In the static version, you need only surround the function body + * with `scrBegin' and `scrFinish', and then you can do `scrReturn' + * within the function and on the next call control will resume + * just after the scrReturn statement. Any local variables you need + * to be persistent across an `scrReturn' must be declared static. + * + * In the re-entrant version, you need to declare your persistent + * variables between `ccrBeginContext' and `ccrEndContext'. These + * will be members of a structure whose name you specify in the + * parameter to `ccrEndContext'. + * + * The re-entrant macros will malloc() the state structure on first + * call, and free() it when `ccrFinish' is reached. If you want to + * abort in the middle, you can use `ccrStop' to free the state + * structure immediately (equivalent to an explicit return() in a + * caller-type routine). + * + * A coroutine returning void type may call `ccrReturnV', + * `ccrFinishV' and `ccrStopV', or `scrReturnV', to avoid having to + * specify an empty parameter to the ordinary return macros. + * + * Ground rules: + * - never put `ccrReturn' or `scrReturn' within an explicit `switch'. + * - never put two `ccrReturn' or `scrReturn' statements on the same + * source line. + * + * The caller of a static coroutine calls it just as if it were an + * ordinary function: + * + * void main(void) { + * int i; + * do { + * i = ascending(); + * printf("got number %d\n", i); + * } while (i != -1); + * } + * + * The caller of a re-entrant coroutine must provide a context + * variable: + * + * void main(void) { + * ccrContext z = 0; + * do { + * printf("got number %d\n", ascending (&z)); + * } while (z); + * } + * + * Note that the context variable is set back to zero when the + * coroutine terminates (by crStop, or by control reaching + * crFinish). This can make the re-entrant coroutines more useful + * than the static ones, because you can tell when they have + * finished. + * + * If you need to dispose of a crContext when it is non-zero (that + * is, if you want to stop calling a coroutine without suffering a + * memory leak), the caller should call `ccrAbort(ctx)' where `ctx' + * is the context variable. + * + * This mechanism could have been better implemented using GNU C + * and its ability to store pointers to labels, but sadly this is + * not part of the ANSI C standard and so the mechanism is done by + * case statements instead. That's why you can't put a crReturn() + * inside a switch() statement. + */ + +/* + * coroutine.h is copyright 1995,2000 Simon Tatham. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef COROUTINE_H +#define COROUTINE_H + +#include + +/* + * `scr' macros for static coroutines. + */ + +#define scrBegin static int scrLine = 0; switch(scrLine) { case 0:; +#define scrFinish(z) } return (z) +#define scrFinishV } return + +#define scrReturn(z) \ + do {\ + scrLine=__LINE__;\ + return (z); case __LINE__:;\ + } while (0) +#define scrReturnV \ + do {\ + scrLine=__LINE__;\ + return; case __LINE__:;\ + } while (0) + +/* + * `ccr' macros for re-entrant coroutines. + */ + +#define ccrContParam void **ccrParam + +#define ccrBeginContext struct ccrContextTag { int ccrLine +#define ccrEndContext(x) } *x = (struct ccrContextTag *)*ccrParam + +#define ccrBegin(x) if(!x) {x= *ccrParam=malloc(sizeof(*x)); x->ccrLine=0;}\ + if (x) switch(x->ccrLine) { case 0:; +#define ccrFinish(z) } free(*ccrParam); *ccrParam=0; return (z) +#define ccrFinishV } free(*ccrParam); *ccrParam=0; return + +#define ccrReturn(z) \ + do {\ + ((struct ccrContextTag *)*ccrParam)->ccrLine=__LINE__;\ + return (z); case __LINE__:;\ + } while (0) +#define ccrReturnV \ + do {\ + ((struct ccrContextTag *)*ccrParam)->ccrLine=__LINE__;\ + return; case __LINE__:;\ + } while (0) + +#define ccrStop(z) do{ free(*ccrParam); *ccrParam=0; return (z); }while(0) +#define ccrStopV do{ free(*ccrParam); *ccrParam=0; return; }while(0) + +#define ccrContext void * +#define ccrAbort(ctx) do { free (ctx); ctx = 0; } while (0) + +#endif /* COROUTINE_H */ diff --git a/picohttp.c b/picohttp.c index e3762f1..7e56de1 100644 --- a/picohttp.c +++ b/picohttp.c @@ -53,6 +53,7 @@ static size_t picohttp_fmt_int(char *dest,int i) { return picohttp_fmt_uint(dest, i); } #else +#include #define picohttp_fmt_uint fmt_ulong #define picohttp_fmt_int fmt_long #endif -- cgit v1.2.3