lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


于 2012-6-6 7:30, Erik Cassel 写道:
I've seen conflicting information on the Lua list about calling
lua_yield inside a hook. Can somebody state authoritatively if this is
supported or not?

A comment in luaV_execute code implies that it is legal (5.1 source):

       if (L->status == LUA_YIELD) {  /* did hook yield? */
         L->savedpc = pc - 1;
         return;
       }


Here is a very simple test:

static void hook(lua_State* l, lua_Debug* ar)
{
    lua_getinfo(l, "n", ar);
    printf("Line hook %d\n", ar->currentline);
    lua_yield(l, 0);
}

void debugTest()
{
    lua_State* l = luaL_newstate();
    luaL_openlibs(l);
    lua_sethook(l, hook, LUA_MASKLINE, 0);

    luaL_loadstring(l,
       "for i=1,5 do\n"
       "   print('iteration', i)\n"
       "end\n"
    );

    while (lua_resume(l, 0) == LUA_YIELD)
       printf("Yielding\n");
}

This doesn't work. I get an infinite loop with the following output:

Yielding
Line hook 1
Yielding
Line hook 1
Yielding
Line hook 1
...

Lua never steps beyond line 1.

Thanks,

-Erik


I think I've encountered the same "bug" before, but with the LUA_MASKCOUNT hook,.
after some debugging, I found this is due to the way the Lua VM handles
the LUA_MASKLINE hook and the LUA_MASKCOUNT hook.

the VM check for condition for the LUA_MASKLINE hook or LUA_MASKCOUNT hook
*BEFORE* executing an instruction. including the *FIRST* instruction of a function/chunk.

and for your condition, i.e. the LUA_MASKLINE hook, the VM *ALWAYS* call the line hook
when entering an new function. so your hook is called, and the hook yielded.
then the VM "recover" the saved pc, since the "trapped instruction" has not been executed yet.
and then the VM just yielded itself, by returning to the lua_resume call directly,

so this came the problem. when you resume the thread next time, its state is just fresh, since
not a single instruction had been executed yet.
so the infinite loop appeared.

the same problem exists with the LUA_MASKCOUNT, when the hookcount is set to 1, which means
the VM should call the hook every single instruction. but the VM call the hook before the instruction is
actually executed, so if the hook yield, the VM won't go forward any more.

I suppose this a real BUG, but I suppose the situation is really rare in practice.

there is a simple work around for your situation: you don't yield at the first line when your line hook is called.
after that, the VM would call your line hook only when the line number increased,
so the VM is sure to have executed some instructions between two consecutive hook calls, so it won't get stuck.


good luck.