Skip to content

Instantly share code, notes, and snippets.

@mintisan
Created April 19, 2015 12:00
Show Gist options
  • Save mintisan/4a3b599b559ae82194e3 to your computer and use it in GitHub Desktop.
Save mintisan/4a3b599b559ae82194e3 to your computer and use it in GitHub Desktop.
Tony Finch - Coroutines in less than 20 lines of standard C
/**
* From
* http://fanf.livejournal.com/105413.html
**/
#include <stddef.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#define MAXTHREAD 5
static void *coarg;
void *coto(jmp_buf here, jmp_buf there, void *arg) {
coarg = arg;
if (setjmp(here)) return(coarg);
longjmp(there, 1);
}
#define STACKDIR - // set to + for upwards and - for downwards
#define STACKSIZE (1<<12)
static char *tos; // top of stack
void *cogo(jmp_buf here, void (*fun)(void*), void *arg) {
if (tos == NULL) tos = (char*)&arg;
tos += STACKDIR STACKSIZE;
char n[STACKDIR (tos - (char*)&arg)];
coarg = n; // ensure optimizer keeps n
if (setjmp(here)) return(coarg);
fun(arg);
abort();
}
static jmp_buf thread[MAXTHREAD];
static int count = 0;
static void comain(void *arg) {
int *p = arg, i = *p;
for (;;) {
printf("coroutine %d at %p arg %p\n", i, (void*)&i, arg);
int n = arc4random() % count;
printf("jumping to %d\n", n);
arg = coto(thread[i], thread[n], (char*)arg + 1);
}
}
int main(void) {
while (++count < MAXTHREAD) {
printf("spawning %d\n", count);
cogo(thread[0], comain, &count);
}
return 0;
}
@mintisan
Copy link
Author

Result:

/Users/linjinhui/Library/Caches/clion10/cmake/generated/e2a0a57b/e2a0a57b/Debug/Coroutine
spawning 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a060
jumping to 0
spawning 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a060
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a061
jumping to 0
spawning 3
coroutine 3 at 0x7fff5f673b4c arg 0x10058a060
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a061
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a062
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a063
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a064
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a065
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a066
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a067
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a068
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a069
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a06a
jumping to 0
spawning 4
coroutine 4 at 0x7fff5f672b4c arg 0x10058a060
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a061
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a062
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a063
jumping to 2
coroutine 2 at 0x7fff5f674b4c arg 0x10058a064
jumping to 1
coroutine 1 at 0x7fff5f675b4c arg 0x10058a065
jumping to 3
coroutine 3 at 0x7fff5f673b4c arg 0x10058a066
jumping to 0

Process finished with exit code 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment