diff options
| author | take_cheeze <[email protected]> | 2014-03-21 22:10:39 +0900 |
|---|---|---|
| committer | take_cheeze <[email protected]> | 2014-03-21 22:10:47 +0900 |
| commit | e854a0e8500c254fc845924888cdb20743e59e34 (patch) | |
| tree | b1b650e31c29a0c5f45d1600aa76fa9b00ea91d9 /mrbgems/mruby-fiber/src | |
| parent | d4d4f1b0d57bed96bb3341c2304e39afefa352c5 (diff) | |
| download | mruby-e854a0e8500c254fc845924888cdb20743e59e34.tar.gz mruby-e854a0e8500c254fc845924888cdb20743e59e34.zip | |
make Fiber#transfer compatible with CRuby
Diffstat (limited to 'mrbgems/mruby-fiber/src')
| -rw-r--r-- | mrbgems/mruby-fiber/src/fiber.c | 74 |
1 files changed, 47 insertions, 27 deletions
diff --git a/mrbgems/mruby-fiber/src/fiber.c b/mrbgems/mruby-fiber/src/fiber.c index b5f9b69dc..b077def8b 100644 --- a/mrbgems/mruby-fiber/src/fiber.c +++ b/mrbgems/mruby-fiber/src/fiber.c @@ -136,27 +136,10 @@ fiber_result(mrb_state *mrb, mrb_value *a, int len) /* mark return from context modifying method */ #define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL -/* - * 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) +fiber_switch(mrb_state *mrb, mrb_value self, int len, const mrb_value *a, mrb_bool resume) { struct mrb_context *c = fiber_check(mrb, self); - mrb_value *a; - int len; mrb_callinfo *ci; for (ci = c->ci; ci >= c->cibase; ci--) { @@ -164,6 +147,9 @@ fiber_resume(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary"); } } + if (resume && c->status == MRB_FIBER_TRANSFERRED) { + mrb_raise(mrb, E_FIBER_ERROR, "resuming transfered fiber"); + } if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) { mrb_raise(mrb, E_FIBER_ERROR, "double resume"); } @@ -171,7 +157,8 @@ fiber_resume(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber"); } mrb_get_args(mrb, "*", &a, &len); - mrb->c->status = MRB_FIBER_RESUMING; + mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED; + c->prev = resume ? mrb->c : (c->prev ? c->prev : mrb->root_c); if (c->status == MRB_FIBER_CREATED) { mrb_value *b = c->stack+1; mrb_value *e = b + len; @@ -180,7 +167,6 @@ fiber_resume(mrb_state *mrb, mrb_value self) *b++ = *a++; } c->cibase->argc = len; - c->prev = mrb->c; if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); @@ -191,7 +177,6 @@ fiber_resume(mrb_state *mrb, mrb_value self) return c->ci->proc->env->stack[0]; } MARK_CONTEXT_MODIFY(c); - c->prev = mrb->c; if (c->prev->fib) mrb_field_write_barrier(mrb, (struct RBasic*)c->fib, (struct RBasic*)c->prev->fib); mrb_write_barrier(mrb, (struct RBasic*)c->fib); @@ -202,6 +187,30 @@ fiber_resume(mrb_state *mrb, mrb_value self) /* * 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) +{ + mrb_value *a; + int len; + mrb_get_args(mrb, "*", &a, &len); + return fiber_switch(mrb, self, len, a, TRUE); +} + +/* + * call-seq: * fiber.alive? -> true or false * * Returns true if the fiber can still be resumed. After finishing @@ -229,14 +238,25 @@ fiber_eq(mrb_state *mrb, mrb_value self) static mrb_value fiber_transfer(mrb_state *mrb, mrb_value self) { - mrb_value result = fiber_resume(mrb, self); + struct mrb_context *c = fiber_check(mrb, self); + mrb_value* a; + int len; + + mrb_get_args(mrb, "*", &a, &len); - mrb_assert(mrb->c->prev); - mrb_assert(mrb->c->prev->prev); - mrb->c->prev->status = MRB_FIBER_SUSPENDED; - mrb->c->prev = mrb->c->prev->prev; + if (c == mrb->root_c) { + mrb->c->status = MRB_FIBER_TRANSFERRED; + mrb->c = c; + c->status = MRB_FIBER_RUNNING; + MARK_CONTEXT_MODIFY(c); + return fiber_result(mrb, a, len); + } + + if (c == mrb->c) { + return fiber_result(mrb, a, len); + } - return result; + return fiber_switch(mrb, self, len, a, FALSE); } mrb_value |
