lua-users home
lua-l archive

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

On 2016-09-03 15:39, Rain Gloom wrote:
> On Tue, Aug 30, 2016 at 7:20 AM, Daurnimator <> 
> wrote:
>> One of the more interesting things you can do here is inject a hook
>> that calls lua_yield. This means your top level "lua_resume" (or
>> lua_pcallk) will return, and you can perform some operation before
>> proceeding.
> Does this only work from C? I have tried a naive pure-Lua thread 
> implementation with debug.sethook(coroutine.yield,'',1) and it blew 
> up.


`debug.sethook` sets a ready-made C hook function[1] that calls the hook
function set from Lua.  This means there's an extra C layer in the way
that you can't yield through.

The hook is not a normal Lua C function/closure, but a raw C function.
So the hook can't lua_[p]callk & then yield.

My accumulated "C API cheats" contain the following crappy workaround
which I use whenever I need this functionality in Lua ("soft"/resumable
timeouts mostly - I run into that quite often...):

static void yieldhook( lua_State * L, lua_Debug * ar ) {
	lua_yield( L, 0 );

/* setyieldhook( coro, [count=0] ) ~~> sethook( coro, nil ) */
/* setyieldhook( coro, count ) ~~> sethook( coro, yield, "", count ) */
static int lcheat_setyieldhook( lua_State * L ) {
	lua_State * coro;
	int steps;
	luaL_checktype( L, 1, LUA_TTHREAD );
	coro = lua_tothread( L, 1 );
	steps = luaL_optinteger( L, 2, 0 );
	if (steps <= 0) {
		lua_sethook( coro, NULL, 0, 0 );
	} else {
		lua_sethook( coro, yieldhook, LUA_MASKCOUNT, steps );
	return 0;

It's a bit ugly...  One limitation is that it will only yield (and do
nothing else, not even return a special marker value from the yield).
You also can't `setyieldhook` and then clear it with `debug.sethook`.
(`debug.sethook`/`debug.gethook` store the hook info as an entry in the
registry with a userdata value as its key.  There may be several such
values, so it would be rather complex to identify the right one of those.)

It may still be enough or at least serve as a starting point.