[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: interrupting coroutines (was Re: Local Variables)
- From: William Ahern <william@...>
- Date: Mon, 11 Aug 2014 21:14:05 -0700
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.