Search code examples
cmodulelualua-api

Pass upvalue to Lua 5.2 module in C


I am trying to create an experimentation environment for myself where my application runs as a telnet server for theoretically unlimited telnet clients that can execute Lua commands in their own Lua environment. For this, every client has its own thread as I want them to have their own windows message loop with their own specific needs.

I have created several modules accessible in Lua to do some fun stuff. I also want to be able to create a window from Lua, so I would like to add a module called "window" and add a "new" method. The problem is, I need to know what thread I am in (well, to be more specific, I need the class that I use to define the client the thread is handling with) and I don't know how to get it inside the C Lua functions for window.new.

With normal functions, you can add upvalues (I already have a simple window function that is able to create a window that is managed by the thread it is running in), but when creating modules, this is not so simple when you try to do it the standard way.

My window-module has the following typical luaopen function:

LUALIB_API int luaopen_window(lua_State *L)
{
    luaL_newmetatable(L, "window");
    luaL_setfuncs(L, reg_window_m, 0);
    luaL_newlib(L, reg_window_f);
    return 1;
}

My thread creates a Lua state and opens the necessary libs, including the window one:

luaL_requiref(L, "window", luaopen_window, 1);
lua_pop(L, 1);

I know that the function luaL_setfuncs supports upvalues, but it's already too late there. I don't have a way to pass the values to put in the up values.

I have tried to push them before calling luaL_requiref and pop them inside the luaopen_window function, pushing them again before the call to luaL_setfuncs but it doesn't work: the pushed values are gone because of how luaL_setfuncs works internally. I could of course write my own luaL_setfuncs that supports upvalues (well, I think I could), but there must already exist a better way?

Edit: BTW. I would like to prevent using a global Lua variable to store the pointer to my class. That could become a security risk and although this tool will probably never be used outside of my computer, I just want to code this right.


Solution

  • The luaopen_* functions are supposed to be called by require, and require doesn't pass extra arguments (besides module name and file path) to avoid the confusion when a second call with different arguments returns the cached result of the first call.

    However, you could store the thread/class in the registry table (at pseudo index LUA_REGISTRYINDEX) after creating the Lua state. Without the debug library the registry is inaccessible from Lua, so you should be safe. You can retrieve the class in your luaopen_window function and put it as upvalue to your methods, or access the registry from within your methods.

    To avoid conflicts with other modules that store information in the registry you can use the address of a static variable in your code as the table key.