From 76ddf86c72ccefefbeb2cd5dcf78c8365b1a2bcc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 23 May 2013 15:24:31 +0900 Subject: manage fiber status (create|running|resumed|terminated) --- include/mruby.h | 8 ++++++++ mrbgems/mruby-fiber/src/fiber.c | 18 +++++++++++++----- src/vm.c | 9 ++++++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 925344502..fac7e6fcd 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -61,6 +61,13 @@ typedef struct { struct REnv *env; } mrb_callinfo; +enum mrb_fiber_state { + MRB_FIBER_CREATED = 0, + MRB_FIBER_RUNNING, + MRB_FIBER_RESUMED, + MRB_FIBER_TERMINATED, +}; + struct mrb_context { struct mrb_context *prev; @@ -75,6 +82,7 @@ struct mrb_context { struct RProc **ensure; int esize; + uint8_t status; struct RFiber *fib; }; diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index c338b8b95..c98dd0e67 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -105,6 +105,7 @@ fiber_init(mrb_state *mrb, mrb_value self) c->ci++; /* push dummy callinfo */ c->fib = f; + c->status = MRB_FIBER_CREATED; return self; } @@ -153,8 +154,15 @@ fiber_resume(mrb_state *mrb, mrb_value self) mrb_value *a; int len; + if (c->status == MRB_FIBER_RESUMED) { + mrb_raise(mrb, E_RUNTIME_ERROR, "double resume"); + } + if (c->status == MRB_FIBER_TERMINATED) { + mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead fiber"); + } mrb_get_args(mrb, "*", &a, &len); - if (!c->prev) { /* first call */ + mrb->c->status = MRB_FIBER_RESUMED; + if (c->status == MRB_FIBER_CREATED) { mrb_value *b = c->stack+1; mrb_value *e = b + len; @@ -163,16 +171,15 @@ fiber_resume(mrb_state *mrb, mrb_value self) } c->ci->argc = len; c->prev = mrb->c; + c->status = MRB_FIBER_RUNNING; mrb->c = c; MARK_CONTEXT_MODIFY(c); return c->ci->proc->env->stack[0]; } - if (c->ci == c->cibase) { - mrb_raise(mrb, E_RUNTIME_ERROR, "resuming dead fiber"); - } MARK_CONTEXT_MODIFY(c); c->prev = mrb->c; + c->status = MRB_FIBER_RUNNING; mrb->c = c; return fiber_result(mrb, a, len); } @@ -198,8 +205,9 @@ fiber_yield(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_ARGUMENT_ERROR, "can't yield from root fiber"); } mrb_get_args(mrb, "*", &a, &len); - + c->prev->status = MRB_FIBER_RUNNING; mrb->c = c->prev; + c->prev = NULL; MARK_CONTEXT_MODIFY(mrb->c); return fiber_result(mrb, a, len); } diff --git a/src/vm.c b/src/vm.c index c240ef968..f9aec1520 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1301,7 +1301,14 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } - mrb->c = mrb->c->prev; /* automatic yield at the end */ + if (mrb->c->prev->ci == mrb->c->prev->cibase) { + mrb_value exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, mrb_str_new(mrb, "double resume", 13)); + mrb->exc = mrb_obj_ptr(exc); + goto L_RAISE; + } + /* automatic yield at the end */ + mrb->c->status = MRB_FIBER_TERMINATED; + mrb->c = mrb->c->prev; } ci = mrb->c->ci; break; -- cgit v1.2.3