/* * 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); }
bool Fiber::yield() { Fiber *f = current; for (auto *p = ++f ;; f++) { if (p == &fibers.at(MAXFIBERS-1)) { p = &fibers.at(0); } else if (p->status == Fiber::Ready) { f = p; break; } else if (p == f) { return false; } } if (current->status != Fiber::Unused) { current->status = Fiber::Ready; } f->status = Fiber::Running; auto old_ctx = ¤t->context; auto new_ctx = &f->context; current = f; fiber_switch(old_ctx, new_ctx); return true; }
/* * 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) { mrb_value *a; int len; mrb_get_args(mrb, "*", &a, &len); return fiber_switch(mrb, self, len, a, TRUE); }
VALUE rb_fiber_resume(VALUE fibval, int argc, VALUE *argv) { rb_fiber_t *fib; GetFiberPtr(fibval, fib); if (fib->prev != Qnil) { rb_raise(rb_eFiberError, "double resume"); } return fiber_switch(fibval, argc, argv, 1); }
VALUE rb_fiber_resume(VALUE fib, int argc, VALUE *argv) { rb_context_t *cont; GetContPtr(fib, cont); if (cont->prev != Qnil) { rb_raise(rb_eFiberError, "double resume"); } return fiber_switch(fib, argc, argv, 1); }
/* * 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) { mrb_value *a; mrb_int len; mrb_bool vmexec = FALSE; mrb_get_args(mrb, "*", &a, &len); if (mrb->c->ci->acc < 0) { vmexec = TRUE; } return fiber_switch(mrb, self, len, a, TRUE, vmexec); }
/* resume thread with given arguments */ MRB_API mrb_value mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a) { return fiber_switch(mrb, fib, len, a, TRUE, TRUE); }
VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv) { return fiber_switch(fib, argc, argv, 0); }