From 9bab2cf55d9b151d730c1461e3882a5fbc7d790d Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 18 Nov 2002 13:24:11 -0200 Subject: [PATCH] support for yield inside hooks --- ldo.c | 44 ++++++++++++++++++++++++++------------------ lvm.c | 13 +++++++++---- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/ldo.c b/ldo.c index 176cf0da..02f0d20b 100644 --- a/ldo.c +++ b/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; ibase + 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; ibase + 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; } diff --git a/lvm.c b/lvm.c index e9f122d0..29dcc56d 100644 --- a/lvm.c +++ b/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 */