#include #include /* co-routines in (gnu) c inspired by http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html instead of using an offet to a jump table, it's possible to use an offset to a code label in GNU C labels as values are defined here: http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html like sgtathams code, we store an offset to jump back into the function but we use a direct jmp instead of an internal jump table. */ /* the preprocessor works in mysterious ways */ #define __NAME__ __LABEL__(__LINE__) #define __LABEL__(x) __LABEL2__(x) #define __LABEL2__(x) __next##__##x typedef unsigned int __offset__; #define CORO_STRUCT(x) typedef struct {__offset__ __state__; struct x;} #define CORO_MALLOC(t,cr) \ t *cr = malloc(sizeof(t));\ cr -> __state__ = 0 #define CORO_STATIC(cr,t,in) \ static t (cr) = {0,in}; \ CORO_INIT(cr) #define CORO_INIT(cr) \ goto *(&&__init__ + (cr).__state__); \ __init__: /* use offsets instead of label addresses, to make code relocatable */ #define YIELD(cr, ...) { \ (cr).__state__ = &&__NAME__ - &&__init__; \ return __VA_ARGS__; \ } __NAME__: /* possible cleanup code */ #define FAIL(cr) {} CORO_STRUCT({int i;}) foo_cr; /* example coroutine */ int foo_static() { CORO_STATIC(cr,foo_cr, {10}); while (cr.i--) { YIELD(cr,cr.i); } return 0; } int foo_dynamic(foo_cr *cr) { CORO_INIT(*cr); cr->i = 9; while ((cr->i)--) { YIELD(*cr,cr->i); } return 0; } int main () { int a; while (1) { a = foo_static(); if (a <= 0) break; printf("-%d\n",a); } CORO_MALLOC(foo_cr,cr); while (1) { a = foo_dynamic(cr); if (a <= 0) break; printf("%d\n",a); } free(cr); return 0; }