Exemple #1
0
/*
 *  call-seq:
 *     fiber.resume(args, ...) -> obj
 *
 *  Resumes the fiber from the point at which the last <code>Fiber.yield</code>
 *  was called, or starts running it if it is the first call to
 *  <code>resume</code>. Arguments passed to resume will be the value of
 *  the <code>Fiber.yield</code> expression or will be passed as block
 *  parameters to the fiber's block if this is the first <code>resume</code>.
 *
 *  Alternatively, when resume is called it evaluates to the arguments passed
 *  to the next <code>Fiber.yield</code> statement inside the fiber's block
 *  or to the block value if it runs to completion without any
 *  <code>Fiber.yield</code>
 */
static mrb_value
fiber_resume(mrb_state *mrb, mrb_value self)
{
  struct mrb_context *c = fiber_check(mrb, self);
  mrb_value *a;
  int len;
  mrb_callinfo *ci;

  for (ci = c->ci; ci >= c->cibase; ci--) {
    if (ci->acc < 0) {
      mrb_raise(mrb, E_ARGUMENT_ERROR, "can't cross C function boundary");
    }
  }
  if (c->status == MRB_FIBER_RESUMED) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "double resume");
  }
  if (c->status == MRB_FIBER_TERMINATED) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead fiber");
  }
  mrb_get_args(mrb, "*", &a, &len);
  mrb->c->status = MRB_FIBER_RESUMED;
  if (c->status == MRB_FIBER_CREATED) {
    mrb_value *b = c->stack+1;
    mrb_value *e = b + len;

    while (b<e) {
      *b++ = *a++;
    }
    c->cibase->argc = len;
    c->prev = mrb->c;
    if (c->prev->fib) 
      mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
    mrb_write_barrier(mrb, (struct RBasic*)c->fib);
    c->status = MRB_FIBER_RUNNING;
    mrb->c = c;

    MARK_CONTEXT_MODIFY(c);
    return c->ci->proc->env->stack[0];
  }
  MARK_CONTEXT_MODIFY(c);
  c->prev = mrb->c;
  if (c->prev->fib) 
    mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
  c->status = MRB_FIBER_RUNNING;
  mrb->c = c;
  return fiber_result(mrb, a, len);
}
Exemple #2
0
/*
 *  call-seq:
 *     fiber.transfer(args, ...) -> obj
 *
 *  Transfers control to receiver fiber of the method call.
 *  Unlike <code>resume</code> the receiver wouldn't be pushed to call
 * stack of fibers. Instead it will switch to the call stack of
 * transferring fiber.
 *  When resuming a fiber that was transferred to another fiber it would
 * cause double resume error. Though when the fiber is re-transferred
 * and <code>Fiber.yield</code> is called, the fiber would be resumable.
 */
