diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-05-20 17:54:07 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-05-20 17:54:07 +0900 |
| commit | 5c0b9b703c9d1a08d7219b057b809bda4bc89f8a (patch) | |
| tree | ab610a2988ef928c02bfc50e31aedc5a707f008e /mrbgems | |
| parent | 35ee85164dd19143d4b47a34f13ad2bb71fed369 (diff) | |
| download | mruby-5c0b9b703c9d1a08d7219b057b809bda4bc89f8a.tar.gz mruby-5c0b9b703c9d1a08d7219b057b809bda4bc89f8a.zip | |
primary mruby fiber implementation
Diffstat (limited to 'mrbgems')
| -rw-r--r-- | mrbgems/default.gembox | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-fiber/mrbgem.rake | 4 | ||||
| -rw-r--r-- | mrbgems/mruby-fiber/src/fiber.c | 179 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/src/struct.c | 4 |
4 files changed, 188 insertions, 2 deletions
diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index a53b07d8a..1c6732d48 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -44,6 +44,9 @@ MRuby::GemBox.new do |conf| # Use ObjectSpace class conf.gem :core => "mruby-objectspace" + # Use Fiber class + conf.gem :core => "mruby-fiber" + # Generate mirb command conf.gem :core => "mruby-bin-mirb" diff --git a/mrbgems/mruby-fiber/mrbgem.rake b/mrbgems/mruby-fiber/mrbgem.rake new file mode 100644 index 000000000..cb258adcb --- /dev/null +++ b/mrbgems/mruby-fiber/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-fiber') do |spec| + spec.license = 'MIT' + spec.authors = 'mruby developers' +end diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c new file mode 100644 index 000000000..01410e4b3 --- /dev/null +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -0,0 +1,179 @@ +#include "mruby.h" +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/proc.h" + +#define FIBER_STACK_INIT_SIZE 64 +#define FIBER_CI_INIT_SIZE 8 + +/* + * call-seq: + * Fiber.new{...} -> obj + * + * Creates an fiber, whose execution is suspend until it explicitly + * resumed using <code>Fibder#resume</code> method. + * <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_init(mrb_state *mrb, mrb_value self) +{ + static const struct mrb_context mrb_context_zero = { 0 }; + struct RFiber *f = (struct RFiber*)self.value.p; + 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; + + /* initialize VM stack */ + c = f->cxt; + 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; + + /* 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 */ + + return self; +} + +static struct mrb_context* +fiber_check(mrb_state *mrb, mrb_value fib) +{ + struct RFiber *f = (struct RFiber*)fib.value.p; + + if (!f->cxt) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized Fiber"); + } + return f->cxt; +} + +static mrb_value +fiber_result(mrb_state *mrb, mrb_value *a, int len) +{ + if (len == 0) return mrb_nil_value(); + if (len == 1) return a[0]; + return mrb_ary_new_from_values(mrb, len, a); +} + +/* + * 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_get_args(mrb, "*", &a, &len); + if (!c->prev) { /* first call */ + mrb_value *b = c->stack+1; + mrb_value *e = b + len; + + while (b<e) { + *b++ = *a++; + } + c->ci->argc = len; + c->prev = mrb->c; + mrb->c = c; + + return c->ci->proc->env->stack[0]; + } + if (c->ci == c->cibase) { + mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead Fiber"); + } + c->prev = mrb->c; + mrb->c = c; + return fiber_result(mrb, a, len); +} + +/* + * 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->c; + mrb_value *a; + int len; + + if (!c->prev) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "can't yield from root Fiber"); + } + mrb_get_args(mrb, "*", &a, &len); + + mrb->c = c->prev; + return fiber_result(mrb, a, len); +} + +void +mrb_mruby_fiber_gem_init(mrb_state* mrb) +{ + struct RClass *c; + + c = mrb_define_class(mrb, "Fiber", mrb->object_class); + MRB_SET_INSTANCE_TT(c, MRB_TT_FIBER); + + mrb_define_method(mrb, c, "initialize", fiber_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, c, "resume", fiber_resume, MRB_ARGS_ANY()); + + mrb_define_class_method(mrb, c, "yield", fiber_yield, MRB_ARGS_ANY()); +} + +void +mrb_mruby_fiber_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 2775471fe..a2731ca54 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -132,7 +132,7 @@ mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id) static mrb_value mrb_struct_ref(mrb_state *mrb, mrb_value obj) { - return mrb_struct_getmember(mrb, obj, mrb->ci->mid); + return mrb_struct_getmember(mrb, obj, mrb->c->ci->mid); } static mrb_value mrb_struct_ref0(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[0];} @@ -191,7 +191,7 @@ mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val) mrb_value members, slot, *ptr, *ptr_members; /* get base id */ - name = mrb_sym2name_len(mrb, mrb->ci->mid, &len); + name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &len); mid = mrb_intern2(mrb, name, len-1); /* omit last "=" */ members = mrb_struct_members(mrb, obj); |
