Skip to content

Instantly share code, notes, and snippets.

@jsn
Created July 26, 2010 21:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsn/491302 to your computer and use it in GitHub Desktop.
Save jsn/491302 to your computer and use it in GitHub Desktop.
*.o
main
tags
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include "coro.h"
struct state {
struct state *next, *prev ;
jmp_buf jmp ;
void *saved, *start ;
size_t len, used ;
} ;
static int stack_dir ;
static struct state zero = {&zero, &zero}, *current = &zero ;
static void *cont ;
static int check_stack(void *p) { return (char *)&p - (char *)p > 0 ? 1 : -1 ; }
static int coro_save(void) {
void *p ;
if (!stack_dir) stack_dir = check_stack(&p) ;
current->used = abs((char *)current->start - (char *)&p) + sizeof(p) ;
p = stack_dir < 0 ? &p : current->start ;
if (current->len < current->used) {
if (current->saved) free(current->saved) ;
current->len = current->used + 512 ;
current->saved = malloc(current->len) ;
}
memcpy(current->saved, p, current->used) ;
if (setjmp(current->jmp)) {
memcpy(cont, current->saved, current->used) ;
cont = NULL ;
return 1 ;
}
return 0 ;
}
static void coro_restore(void) {
cont = (stack_dir > 0) ?
current->start :
(char *)current->start - current->used + sizeof(void *) ;
longjmp(current->jmp, 1) ;
}
void coro_start(coro f, int hint) {
if (
(!current->start) ||
((char *)current->start - (char *)hint) * stack_dir < 0
)
current->start = &hint ;
if (coro_save() == 0) {
struct state * tmp = calloc(sizeof(*tmp), 1) ;
tmp->next = current ;
tmp->prev = current->prev ;
tmp->next->prev = tmp->prev->next = tmp ;
tmp->start = &hint ;
current = tmp ;
f(hint) ;
tmp->prev->next = tmp->next ;
tmp->next->prev = tmp->prev ;
current = tmp->next ;
if (tmp->saved) free(tmp->saved) ;
free(tmp) ;
coro_restore() ;
printf("notreached\n") ;
return ;
}
}
void coro_yield(void) {
if (coro_empty() || coro_save()) return ;
current = current->next ;
coro_restore() ;
}
int coro_empty(void) {
return current == current->next ;
}
#ifndef __CORO_H__
#define __CORO_H__
typedef void (*coro)(int hint) ;
void coro_start(coro f, int hint) ;
void coro_yield(void) ;
int coro_empty(void) ;
#endif /* __CORO_H__ */
#include <stdio.h>
#include "coro.h"
void f2(int hint) {
int i ;
printf("started %d\n", hint) ;
for (i = 0; i < hint; i ++) {
printf("f2: %d (%d)\n", i, hint) ;
coro_yield() ;
}
printf("ended %d\n", hint) ;
}
void f1(int hint) {
int i ;
for (i = 0; i < hint; i ++) {
coro_yield() ;
printf("f1: %d (%d)\n", i + 3, hint) ;
coro_start(f2, i + 3) ;
coro_yield() ;
}
}
int main(int ac, const char *av[]) {
coro_start(f1, 3) ;
coro_start(f2, 12) ;
while(!coro_empty()) coro_yield() ;
return 0 ;
}
CFLAGS = -Wall -O3 -fomit-frame-pointer
OBJS = coro.o
HEADERS = coro.h
LIBS =
TOPLEVEL = tags main
all: $(TOPLEVEL)
tags: $(OBJS) $(HEADERS)
ctags *.[chl] || echo no ctags, who cares
main: main.c $(OBJS)
$(CC) $(CFLAGS) -o $@ $< $(OBJS) $(LIBS)
$(OBJS): $(HEADERS)
clean:
rm -f $(OBJS) $(TOPLEVEL)
stats: clean
echo `cat *.[chl] | wc -l` lines, \
`cat *.[chl] | grep -v '^ *$$' | grep -v '^ */[\*/]' | wc -l` loc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment