#include #include #include "linux.h" typedef struct Jmparg Jmparg; struct Jmparg { int (*fn)(void *); void *arg; int ret; jmp_buf jmp; }; static jmp_buf stkjmp; void set9stack(void *stack) { Jmparg *x; if(!(x = (Jmparg*)setjmp(stkjmp))){ if(stack) stkjmp[JMPBUFSP] = (ulong)stack - 16; return; } DPRINT("now in 9stack from x=0x%p pc=0x%lux sp=0x%lux...\n", x, x->jmp[JMPBUFPC], x->jmp[JMPBUFSP]); x->ret = x->fn(x->arg); DPRINT("jumping back from 9stack to x=0x%p pc=0x%lux sp=0x%lux...\n", x, x->jmp[JMPBUFPC], x->jmp[JMPBUFSP]); longjmp(x->jmp, (int)x); abort(); } int do9stack(int (*fn)(void *), void *arg) { Jmparg a; a.fn = fn; a.arg = arg; if(!setjmp(a.jmp)){ longjmp(stkjmp, (int)&a); abort(); } return a.ret; } typedef struct Args Args; struct Args { int flags; int stacksize; void (*fn)(void *); void *arg; }; static int _freeandexitxproc(void *aux) { free(aux); exits(0); return 0; } static void _exitxproc(void) { ulong *p; ulong *top, *bot; p = (ulong*)&p; p += 2; if(memcmp(p, "STACKBOT", 8) != 0) abort(); p += 2; bot = p; top = (ulong*)*bot; if(memcmp(&top[1], "STACKTOP", 8) != 0) abort(); if(*bot != (ulong)top) abort(); if(*top != (ulong)bot) abort(); do9stack(_freeandexitxproc, top); } static int _createxproc(void *aux) { int pid; Args a, *x; x = aux; /* * need to have a deep copy on stack because x will * go away if parent returns after rfork. */ memcpy(&a, x, sizeof(a)); pid = rfork(a.flags); if(pid < 0) return pid; if(pid == 0){ jmp_buf jmp; int n; ulong *top, *bot, *p; n = a.stacksize + (4 + 8) * 2; top = malloc(n); bot = (ulong*)((uchar*)top + n - 4); *top = (ulong)bot; *bot = (ulong)top; memcpy(&top[1], "STACKTOP", 8); p = bot; p -= 2; memcpy(p, "STACKBOT", 8); *--p = (ulong)a.arg; *--p = (ulong)_exitxproc; *--p = 0; jmp[JMPBUFSP] = (ulong)p; jmp[JMPBUFPC] = (ulong)a.fn; longjmp(jmp, 1); abort(); } return pid; } int createxproc(void (*fn)(void *), void *arg, int flags, int stacksize) { Args a; a.fn = fn; a.arg = arg; a.flags = flags; a.stacksize = stacksize; return do9stack(_createxproc, &a); }