[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Continuations/coroutines in UNIX98 standard
On Mon, 7 Oct 2002 14:45:39 -0700 (PDT), "Avi Bryant" <avi@beta4.com>
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
chris.double@double.co.nz