Browse Source

support for yield inside hooks

Roberto Ierusalimschy 23 years ago
parent
commit
9bab2cf55d
2 changed files with 35 additions and 22 deletions
  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
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 ** 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");
       luaG_runerror(L, "cannot resume dead coroutine");
     luaD_precall(L, L->top - (nargs + 1));  /* start 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
   else
     luaG_runerror(L, "cannot resume non-suspended coroutine");
     luaG_runerror(L, "cannot resume non-suspended coroutine");
@@ -349,15 +354,18 @@ LUA_API int lua_yield (lua_State *L, int nresults) {
   CallInfo *ci;
   CallInfo *ci;
   lua_lock(L);
   lua_lock(L);
   ci = L->ci;
   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);
   lua_unlock(L);
   return -1;
   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
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -393,8 +393,14 @@ StkId luaV_execute (lua_State *L) {
     const Instruction i = *pc++;
     const Instruction i = *pc++;
     StkId ra;
     StkId ra;
     if (L->hookmask >= LUA_MASKLINE &&
     if (L->hookmask >= LUA_MASKLINE &&
-        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE))
+        (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
       traceexec(L);
       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' */
     /* warning!! several calls may realloc the stack and invalidate `ra' */
     ra = RA(i);
     ra = RA(i);
     lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base);
     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) {
           if (firstResult > L->top) {  /* yield? */
           if (firstResult > L->top) {  /* yield? */
             (L->ci - 1)->u.l.savedpc = pc;
             (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;
             return NULL;
           }
           }
           /* it was a C function (`precall' called it); adjust results */
           /* it was a C function (`precall' called it); adjust results */