lua-users home
lua-l archive

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


Peng,

> I suppose the situation is really rare in practice.

Well, this seems to be the best way to write a debugger that doesn't
lock up my process. By yielding the current thread, I can pause the
thread and unwind the C++ stack to continue normal event handling.

> since not a single instruction had been executed yet.
> so the infinite loop appeared.

That explains the problem. I tweaked the code to skip the first hook
after a yield. This works fine if all statements are in separate
lines. It causes some inconsistent behavior if the "for" loop is all
in one line:

   for i=1,4 do print('iteration', i) end

In this case, the output is:

Yielding
Yielding
iteration 1
iteration 2
Yielding
iteration 3
iteration 4

As you can see, the debugger yields twice (!) before executing code
and the yields after every *other* iteration step.

In an ordinary debugger, you'd want to trap each step:

Yielding
iteration 1
Yielding
iteration 2
Yielding
iteration 3
Yielding
iteration 4

I don't think there is a fix for this problem, but at least there is a
workaround: Don't inline your blocks.

Does Lua 5.2 behave differently? If so that would be a major incentive
for me to upgrade!

-Erik







On Wed, Jun 6, 2012 at 7:36 AM, Peng Zhicheng
<pengzhicheng1986@gmail.com> wrote:
>
> 于 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.
>
>
>
>
>