Selaa lähdekoodia

support for yield inside hooks

Roberto Ierusalimschy 23 vuotta sitten
vanhempi
commit
9bab2cf55d
2 muutettua tiedostoa jossa 35 lisäystä ja 22 poistoa
  1. 26 18
      ldo.c
  2. 9 4
      lvm.c

+ 26 - 18
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 1.201 2002/11/14 16:15:53 roberto Exp roberto $
+** $Id: ldo.c,v 1.202 2002/11/18 11:01:55 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -308,15 +308,20 @@ static void resume (lua_State *L, void *ud) {
       luaG_runerror(L, "cannot resume dead coroutine");
     luaD_precall(L, L->top - (nargs + 1));  /* start coroutine */
   }
-  else if (ci->state && CI_YIELD) {  /* inside a yield? */
-    /* finish interrupted execution of `OP_CALL' */
-    int nresults;
-    lua_assert((ci-1)->state & CI_SAVEDPC);
-    lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL ||
-               GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL);
-    nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1;
-    luaD_poscall(L, nresults, L->top - nargs);  /* complete it */
-    if (nresults >= 0) L->top = L->ci->top;
+  else if (ci->state & CI_YIELD) {  /* inside a yield? */
+    if (ci->state & CI_C) {  /* `common' yield? */
+      /* finish interrupted execution of `OP_CALL' */
+      int nresults;
+      lua_assert((ci-1)->state & CI_SAVEDPC);
+      lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL ||
+                 GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL);
+      nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1;
+      luaD_poscall(L, nresults, L->top - nargs);  /* complete it */
+      if (nresults >= 0) L->top = L->ci->top;
+    }
+    else {  /* yielded inside a hook: just continue its execution */
+      ci->state &= ~CI_YIELD;
+    }
   }
   else
     luaG_runerror(L, "cannot resume non-suspended coroutine");
@@ -349,15 +354,18 @@ LUA_API int lua_yield (lua_State *L, int nresults) {
   CallInfo *ci;
   lua_lock(L);
   ci = L->ci;
-  if ((ci-1)->state & CI_C)
-    luaG_runerror(L, "cannot yield a C function");
-  lua_assert(ci->state & CI_C);  /* current function is not Lua */
-  if (L->top - nresults > ci->base) {  /* is there garbage in the stack? */
-    int i;
-    for (i=0; i<nresults; i++)  /* move down results */
-      setobjs2s(ci->base + i, L->top - nresults + i);
-    L->top = ci->base + nresults;
+  if (ci->state & CI_C) {  /* usual yield */
+    if ((ci-1)->state & CI_C)
+      luaG_runerror(L, "cannot yield a C function");
+    if (L->top - nresults > ci->base) {  /* is there garbage in the stack? */
+      int i;
+      for (i=0; i<nresults; i++)  /* move down results */
+        setobjs2s(ci->base + i, L->top - nresults + i);
+      L->top = ci->base + nresults;
+    }
   }
+  /* else it's an yield inside a hook: nothing to do */
+  ci->state |= CI_YIELD;
   lua_unlock(L);
   return -1;
 }

+ 9 - 4
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 1.261 2002/11/14 16:15:53 roberto Exp roberto $
+** $Id: lvm.c,v 1.262 2002/11/18 11:01:55 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -393,8 +393,14 @@ StkId luaV_execute (lua_State *L) {
     const Instruction i = *pc++;
     StkId ra;
     if (L->hookmask >= LUA_MASKLINE &&
-        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE))
+        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
       traceexec(L);
+      if (L->ci->state & CI_YIELD) {  /* did hook yield? */
+        L->ci->u.l.savedpc = pc - 1;
+        L->ci->state |= CI_SAVEDPC;
+        return NULL;
+      }
+    }
     /* warning!! several calls may realloc the stack and invalidate `ra' */
     ra = RA(i);
     lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base);
@@ -595,8 +601,7 @@ StkId luaV_execute (lua_State *L) {
         if (firstResult) {
           if (firstResult > L->top) {  /* yield? */
             (L->ci - 1)->u.l.savedpc = pc;
-            (L->ci - 1)->state = CI_SAVEDPC;
-            L->ci->state |= CI_YIELD;
+            (L->ci - 1)->state |= CI_SAVEDPC;
             return NULL;
           }
           /* it was a C function (`precall' called it); adjust results */