lua-users home
lua-l archive

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


On Mon, Aug 11, 2014 at 11:16:40PM -0400, Sean Conner wrote:
> It was thus said that the Great William Ahern once stated:
> > On Mon, Aug 11, 2014 at 09:55:40PM -0400, Sean Conner wrote:
<snip>
> > >   But this won't handle the original problem:
> > > 
> > > 	coroutine.resume(coroutine.create(function() while true do end end))
> > 
> > Neither will using lua_sethook! IIRC this was discussed in another thread a
> > few weeks ago. Here's the relevant code in Lua (from 5.2 source code):
> > 
> > LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
> >   if (func == NULL || mask == 0) {  /* turn off hooks? */
> >     mask = 0;
> >     func = NULL;
> >   }
> >   if (isLua(L->ci))
> >     L->oldpc = L->ci->u.l.savedpc;
> >   L->hook = func;
> >   L->basehookcount = count;
> >   resethookcount(L);
> >   L->hookmask = cast_byte(mask);
> >   return 1;
> > }
> 
>   It diverts the flow of control within a coroutine, which is the point.
> 
> > Note that it only sets the hook for the currently running coroutine.
> 
> And the hook will gain control at the next possible point (since the code
> n question hooks calls, returns and next VM instruction).
>

So I just tested with Lua 5.2. We're both right/wrong. New Lua threads
inherit hooks, but each has an independent hook state. See lua_newthread in
lstate.c:

  ...
  L1->hookmask = L->hookmask;
  L1->basehookcount = L->basehookcount;
  L1->hook = L->hook;   
  ...

So if you set the global hook before the coroutine is created, then the
lua_sethook trick will work because the new coroutine will inherit the hook
parameters. However, if the coroutine is created before lua_sethook is
applied to the global state, then it won't work. You can test it yourself.

hook.c:

  #include <stdio.h>
  #include <lua.h>

  static lua_State *GL;

  static void hook(lua_State *L, lua_Debug *ar) {
    fprintf(stderr, "hook (state:%p global:%p)\n", (void *)L, (void *)GL);
  } /* hook() */

  int luaopen_hook(lua_State *L) {
    GL = L;
    lua_sethook(L, &hook, LUA_MASKCOUNT, 10);
    return 0;
  } /* luaopen_hook() */

test1.lua:

  require"hook"
  co = coroutine.create(function() for i=1,100 do end end)
  coroutine.resume(co) 

test2.lua:

  co = coroutine.create(function() for i=1,100 do end end)
  require"hook"
  coroutine.resume(co) 


It's also worth point out that when you require a module, the state passed
to the luaopen routine is the current coroutine. So modules like luaposix
which call lua_sethook on the same state used to load the module should
loudly document the behavior. This is one reason I don't want to use the
lua_sethook hack used in luaposix in my own unix module--I don't want
anything in a general-purpose module which can accidentally cause illegal
memory access, because people won't expect such behavior.