diff --git a/include/mruby.h b/include/mruby.h index 833c19a09..7a533cfa7 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1445,6 +1445,13 @@ MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mr /* obsolete function(s); will be removed */ #define mrb_int(mrb, val) mrb_as_int(mrb, val) +/** + * Create a new Fiber from proc object + * + * Implemented in mruby-fiber + */ +MRB_API mrb_value mrb_fiber_new(mrb_state *mrb, const struct RProc *proc); + /** * Resume a Fiber * diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index ff09824f1..62bcbc301 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -3,6 +3,7 @@ #include #include #include +#include #define fiber_ptr(o) ((struct RFiber*)mrb_ptr(o)) @@ -11,6 +12,66 @@ /* copied from vm.c */ #define CINFO_RESUMED 3 +static mrb_value +fiber_init_fiber(mrb_state *mrb, struct RFiber *f, const struct RProc *p) +{ + static const struct mrb_context mrb_context_zero = { 0 }; + struct mrb_context *c; + mrb_callinfo *ci; + size_t slen; + + if (f->cxt) { + mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice"); + } + 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; + + { + mrb_value *p = c->stbase; + mrb_value *pend = c->stend; + + while (p < pend) { + SET_NIL_VALUE(*p); + p++; + } + } + + /* copy receiver from a block */ + c->stbase[0] = mrb->c->ci->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; + + /* adjust return callinfo */ + ci = c->ci; + mrb_vm_ci_target_class_set(ci, MRB_PROC_TARGET_CLASS(p)); + mrb_vm_ci_proc_set(ci, p); + mrb_field_write_barrier(mrb, (struct RBasic*)f, (struct RBasic*)p); + ci->stack = c->stbase; + ci[1] = ci[0]; + c->ci++; /* push dummy callinfo */ + + c->fib = f; + c->status = MRB_FIBER_CREATED; + + return mrb_obj_value(f); +} + /* * call-seq: * Fiber.new{...} -> obj @@ -66,67 +127,9 @@ 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; - - { - mrb_value *p = c->stbase; - mrb_value *pend = c->stend; - - while (p < pend) { - SET_NIL_VALUE(*p); - p++; - } - } - - /* copy receiver from a block */ - c->stbase[0] = mrb->c->ci->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; - - /* adjust return callinfo */ - ci = c->ci; - mrb_vm_ci_target_class_set(ci, MRB_PROC_TARGET_CLASS(p)); - mrb_vm_ci_proc_set(ci, p); - mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p); - ci->stack = c->stbase; - ci[1] = ci[0]; - c->ci++; /* push dummy callinfo */ - - c->fib = f; - c->status = MRB_FIBER_CREATED; - - return self; + return fiber_init_fiber(mrb, fiber_ptr(self), mrb_proc_ptr(blk)); } static struct mrb_context* @@ -457,6 +460,18 @@ fiber_current(mrb_state *mrb, mrb_value self) return mrb_obj_value(mrb->c->fib); } +MRB_API mrb_value +mrb_fiber_new(mrb_state *mrb, const struct RProc *p) +{ + struct RClass *c = mrb_class_get_id(mrb, MRB_SYM(Fiber)); + if (MRB_INSTANCE_TT(c) != MRB_TT_FIBER) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong Fiber class"); + } + + struct RFiber *f = MRB_OBJ_ALLOC(mrb, MRB_TT_FIBER, c); + return fiber_init_fiber(mrb, f, p); +} + void mrb_mruby_fiber_gem_init(mrb_state* mrb) {