From ba484b9eb16dd62a7c3a5400a66eb952b654d3f0 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 10 Mar 2009 14:14:37 -0300 Subject: yielding across lua_call (first version) --- ldo.c | 103 ++++++++++++++++++++++++++---------------------------------------- 1 file changed, 41 insertions(+), 62 deletions(-) (limited to 'ldo.c') diff --git a/ldo.c b/ldo.c index effef571..bf21e609 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.53 2009/03/03 18:51:24 roberto Exp roberto $ +** $Id: ldo.c,v 2.54 2009/03/04 13:32:29 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -14,6 +14,7 @@ #include "lua.h" +#include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" @@ -365,7 +366,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** When returns, all the results are on the stack, starting at the original ** function position. */ -void luaD_call (lua_State *L, StkId func, int nResults) { +void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { global_State *g = G(L); if (++g->nCcalls >= LUAI_MAXCCALLS) { if (g->nCcalls == LUAI_MAXCCALLS) @@ -373,64 +374,41 @@ void luaD_call (lua_State *L, StkId func, int nResults) { else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } + if (!allowyield) L->nny++; if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ + if (!allowyield) L->nny--; g->nCcalls--; luaC_checkGC(L); } +static void finishCcall (lua_State *L) { + int n; + lua_assert(L->ci->u.c.cont != NULL); /* must have a continuation */ + lua_assert(L->nny == 0); + /* finish 'luaD_call' */ + G(L)->nCcalls--; + /* finish 'lua_callcont' */ + adjustresults(L, (L->ci + 1)->nresults); + /* call continuation function */ + lua_unlock(L); + n = (*L->ci->u.c.cont)(L); + lua_lock(L); + /* finish 'luaD_precall' */ + luaD_poscall(L, L->top - n); +} + + static void unroll (lua_State *L) { for (;;) { - Instruction inst; - luaV_execute(L); /* execute down to higher C 'boundary' */ - if (L->ci == L->base_ci) { /* stack is empty? */ - lua_assert(L->baseCcalls == G(L)->nCcalls); + if (L->ci == L->base_ci) /* stack is empty? */ return; /* coroutine finished normally */ - } - L->baseCcalls--; /* undo increment that allows yields */ - inst = *(L->savedpc - 1); /* interrupted instruction */ - switch (GET_OPCODE(inst)) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: - case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: - case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { - setobjs2s(L, L->base + GETARG_A(inst), --L->top); - break; - } - case OP_LE: case OP_LT: case OP_EQ: { - int res = !l_isfalse(L->top - 1); - L->top--; - /* metamethod should not be called when operand is K */ - lua_assert(!ISK(GETARG_B(inst))); - if (GET_OPCODE(inst) == OP_LE && /* "<=" using "<" instead? */ - ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE))) - res = !res; /* invert result */ - lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP); - if (res != GETARG_A(inst)) /* condition failed? */ - L->savedpc++; /* skip jump instruction */ - break; - } - case OP_CONCAT: { - StkId top = L->top - 1; /* top when __concat was called */ - int last = cast_int(top - L->base) - 2; /* last element and ... */ - int b = GETARG_B(inst); /* ... first element to concatenate */ - int total = last - b + 1; /* number of elements to concatenate */ - setobj2s(L, top - 2, top); /* put TM result in proper position */ - L->top = L->ci->top; /* correct top */ - if (total > 1) /* are there elements to concat? */ - luaV_concat(L, total, last); /* concat them (may yield again) */ - /* move final result to final position */ - setobj2s(L, L->base + GETARG_A(inst), L->base + b); - continue; - } - case OP_TFORCALL: { - lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP); - L->top = L->ci->top; /* correct top */ - break; - } - case OP_SETGLOBAL: case OP_SETTABLE: - break; /* nothing to be done */ - default: lua_assert(0); + if (!isLua(L->ci)) /* C function? */ + finishCcall(L); + else { /* Lua function */ + luaV_finishOp(L); /* finish interrupted instruction */ + luaV_execute(L); /* execute down to higher C 'boundary' */ } } } @@ -441,23 +419,22 @@ static void resume (lua_State *L, void *ud) { CallInfo *ci = L->ci; if (L->status == LUA_OK) { /* start coroutine? */ lua_assert(ci == L->base_ci && firstArg > L->base); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */ - return; /* done */ + if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ + luaV_execute(L); /* call it */ } else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; - if (isLua(ci)) /* yielded inside a hook? */ + if (isLua(ci)) { /* yielded inside a hook? */ L->base = L->ci->base; /* just continue its execution */ + luaV_execute(L); + } else { /* 'common' yield */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); - if (luaD_poscall(L, firstArg)) /* complete it... */ - L->top = L->ci->top; /* and correct top if not multiple results */ + G(L)->nCcalls--; /* finish 'luaD_call' */ + luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ } + unroll(L); } - unroll(L); } @@ -484,7 +461,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { if (G(L)->nCcalls >= LUAI_MAXCCALLS) return resume_error(L, "C stack overflow"); ++G(L)->nCcalls; /* count resume */ - L->baseCcalls += G(L)->nCcalls; + L->nny = 0; /* allow yields */ status = luaD_rawrunprotected(L, resume, L->top - nargs); if (status != LUA_OK && status != LUA_YIELD) { /* error? */ L->status = cast_byte(status); /* mark thread as `dead' */ @@ -494,7 +471,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { else { lua_assert(status == L->status); } - L->baseCcalls -= G(L)->nCcalls; + L->nny = 1; /* do not allow yields */ --G(L)->nCcalls; lua_unlock(L); return status; @@ -504,7 +481,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { LUA_API int lua_yield (lua_State *L, int nresults) { luai_userstateyield(L, nresults); lua_lock(L); - if (G(L)->nCcalls > L->baseCcalls) + if (L->nny > 0) luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; @@ -521,6 +498,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, int status; ptrdiff_t old_ci = saveci(L, L->ci); lu_byte old_allowhooks = L->allowhook; + unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); @@ -532,6 +510,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, L->base = L->ci->base; L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; + L->nny = old_nny; restore_stack_limit(L); } L->errfunc = old_errfunc; -- cgit v1.2.3-55-g6feb