static mrb_value
fiber_transfer(mrb_state *mrb, mrb_value self)
{
  struct mrb_context *c = fiber_check(mrb, self);
  mrb_value* a;
  mrb_int len;

  fiber_check_cfunc(mrb, mrb->c);
  mrb_get_args(mrb, "*", &a, &len);

  if (c == mrb->root_c) {
    mrb->c->status = MRB_FIBER_TRANSFERRED;
    mrb->c = c;
    c->status = MRB_FIBER_RUNNING;
    MARK_CONTEXT_MODIFY(c);
    mrb_write_barrier(mrb, (struct RBasic*)c->fib);
    return fiber_result(mrb, a, len);
  }

  if (c == mrb->c) {
    return fiber_result(mrb, a, len);
  }

  return fiber_switch(mrb, self, len, a, FALSE, FALSE);
}
Exemple #3
0
static mrb_value
fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume)
{
  struct mrb_context *c = fiber_check(mrb, self);
  mrb_callinfo *ci;

  for (ci = c->ci; ci >= c->cibase; ci--) {
    if (ci->acc < 0) {
      mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary");
    }
  }
  if (resume && c->status == MRB_FIBER_TRANSFERRED) {
    mrb_raise(mrb, E_FIBER_ERROR, "resuming transfered fiber");
  }
  if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) {
    mrb_raise(mrb, E_FIBER_ERROR, "double resume");
  }
  if (c->status == MRB_FIBER_TERMINATED) {
    mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
  }
  mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED;
  c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
  if (c->status == MRB_FIBER_CREATED) {
    mrb_value *b = c->stack+1;
    mrb_value *e = b + len;

    while (b<e) {
      *b++ = *a++;
    }
    c->cibase->argc = len;
    if (c->prev->fib)
      mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
    mrb_write_barrier(mrb, (struct RBasic*)c->fib);
    c->status = MRB_FIBER_RUNNING;
    mrb->c = c;

    MARK_CONTEXT_MODIFY(c);
    return c->ci->proc->env->stack[0];
  }
  MARK_CONTEXT_MODIFY(c);
  if (c->prev->fib)
    mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib);
  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
  c->status = MRB_FIBER_RUNNING;
  mrb->c = c;
  return fiber_result(mrb, a, len);
}
Exemple #4
0
static mrb_value
fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec)
{
  struct mrb_context *c = fiber_check(mrb, self);
  struct mrb_context *old_c = mrb->c;
  mrb_value value;

  fiber_check_cfunc(mrb, c);
  if (resume && c->status == MRB_FIBER_TRANSFERRED) {
    mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
  }
  if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) {
    mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)");
  }
  if (c->status == MRB_FIBER_TERMINATED) {
    mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
  }
  mrb->c->status = resume ? MRB_FIBER_RESUMED : MRB_FIBER_TRANSFERRED;
  c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c);
  if (c->status == MRB_FIBER_CREATED) {
    mrb_value *b = c->stack+1;
    mrb_value *e = b + len;

    while (b<e) {
      *b++ = *a++;
    }
    c->cibase->argc = len;
    value = c->stack[0] = c->ci->proc->env->stack[0];
  }
  else {
    value = fiber_result(mrb, a, len);
  }
  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
  c->status = MRB_FIBER_RUNNING;
  mrb->c = c;

  if (vmexec) {
    c->vmexec = TRUE;
    value = mrb_vm_exec(mrb, c->ci[-1].proc, c->ci->pc);
    mrb->c = old_c;
  }
  else {
    MARK_CONTEXT_MODIFY(c);
  }
  return value;
}
Exemple #5
0
/* mrb_fiber_yield() must be called as `return mrb_fiber_yield(...)` */
MRB_API mrb_value
mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
{
  struct mrb_context *c = mrb->c;

  if (!c->prev) {
    mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber");
  }

  c->prev->status = MRB_FIBER_RUNNING;
  c->status = MRB_FIBER_SUSPENDED;
  mrb->c = c->prev;
  c->prev = NULL;
  if (c->vmexec) {
    c->vmexec = FALSE;
    mrb->c->ci->acc = CI_ACC_RESUMED;
  }
  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
  MARK_CONTEXT_MODIFY(mrb->c);
  return fiber_result(mrb, a, len);
}
Exemple #6
0
mrb_value
mrb_fiber_yield(mrb_state *mrb, int len, mrb_value *a)
{
  struct mrb_context *c = mrb->c;
  mrb_callinfo *ci;

  for (ci = c->ci; ci >= c->cibase; ci--) {
    if (ci->acc < 0) {
      mrb_raise(mrb, E_ARGUMENT_ERROR, "can't cross C function boundary");
    }
  }
  if (!c->prev) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "can't yield from root fiber");
  }

  c->prev->status = MRB_FIBER_RUNNING;
  mrb->c = c->prev;
  c->prev = NULL;
  MARK_CONTEXT_MODIFY(mrb->c);
  return fiber_result(mrb, a, len);
}
Exemple #7
0
/*
 *  call-seq:
 *     Fiber.yield(args, ...) -> obj
 *
 *  Yields control back to the context that resumed the fiber, passing
 *  along any arguments that were passed to it. The fiber will resume
 *  processing at this point when <code>resume</code> is called next.
 *  Any arguments passed to the next <code>resume</code> will be the
 *  value that this <code>Fiber.yield</code> expression evaluates to.
 */
static mrb_value fiber_yield(mrb_state *mrb, mrb_value self)
{
    struct mrb_context *c = mrb->m_ctx;
    mrb_callinfo *ci;
    mrb_value *a;
    int len;
    for (ci = c->m_ci; ci >= c->cibase; ci--) {
        if (ci->acc < 0) {
            mrb->mrb_raise(E_ARGUMENT_ERROR, "can't cross C function boundary");
        }
    }
    if (!c->prev) {
        mrb->mrb_raise(E_ARGUMENT_ERROR, "can't yield from root fiber");
    }
    mrb_get_args(mrb, "*", &a, &len);
    c->prev->status = MRB_FIBER_RUNNING;
    mrb->m_ctx = c->prev;
    c->prev = NULL;
    MARK_CONTEXT_MODIFY(mrb->m_ctx);
    return fiber_result(mrb, a, len);
}
Exemple #8
0
MRB_API mrb_value
mrb_fiber_yield(mrb_state *mrb, mrb_int len, const mrb_value *a)
{
  struct mrb_context *c = mrb->c;
  mrb_callinfo *ci;

  for (ci = c->ci; ci >= c->cibase; ci--) {
    if (ci->acc < 0) {
      mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary");
    }
  }
  if (!c->prev) {
    mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber");
  }

  c->prev->status = MRB_FIBER_RUNNING;
  c->status = MRB_FIBER_SUSPENDED;
  mrb->c = c->prev;
  c->prev = NULL;
  MARK_CONTEXT_MODIFY(mrb->c);
  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
  return fiber_result(mrb, a, len);
}