Re: Continuations/coroutines in UNIX98 standard
"Chris Double" <[email protected]> Mon, 7 Oct 2002 22:28:25 UT
| Newsgroups | gmane.comp.lang.goo.general |
|---|---|
| Message-ID | <[email protected]> |
On Mon, 7 Oct 2002 14:45:39 -0700 (PDT), "Avi Bryant" <[email protected]> said: > But these are only one-shot continuations, right? Is there any way to > copy a Fiber? Yes, Fiber's are only one shot continuations and cannot be copied. The trick that 'Io' uses could probably do multi-shot continuations by copying the stack since full control/allocation of the stack is up to the programmer. Here's a paste of the code to create the coroutine: -----------8<-------------- /* This is the system dependent function. * Setup a jmp_buf so when it is longjmp'ed it will invoke 'func' using 'stack'. * ('func' will not (and mustn't) return!) */ static void setup_jmpbuf(jmp_buf buf, void *func, void *stack, size_t stacksize) { setjmp(buf); #ifdef _BSD_PPC_SETJMP_H_ /* ppc-os-x */ #define setjmp _setjmp /* no need for signal masks */ #define longjmp _longjmp memset(stack+stacksize-64, 0, 64); /* very crude... */ buf[0] = ((int)stack + stacksize - 64 + 15) & ~15; buf[21] = (int)func; #elif JB_SP /* x86-linux with glibc2 */ buf->__jmpbuf[JB_SP] = (int)stack + stacksize; buf->__jmpbuf[JB_PC] = (int)func; #elif defined(_I386_JMP_BUF_H) /* x86-linux with libc5 */ buf->__sp = stackend; buf->__pc = func; #elif defined(__CYGWIN__) /* win32 */ buf[7] = (int)(stack + stacksize); buf[8] = (int)func; #elif defined(__SYMBIAN32__) buf[0] = 0; buf[1] = 0; buf[2] = 0; buf[3] = (unsigned int)stack + SCHEDULER_STACKSIZE - 64; buf[9] = (int)func; buf[8] = buf[3] + 32; #endif #if 0 /* untested... */ /* m68k-linux with glibc2 */ buf->__jmpbuf->__sp = stackend; buf->__jmpbuf->__aregs[0] = (long)func; #endif } Coro *Scheduler_createCoro(Scheduler *self, void *aContext, void (*func)(void *)) { Coro *th; if (self->nr_free) th = self->freeCoros[--self->nr_free]; else th = malloc(sizeof(*th) + SCHEDULER_STACKSIZE); /* setjmp/longjmp is flakey under Symbian. If the setjmp is done inside the setup_jmpbuf call then a crash occurs. inlining it here solves the problem */ #if !defined(__SYMBIAN32__) setup_jmpbuf(th->env, start, th + 1, SCHEDULER_STACKSIZE); #else setjmp(th->env); th->env[0] = 0; th->env[1] = 0; th->env[2] = 0; th->env[3] = (unsigned int)(th + 1) + SCHEDULER_STACKSIZE - 64; th->env[9] = (int)start; th->env[8] = th->env[3] + 32; #endif /* insert after currentCoro */ th->next = self->currentCoro->next; th->prev = self->currentCoro; th->next->prev = th; th->prev->next = th; self->coroCount++; self->start_func = func; self->context = aContext; Scheduler_yield(self); return th; } void Scheduler_yield(Scheduler *self) { #if defined(__SYMBIAN32) ProcessUIEvent(); #endif if (setjmp(self->currentCoro->env) == 0) { self->currentCoro = self->currentCoro->next; longjmp(self->currentCoro->env, 1); } } -----------8<-------------- Chris. -- Chris Double [email protected]