[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