static struct mrb_context* fiber_check(mrb_state *mrb, mrb_value fib) { struct RFiber *f = (struct RFiber*)mrb_ptr(fib); if (!f->cxt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized Fiber"); } return f->cxt; }
mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) { if (mrb_type(v1) != mrb_type(v2)) return FALSE; switch (mrb_type(v1)) { case MRB_TT_TRUE: return TRUE; case MRB_TT_FALSE: case MRB_TT_FIXNUM: return (v1.value.i == v2.value.i); case MRB_TT_SYMBOL: return (v1.value.sym == v2.value.sym); case MRB_TT_FLOAT: return (mrb_float(v1) == mrb_float(v2)); default: return (mrb_ptr(v1) == mrb_ptr(v2)); } }
/* * call-seq: * Fiber.new{...} -> obj * * Creates a fiber, whose execution is suspend until it is explicitly * resumed using <code>Fiber#resume</code> method. * The code running inside the fiber can give up control by calling * <code>Fiber.yield</code> in which case it yields control back to caller * (the caller of the <code>Fiber#resume</code>). * * 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 * * <em>produces</em> * * 1 * 2 * resuming dead fiber (RuntimeError) * * The <code>Fiber#resume</code> method accepts an arbitrary number of * parameters, if it is the first call to <code>resume</code> then they * will be passed as block arguments. Otherwise they will be the return * value of the call to <code>Fiber.yield</code> * * Example: * * fiber = Fiber.new do |first| * second = Fiber.yield first + 2 * end * * puts fiber.resume 10 * puts fiber.resume 14 * puts fiber.resume 18 * * <em>produces</em> * * 12 * 14 * resuming dead fiber (RuntimeError) * */ static mrb_value fiber_init(mrb_state *mrb, mrb_value self) { static const struct mrb_context mrb_context_zero = { 0 }; struct RFiber *f = (struct RFiber*)mrb_ptr(self); struct mrb_context *c; struct RProc *p; mrb_callinfo *ci; mrb_value blk; mrb_get_args(mrb, "&", &blk); if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block"); } p = mrb_proc_ptr(blk); if (MRB_PROC_CFUNC_P(p)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber from C defined method"); } f->cxt = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context)); *f->cxt = mrb_context_zero; c = f->cxt; /* initialize VM stack */ c->stbase = (mrb_value *)mrb_calloc(mrb, FIBER_STACK_INIT_SIZE, sizeof(mrb_value)); c->stend = c->stbase + FIBER_STACK_INIT_SIZE; c->stack = c->stbase; /* 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 = p->target_class; ci->proc = p; ci->pc = p->body.irep->iseq; ci->nregs = p->body.irep->nregs; ci[1] = ci[0]; c->ci++; /* push dummy callinfo */ c->fib = f; c->status = MRB_FIBER_CREATED; return self; }
inline bool operator==(mrb_value v1, mrb_value v2) { if (mrb_type(v1) != mrb_type(v2)) return false; switch (mrb_type(v1)) { case MRB_TT_TRUE: return true; case MRB_TT_FALSE: case MRB_TT_FIXNUM: return (v1.value.i == v2.value.i); case MRB_TT_SYMBOL: return (v1.value.sym == v2.value.sym); case MRB_TT_FLOAT: return (mrb_float(v1) == mrb_float(v2)); default: return (mrb_ptr(v1) == mrb_ptr(v2)); } }
static mrb_value mrb_uv_key_set(mrb_state *mrb, mrb_value self) { uv_key_t *key; void *p; mrb_value new_val; mrb_value ary; mrb_get_args(mrb, "o", &new_val); if (mrb_type(new_val) < MRB_TT_HAS_BASIC) { mrb_raisef(mrb, E_TYPE_ERROR, "cannot store value without basic: %S", new_val); } key = (uv_key_t*)mrb_uv_get_ptr(mrb, self, &mrb_uv_key_type); p = uv_key_get(key); ary = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "values")); mrb_assert(mrb_array_p(ary)); if (p) { /* remove value */ int i, dst; for (i = 0, dst = 0; i < RARRAY_LEN(ary); ++i) { mrb_value v = RARRAY_PTR(ary)[i]; if (mrb_ptr(v) != p) { mrb_ary_ptr(ary)->ptr[dst++] = v; } } RARRAY_LEN(ary) = dst; } uv_key_set(key, mrb_ptr(new_val)); mrb_ary_push(mrb, ary, new_val); /* protect from GC */ return new_val; }