summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-fiber/src
diff options
context:
space:
mode:
authortake_cheeze <[email protected]>2014-03-21 22:10:39 +0900
committertake_cheeze <[email protected]>2014-03-21 22:10:47 +0900
commite854a0e8500c254fc845924888cdb20743e59e34 (patch)
treeb1b650e31c29a0c5f45d1600aa76fa9b00ea91d9 /mrbgems/mruby-fiber/src
parentd4d4f1b0d57bed96bb3341c2304e39afefa352c5 (diff)
downloadmruby-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.c74
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