Class: Fiber
- Inherits:
-
Object
- Object
- Fiber
- Defined in:
- mrbgems/mruby-fiber/src/fiber.c
Instance Method Summary collapse
-
#== ⇒ Object
-
#alive? ⇒ Boolean
-
#new { ... } ⇒ Object
constructor
Creates a fiber, whose execution is suspend until it is explicitly resumed using
Fiber#resume
method. -
#resume(args, ...) ⇒ Object
Resumes the fiber from the point at which the last
Fiber.yield
was called, or starts running it if it is the first call toresume
. -
#transfer(args, ...) ⇒ Object
Transfers control to receiver fiber of the method call.
Constructor Details
#new { ... } ⇒ Object
Creates a fiber, whose execution is suspend until it is explicitly
resumed using Fiber#resume
method.
The code running inside the fiber can give up control by calling
Fiber.yield
in which case it yields control back to caller
(the caller of the Fiber#resume
).
Upon yielding or termination the Fiber returns the value of the last executed expression
For instance:
fiber = Fiber.new do Fiber.yield 1 2 end
puts fiber.resume puts fiber.resume puts fiber.resume
produces
1 2 resuming dead fiber (FiberError)
The Fiber#resume
method accepts an arbitrary number of
parameters, if it is the first call to resume
then they
will be passed as block arguments. Otherwise they will be the return
value of the call to Fiber.yield
Example:
fiber = Fiber.new do |first| second = Fiber.yield first + 2 end
puts fiber.resume 10 puts fiber.resume 14 puts fiber.resume 18
produces
12 14 resuming dead fiber (FiberError)
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'mrbgems/mruby-fiber/src/fiber.c', line 64 static mrb_value fiber_init(mrb_state *mrb, mrb_value self) { static const struct mrb_context mrb_context_zero = { 0 }; struct RFiber *f = fiber_ptr(self); struct mrb_context *c; struct RProc *p; mrb_callinfo *ci; mrb_value blk; size_t slen; mrb_get_args(mrb, "&!", &blk); if (f->cxt) { mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice"); } p = mrb_proc_ptr(blk); if (MRB_PROC_CFUNC_P(p)) { mrb_raise(mrb, E_FIBER_ERROR, "tried to create Fiber from C defined method"); } c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); *c = mrb_context_zero; f->cxt = c; /* initialize VM stack */ slen = FIBER_STACK_INIT_SIZE; if (p->body.irep->nregs > slen) { slen += p->body.irep->nregs; } c->stbase = (mrb_value *)mrb_malloc(mrb, slen*sizeof(mrb_value)); c->stend = c->stbase + slen; c->stack = c->stbase; #ifdef MRB_NAN_BOXING { mrb_value *p = c->stbase; mrb_value *pend = c->stend; while (p < pend) { SET_NIL_VALUE(*p); p++; } } #else memset(c->stbase, 0, slen * sizeof(mrb_value)); #endif /* copy receiver from a block */ c->stack[0] = mrb->c->stack[0]; /* initialize callinfo stack */ c->cibase = (mrb_callinfo *)mrb_calloc(mrb, FIBER_CI_INIT_SIZE, sizeof(mrb_callinfo)); c->ciend = c->cibase + FIBER_CI_INIT_SIZE; c->ci = c->cibase; c->ci->stackent = c->stack; /* adjust return callinfo */ ci = c->ci; ci->target_class = MRB_PROC_TARGET_CLASS(p); ci->proc = p; mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); ci->pc = p->body.irep->iseq; ci[1] = ci[0]; c->ci++; /* push dummy callinfo */ c->fib = f; c->status = MRB_FIBER_CREATED; return self; } |
Instance Method Details
#== ⇒ Object
291 292 293 294 295 296 297 298 299 300 301 |
# File 'mrbgems/mruby-fiber/src/fiber.c', line 291 static mrb_value fiber_eq(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_get_args(mrb, "o", &other); if (!mrb_fiber_p(other)) { return mrb_false_value(); } return mrb_bool_value(fiber_ptr(self) == fiber_ptr(other)); } |
#alive? ⇒ Boolean
#resume(args, ...) ⇒ Object
Resumes the fiber from the point at which the last Fiber.yield
was called, or starts running it if it is the first call to
resume
. Arguments passed to resume will be the value of
the Fiber.yield
expression or will be passed as block
parameters to the fiber’s block if this is the first resume
.
Alternatively, when resume is called it evaluates to the arguments passed
to the next Fiber.yield
statement inside the fiber’s block
or to the block value if it runs to completion without any
Fiber.yield
255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'mrbgems/mruby-fiber/src/fiber.c', line 255 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); } |
#transfer(args, ...) ⇒ Object
Transfers control to receiver fiber of the method call.
Unlike resume
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 Fiber.yield
is called, the fiber would be resumable.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'mrbgems/mruby-fiber/src/fiber.c', line 315 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; fiber_switch_context(mrb, c); MARK_CONTEXT_MODIFY(c); 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); } |