Calling back into Lua from C code
Jun 8, 2016 · 2 minute readLuaC
The problem
One thing I found incredibly hard when adapting a large C codebase with Lua
code was the problem of calling back from C code into Lua callback when there’s
no auxiliary passed around void *
pointer available to also pass the
current lua_State.
Of course it would always be possible to just create a new state on-the-fly but if you do you won’t have access to any of the already setup Lua environment so your Lua callbacks might end up to be very complicated and heavy.
A solution
This solution might not be a workable solution for you but it certainly was for me. Two points are rather important here:
- There is an initialisation function which will be called at a defined point in time where the Lua environment is setup nicely for all potential Lua callbacks to work
- There’s no relevant program state stored in the Lua state, all program state is handled by the C code and can be accessed by the appropriate Lua functions in the global environment
If those prerequisites are met then one can use the lua_newthread
function
to create a copy of the current lua_State and store it in a static variable.
In essence this is what I’m doing:
static lua_State *iL = NULL;
void my_init (lua_State *L)
{
/* ... other initialisation code here ... */
iL = lua_newthread (L);
/* It's important to keep a reference to the new state somewhere,
* otherwise the garbage collector will eventually collect it */
luaL_ref (iL, LUA_REGISTRYINDEX);
}
At any later point you can use the iL variable, rather than the usual Lua C function signature with a single lua_State argument, to execute Lua code in order to manipulate the program state.
In closing
While this mechanism alone may in many cases only have limited usefulness since the callbacks themselves need to be C code and hence known at compile time (though it certainly is possible to e.g. let those callbacks execute specific Lua files from the filesystem and hence allow changes in behaviour without recompilation), it can be combined with other mechanisms to e.g. allow setting up Lua functions as callbacks – directly from Lua. But more about that in a later post. ;)
Until then, take care.