JakobOvrum/LuaD

Lua coroutines/threads support

odraencoded opened this issue · 2 comments

Ok, I really could use some help using coroutines/threads in LuaD.

To begin with, if I create a coroutine like this:

lua.doString(`foo = coroutine.create(...)`);

How do I get the lua_State* or LuaState associated with it?

There is no LuaState conversion. You can't LuaObject.to!LuaState, and you can't LuaObject.to!lua_State* either. So you have to push the object and use the C function lua_tothread instead.

Turns out for whatever reason LuaObject doesn't expose its push method. It's marked as private. So you must push pushValue instead.

It took me some time but I was able to do it using this code:

lua_State* toLuaThread(LuaObject obj) {
    lua_State* L = obj.state;
    L.pushValue(obj);
    lua_State* thread_state = lua_tothread(L, -1);
    lua_pop(L, 1);
    return thread_state;
}
auto foo_d_wrapper = lua.get!LuaObject("foo");
lua_State* foo_c_thread = toLuaThread(foo_d_wrapper);

Now I got the thread, but there is no way to lua_resume from LuaD, so another C function has to be called.

int status = lua_resume(foo_c_thread, 0);

The lack of support so far was kind of frustrating but everything went well so far and I could use part of the library. But then I had to lua_yield from a function.

For lua_yield to work properly, its return value must be returned by the C function calling it. So something like this:

extern(C) int foo_calls_me(lua_State* L) {
    return lua_yield(L, 0);
}

Sure there must be a way I could do this with a D function, right?

Well, no. There is not.

LuaD will handle the returning values of D functions and C functions that don't comply with that signature, and that means it will either return 0 or some other calculated value that has nothing to do with lua_yield.

Well, at least I could reuse LuaD amazing templating code to turn that alien lua_State* into typed arguments, right?

Nope. Same reason as LuaObject.push, the extremely convenient functionWrapper is marked as private. Even argsError is marked as private. Everything is private here. This sucks D:

TL;DR: coroutine support please.

For lua_yield to work properly, its return value must be returned by the C function calling it.

I don't believe it does.
lua_yield will longjmp out; it never returns.

Indeed LuaD contains an intermediate layer of template code that operates on the Lua stack, but these primitives are intended to be internal. The goal of the library is to abstract away the Lua stack with higher level expressions, without sacrificing performance.

Coroutines are indeed a blind spot in the LuaD interface.

Until they are properly supported I recommend using the C API (exposed in the luad.c package) for functions that operate on coroutines, as mixing the C API and the LuaD API within the same function can be hazardous. Function pointers with the signature extern(C) int function(lua_State*) are given special handling in the LuaD API so it's possible to mix the two APIs at function level.