// portable coroutine implementation (sketch)
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
jmp_buf contexts[2];
int cid = 0; // coroutine id
void printsp()
{
int x;
printf("stack pointer = %p\n", &x);
}
// execute the func on the specified stack
void exec_on_altstack(void *stkbase, size_t stksz, void (*func)())
{
size_t diff = (void*)&diff - stkbase - stksz;
// allocate a dummy local variable to change the stack pointer
char dummy[diff];
dummy[0] = '\0'; // don't remove dummy, optimizer
(*func)();
}
// context switch
void csw(int target) {
if (_setjmp(contexts[cid]) == 0) {
printf("# coroutine[%d] context saved\n", cid);
cid = target;
_longjmp(contexts[target], 1);
} else {
printf("# coroutine[%d] resumes\n", cid);
}
}
void test() {
printf("test started\n");
printsp();
csw(0);
printf("test resumed\n");
csw(0);
printf("test resumed2\n");
csw(0);
}
extern int main(int argc, char **argv)
{
printsp();
size_t stksz = 4096;
void *stkbase = malloc(stksz);
printf("allocated stack = %p to %p\n", stkbase, stkbase + stksz - 1);
if (_setjmp(contexts[cid]) == 0) {
cid = 1;
exec_on_altstack(stkbase, stksz, test);
} else {
printf("main started\n");
csw(1);
printf("main resumed\n");
csw(1);
printf("main resumed2\n");
}
return 0;
}
/* executed on OSX 10.10.4
~/stacktest% ./a.out
stack pointer = 0x7fff5917492c
allocated stack = 0x7feb08804200 to 0x7feb088051ff
test started
stack pointer = 0x7feb088051bc
# coroutine[1] context saved
main started
# coroutine[0] context saved
# coroutine[1] resumes
test continued
# coroutine[1] context saved
# coroutine[0] resumes
main resumed
# coroutine[0] context saved
# coroutine[1] resumes
test continued2
# coroutine[1] context saved
# coroutine[0] resumes
main resumed2
*/