Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-fiber/src/fiber.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-fiber/src/fiber.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-fiber/src/fiber.c	(revision 331)
@@ -1,6 +1,6 @@
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/class.h"
-#include "mruby/proc.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/proc.h>
 
 #define fiber_ptr(o) ((struct RFiber*)mrb_ptr(o))
@@ -8,4 +8,5 @@
 #define FIBER_STACK_INIT_SIZE 64
 #define FIBER_CI_INIT_SIZE 8
+#define CI_ACC_RESUMED -3
 
 /*
@@ -74,4 +75,7 @@
   mrb_get_args(mrb, "&", &blk);
 
+  if (f->cxt) {
+    mrb_raise(mrb, E_RUNTIME_ERROR, "cannot initialize twice");
+  }
   if (mrb_nil_p(blk)) {
     mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Fiber object without a block");
@@ -82,7 +86,7 @@
   }
 
-  f->cxt = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
-  *f->cxt = mrb_context_zero;
-  c = f->cxt;
+  c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
+  *c = mrb_context_zero;
+  f->cxt = c;
 
   /* initialize VM stack */
@@ -156,8 +160,7 @@
 #define MARK_CONTEXT_MODIFY(c) (c)->ci->target_class = NULL
 
-static mrb_value
-fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume)
-{
-  struct mrb_context *c = fiber_check(mrb, self);
+static void
+fiber_check_cfunc(mrb_state *mrb, struct mrb_context *c)
+{
   mrb_callinfo *ci;
 
@@ -167,39 +170,63 @@
     }
   }
+}
+
+static void
+fiber_switch_context(mrb_state *mrb, struct mrb_context *c)
+{
+  if (mrb->c->fib) {
+    mrb_write_barrier(mrb, (struct RBasic*)mrb->c->fib);
+  }
+  c->status = MRB_FIBER_RUNNING;
+  mrb->c = c;
+}
+
+static mrb_value
+fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mrb_bool resume, mrb_bool vmexec)
+{
+  struct mrb_context *c = fiber_check(mrb, self);
+  struct mrb_context *old_c = mrb->c;
+  mrb_value value;
+
+  fiber_check_cfunc(mrb, c);
   if (resume && c->status == MRB_FIBER_TRANSFERRED) {
     mrb_raise(mrb, E_FIBER_ERROR, "resuming transferred fiber");
   }
-  if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMING) {
-    mrb_raise(mrb, E_FIBER_ERROR, "double resume");
+  if (c->status == MRB_FIBER_RUNNING || c->status == MRB_FIBER_RESUMED) {
+    mrb_raise(mrb, E_FIBER_ERROR, "double resume (fib)");
   }
   if (c->status == MRB_FIBER_TERMINATED) {
     mrb_raise(mrb, E_FIBER_ERROR, "resuming dead fiber");
   }
-  mrb->c->status = resume ? MRB_FIBER_RESUMING : MRB_FIBER_TRANSFERRED;
+  mrb->c->status = resume ? MRB_FIBER_RESUMED : 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;
-
+    mrb_value *b, *e;
+
+    if (len >= c->stend - c->stack) {
+      mrb_raise(mrb, E_FIBER_ERROR, "too many arguments to fiber");
+    }
+    b = c->stack+1;
+    e = b + len;
     while (b<e) {
       *b++ = *a++;
     }
     c->cibase->argc = len;
-    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);
-    c->status = MRB_FIBER_RUNNING;
-    mrb->c = c;
-
+    value = c->stack[0] = c->ci->proc->env->stack[0];
+  }
+  else {
+    value = fiber_result(mrb, a, len);
+  }
+  fiber_switch_context(mrb, c);
+
+  if (vmexec) {
+    c->vmexec = TRUE;
+    value = mrb_vm_exec(mrb, c->ci[-1].proc, c->ci->pc);
+    mrb->c = old_c;
+  }
+  else {
     MARK_CONTEXT_MODIFY(c);
-    return c->ci->proc->env->stack[0];
-  }
-  MARK_CONTEXT_MODIFY(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);
-  c->status = MRB_FIBER_RUNNING;
-  mrb->c = c;
-  return fiber_result(mrb, a, len);
+  }
+  return value;
 }
 
@@ -224,7 +251,11 @@
   mrb_value *a;
   mrb_int len;
+  mrb_bool vmexec = FALSE;
 
   mrb_get_args(mrb, "*", &a, &len);
-  return fiber_switch(mrb, self, len, a, TRUE);
+  if (mrb->c->ci->acc < 0) {
+    vmexec = TRUE;
+  }
+  return fiber_switch(mrb, self, len, a, TRUE, vmexec);
 }
 
@@ -233,5 +264,5 @@
 mrb_fiber_resume(mrb_state *mrb, mrb_value fib, mrb_int len, const mrb_value *a)
 {
-  return fiber_switch(mrb, fib, len, a, TRUE);
+  return fiber_switch(mrb, fib, len, a, TRUE, TRUE);
 }
 
@@ -281,12 +312,11 @@
   mrb_int len;
 
+  fiber_check_cfunc(mrb, mrb->c);
   mrb_get_args(mrb, "*", &a, &len);
 
   if (c == mrb->root_c) {
     mrb->c->status = MRB_FIBER_TRANSFERRED;
-    mrb->c = c;
-    c->status = MRB_FIBER_RUNNING;
+    fiber_switch_context(mrb, c);
     MARK_CONTEXT_MODIFY(c);
-    mrb_write_barrier(mrb, (struct RBasic*)c->fib);
     return fiber_result(mrb, a, len);
   }
@@ -296,5 +326,5 @@
   }
 
-  return fiber_switch(mrb, self, len, a, FALSE);
+  return fiber_switch(mrb, self, len, a, FALSE, FALSE);
 }
 
@@ -305,21 +335,19 @@
 {
   struct mrb_context *c = mrb->c;
-  mrb_callinfo *ci;
-
-  for (ci = c->ci; ci >= c->cibase; ci--) {
-    if (ci->acc < 0) {
-      mrb_raise(mrb, E_FIBER_ERROR, "can't cross C function boundary");
-    }
-  }
+
   if (!c->prev) {
     mrb_raise(mrb, E_FIBER_ERROR, "can't yield from root fiber");
   }
 
+  fiber_check_cfunc(mrb, c);
   c->prev->status = MRB_FIBER_RUNNING;
   c->status = MRB_FIBER_SUSPENDED;
-  mrb->c = c->prev;
+  fiber_switch_context(mrb, c->prev);
   c->prev = NULL;
+  if (c->vmexec) {
+    c->vmexec = FALSE;
+    mrb->c->ci->acc = CI_ACC_RESUMED;
+  }
   MARK_CONTEXT_MODIFY(mrb->c);
-  mrb_write_barrier(mrb, (struct RBasic*)c->fib);
   return fiber_result(mrb, a, len);
 }
@@ -333,5 +361,7 @@
  *  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.
+ *
+ *  mruby limitation: Fiber resume/yield cannot cross C function boundary.
+ *  thus you cannot yield from #initialize which is called by mrb_funcall().
  */
 static mrb_value
