From the documentation, I understand that a new thread created, must be
properly anchored before use.
To do that, I want to keep a reference to the new thread in the registry,
(Table[thread-addr] = thread) for that, I am doing this:
lua_State *L = NULL;
lua_State *L1 = NULL;
int tref = LUA_NOREF;
L = luaL_newstate(); // main lua thread/state
// create a table in registry: Table[thr-addr] = Thread
lua_newtable(L);
tref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pop(L, 1);
L1 = lua_newthread(L);
// Anchor it
lua_rawgeti(L, LUA_REGISTRYINDEX, tref);
lua_pushnumber(L, (ptrdiff_t) L1);
lua_pushlightuserdata(L, L1);
lua_settable(L, -3);
Once I am done with the thread, I plan to set the Table[thread-addr] = nil
Is this sufficient ? or I should also set a meta-table to it, with weak keys/values ?
Thanks.
Once I am done with the thread, I plan to set the Table[thread-addr] = nil Is this sufficient? or I should also set a meta-table to it, with weak keys/values?
A weak table is used if you don't want objects it references to count as real 'strong' references. So Lua is allowed to GC an object if there are no other references to it even if the weak table still refers to that object.
From the use case you described, making Table weak probably isn't appropriate here since Lua might collect that coroutine object before you have a chance to use it.
Also your example code here:
L1 = lua_newthread(L);
// Anchor it
lua_rawgeti(L, LUA_REGISTRYINDEX, tref);
lua_pushnumber(L, (ptrdiff_t) L1);
lua_pushlightuserdata(L, L1);
lua_settable(L, -3);
the lua_pushlightuserdata function is meant for C pointers. The coroutine object lifetime won't get managed by Lua correctly if you tell it to treat the coroutine object like a C data pointer. For this you probably meant to use lua_pushthread instead.
Related
I am trying to wrap ncurses in Lua using the C API. I am working with the stdscr pointer: This is NULL before initscr is called, and initscr is called from Lua by design of my bindings. So in the driver function I do this:
// Driver function
LUALIB_API int luaopen_liblncurses(lua_State* L){
luaL_newlib(L, lncurseslib);
// This will start off as NULL
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
lua_pushstring(L, VERSION);
lua_setglobal(L, "_LNCURSES_VERSION");
return 1;
}
This works as intended. The trouble comes when I need to modify stdscr. initscr is bound like this:
/*
** Put the terminal in curses mode
*/
static int lncurses_initscr(lua_State* L){
initscr();
return 0;
}
I need to moify the stdscr in the library to no longer be null. Example code from Lua side:
lncurses = require("liblncurses");
lncurses.initscr();
lncurses.keypad(lncurses.stdscr, true);
lncurses.getch();
lncurses.endwin();
But, lncurses.stdscr is NULL, so the it's essentially running the c equivalent of keypad(NULL, true);
My question being, how do I modify library values in Lua after the library is created?
You can use the registry.
Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it must take care to choose keys that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, or any Lua object created by your code. As with variable names, string keys starting with an underscore followed by uppercase letters are reserved for Lua.
Store a reference to the module table in the registry on creation.
LUALIB_API int luaopen_liblncurses(lua_State* L) {
luaL_newlib(L, lncurseslib);
// This will start off as NULL
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
lua_pushstring(L, VERSION);
lua_setglobal(L, "_LNCURSES_VERSION");
// Create a reference to the module table in the registry
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "lncurses");
return 1;
}
Then when you initscr, update the field.
static int lncurses_initscr(lua_State* L) {
initscr();
// Update "stdscr" in the module table
lua_getfield(L, LUA_REGISTRYINDEX, "lncurses");
lua_pushlightuserdata(L, stdscr);
lua_setfield(L, -2, "stdscr");
return 0;
}
I am attempting to create a GC finalizer for a function value by storing it in a weak table using the C API.
I started off by writing a prototype in pure Lua 5.2:
local function myfinalizer()
print 'Called finalizer'
end
function myfunc()
print 'Called myfunc'
end
local sentinels = setmetatable({}, { __mode='k' })
sentinels[myfunc] = setmetatable({}, { __gc=myfinalizer })
myfunc()
myfunc = nil
collectgarbage 'collect'
print 'Closing Lua'
Resulting output:
Called myfunc
Called finalizer
Closing Lua
The prototype seems to be working as intended. Below is the C version:
#include <stdlib.h>
#include <stdio.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
static int my_finalizer(lua_State *L)
{
puts("Called finalizer");
return 0;
}
static int my_func(lua_State *L)
{
puts("Called myfunc");
return 0;
}
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// create sentinels table (weak keys) in registry
lua_newtable(L); // t
lua_newtable(L); // t mt
lua_pushstring(L, "k"); // t mt v
lua_setfield(L, -2, "__mode"); // t mt
lua_setmetatable(L, -2); // t
lua_setfield(L, LUA_REGISTRYINDEX, "sentinels"); //
// push global function and register as sentinel
lua_pushcfunction(L, my_func); // f
lua_getfield(L, LUA_REGISTRYINDEX, "sentinels"); // f t
lua_pushvalue(L, 1); // f t k
lua_newuserdata(L, 0); // f t k v
lua_newtable(L); // f t k v mt
lua_pushcfunction(L, my_finalizer); // f t k v mt v
lua_setfield(L, -2, "__gc"); // f t k v mt
lua_setmetatable(L, -2); // f t k v
lua_settable(L, -3); // f t
lua_pop(L, 1); // f
lua_setglobal(L, "myfunc"); //
// execute test script and exit
if (luaL_dostring(L, "myfunc(); myfunc=nil; collectgarbage'collect'")) {
printf("Error: %s\n", lua_tostring(L, -1));
}
lua_gc(L, LUA_GCCOLLECT, 0); // suggestion: two full gc cycles
fflush(stdout); // suggestion: immediate flush
puts("Closing Lua");
lua_close(L);
fflush(stdout);
return EXIT_SUCCESS;
}
Compiled using:
$ gcc -std=c99 -Wall -Werror -pedantic -O2 -o main main.c -ldl -llua52 -lm
Resulting output:
Called myfunc
Closing Lua
Called finalizer
The C version has a few minor differences:
Instead of a local sentinels table I am storing in the registry.
Using a zero sized userdata instead of a table for sentinel value with __gc metamethod.
I am confused as to why in the C version the myfunc finalizer doesn't execute after running a full collection cycle. What am I doing wrong?
As the Lua manual states:
Only objects that have an explicit construction are removed from weak tables. Values, such as numbers and light C functions, are not subject to garbage collection, and therefore are not removed from weak tables (unless its associated value is collected).
Your my_func is pushed without any upvalues, so it is a light C function, and it isn't removed from weak tables during garbage collection, so the associated userdata does not become garbage before you close the Lua state. Your code should work if you use a Lua function instead of my_func, or if you push my_func with upvalues (and if you fix the order of the arguments in the lua_gc call!).
To summarize, the following value types are not removed from weak tables (given that their associated keys/values aren't removed either):
booleans
numbers
strings
light userdata
light C functions (Lua 5.2 only)
As a consequence your program should work fine with Lua 5.1 because there are no light C functions (you still have to fix the lua_gc call).
I have written some code to separate registering custom functions and the __newindex and __index functions into 2 separate functions. The goal of my code is to have functions and variables visible to the Lua script writer that are organized based upon sublevels of specificity. For example, the user would have available the following commands:
orc.chief.attack();
orc.chief.flee();
orc.chief.hp = 100;
orc.pawn.attack();
elf.wood.attack();
elf.wood.hp = 200;
So basically a system with 2 tiers and then a function call or a variable. If I understand Lua correctly, that is a metatable in a table in a table. When the user sets the variable, it should trip a __newindex call (not only to handle setting the value but to access a physical object that will animate through motors). I also assume that the chief table in the table orc just sees lots of functions assigned to it regardless whether it is attack or __newindex. To make it easier to add new variables and functions as the code develops, I have created 2 functions: one to create a function and one to create a variable. The function create just registers the functions and the variable create just makes a new table element and registers the functions for __newindex and __index. Below is the code:
int orcChiefhp;
luaL_Reg Orc_Module[] = {
{"attack", OrcAttack},
{"flee", OrcFlee},
{NULL, NULL}};
const luaL_Reg orcChief_metareg[] = {
{"__index", orcChief__index},
{"__newindex", orcChief__newindex},
{NULL, NULL}};
int OrcAttack(lua_State *L)
{
//code to cause the motors to swing the weapon...
return 0;//0 parameters come back as the data
}
int orcChief__newindex(lua_State *L)
{
const char *idx;
if(lua_isstring(L,2))
{
idx = lua_tostring(L,2);//gets the string so we can get the variable of the struct
if(strcmp(idx, "hp")==0)
{
lua_pushnumber(L, orcChiefhp);
}
else
lua_pushnil(L);
}
return 1;
}
void registerFunctions(lua_State *L, const char *libname, const char *sublibname, const luaL_Reg *funcs)
{
int isitnil;
lua_getglobal(L, libname);
isitnil = lua_isnil(L, -1);
if(isitnil)
{
lua_pop(L, 1);
lua_newtable(L); // create 'libname' table
}
// no sublib: just import our library functions directly into lib and we're done
if (sublibname == NULL)
{
luaL_setfuncs(L, funcs, 0);
}
// sublib: create a table for it, import functions to it, add to parent lib
else
{
lua_newtable(L);
luaL_setfuncs(L, funcs, 0);
lua_setfield(L, -2, sublibname);
}
if(isitnil)
lua_setglobal(L, libname);//this will pop off the global table.
else
lua_pop(L, 1);//the global table is still on the stack, pop it off
}
void registerIntegerVariable(lua_State *L, const char *libname, const char *sublibname, const char *variableName,
const char *metatableName, const luaL_Reg *metatableFuncs, int defaultValue)
{
int isLibnameNil;
int isSubnameNil;
lua_getglobal(L, libname);//get the libname
isLibnameNil = lua_isnil(L, -1);//check to see if it exists
if(isLibnameNil)//if it doesn't exist, create a new one
{
lua_pop(L, 1);//pop off the nil
lua_newtable(L); // create 'libname' table
}
// no sublib: just import our library functions directly into lib and we're done
if (sublibname == NULL)//if we want the functions at the lib level then just set the functions
{
lua_pushstring(L, variableName);//push the variable name
lua_pushnumber(L, defaultValue);//push the default value on the stack
lua_rawset(L, -3);//add the variable to the table (rawset is like settable but doesn't call __index)
luaL_newmetatable(L, metatableName);//create the metatable
luaL_setfuncs(L, metatableFuncs, 0);//set the metatable functions for __newindex and __index
lua_setmetatable(L, -2);//set the metatable to the libtable
}
// otherwise we need to create a table for the sublibname, import functions to it, add to parent lib.
else
{
lua_getfield(L, -1, sublibname);//see if the sublibname is under the global libname
isSubnameNil = lua_isnil(L, -1);//is it a nil
if(isSubnameNil)//if it is, then we need to create the sublibname
{
lua_pop(L, 1);//pop off the nil
lua_newtable(L);//creates the new sublibname table
}
lua_pushstring(L, variableName);//push the variable name
lua_pushnumber(L, defaultValue);//push the default value on the stack
lua_rawset(L, -3);//add the variable to the table and push it (rawset is like settable but doesn't call __index)
luaL_newmetatable(L, metatableName);//create the metatable
luaL_setfuncs(L, metatableFuncs, 0);//add the metamethods
lua_setmetatable(L, -2);//set the metatable to the sublibname
if(isSubnameNil)
lua_setfield(L, -2, sublibname);//now we need to add the sublibname to the libname
}
if(isLibnameNil)
lua_setglobal(L, libname);//set the global name if it was new
else
lua_pop(L, 1);
}
Then, in my main() I call the functions like this:
execContext = luaL_newstate();
//adding lua basic library
luaL_openlibs(execContext);
//now register all the functions with Lua
registerFunctions(execContext, "orc", "chief", Orc_Module);
registerFunctions(execContext, "orc", "pawn", Orc_Module);
registerFunctions(execContext, "elf", "wood", Elf_Module);
//now register all the variables with Lua
registerIntegerVariable(execContext, "orc", "chief", "hp", "chief_meta", orcChief_metareg, 0);
When I run the code and pump in Lua scripts, orc.chief.attack() calls my OrcAttack() function but orc.chief.hp = 100 never calls my orcChief__newindex() function. I have even commented out the registerFunctions calls in case they were interfering somehow and just the registerIntegerVariable by itself still won't trigger the orcChief__newindex(). Any ideas?
__newindex is not called when you set a field in a table. It is called when you set a new field in a table. If the field already exists, __newindex will not be called.
If you want __newindex to be called for every set operation on a table, you can't allow set operations to actually modify that table. This is generally done by creating an empty table, called a proxy table, which the user uses. The proxy table is actually empty and must always remain so; you intercept all of the get and set calls, piping them to an internal table that the user never sees don't have access to.
Or you use some userdata instead of a table. __newindex is always called for them.
Well there are no problems to push C function as function member or register C function as lua function with lua_register(L, lua_func_name, c_func);
But how tell lua what i want to pass luaFoo() as function callback param for "foober" from C?
lua_pushcfunction - pushes C function, lua_pushstring pushes just a plain string, so callback field became a string, not a function.
Lua Code:
CALLBACKS = {};
FOO = 0;
function luaFoo()
FOO = FOO + 1;
end;
function addCallback(_name, _callback)
CALLBACKS[_name] = _callback;
end;
function doCallback(_name)
CALLBACKS[_name]();
end;
C code:
static int c_foo(lua_State* l)
{
printf("FOO\n");
return 0;
}
/*load lua script*/;
lua_State* l = /*get lua state*/;
lua_getglobal(l, "addCallback");
lua_pushstring(l, "foober");
//What push for luaFoo()
lua_pushcfunction(l, c_foo);
lua_call(l, 2, 0);
lua_getglobal(l, "doCallback");
lua_pushstring(l, "foober");
lua_call(l, 1, 0);
Similiar - if i get C functions which already registered with lua_register, how pass them as callback param from C. So we register c_foo => c_foo exist as lua function, how to tell what we want to pass "c_foo" as callback func param.
Remember that:
function luaFoo()
...
end
is equivalent to this, in Lua:
luaFoo = function()
...
end
Therefore, your question ultimately boils down to, "I have a value in the global table. How do I push it onto the stack?" The fact that this value is a function is irrelevant; a function value in Lua is no different from an integer value, which is no different than a string value. Obviously you can do different things with them, but you just want to copy them around. That works the same regardless of what the value is.
The function you're looking for is lua_getglobal.
As for your second question, you can do it in one of two ways. You can either get the function value you registered from the global table, or you can simply re-register it with lua_pushcfunction. Since you're not using upvalues, re-registering it doesn't really have any downsides.
Oh, and one more thing, on code style. Lua doesn't require ; at the end of statements. You can do it (to make C-native programmers feel more comfortable), but it's not necessary.
I have researched this subject and tried various approaches but I can't implement the behavior I have in mind (I'm not even sure it's possible). Basically, I have several userdata objects created in C that can be accessed by their metatable, like this:
Main.lua
config.display_width = 1280
What I'd like to do is to "force" the config namespace to a specific script. You've guessed it, I need to protect a configuration file so that users are restricted to deal only with the config metatable. Like this:
Config.lua
display_width = 1280
And I know I have to do something like this in C:
// Register the config metatable and its methods
luaL_loadfile(L, "my_config.cfg");
lua_getglobal(L, "config"); // Is this necessary?
lua_setfenv(L, -2); // I know this has to be used, but how?
lua_pcall(L, 0, 0, 0);
Thank you in advance, this one is driving me crazy!
PS: For the record, I really need to keep the config userdata as it is because it's binded to a C structure. In consequence, I'm not concerned about "losing" the Lua state or declared variables between different environments.
Adding the following information. This is how the config userdata is being created:
const struct luaL_Reg metaconfig[] =
{
{"__index", l_get},
{"__newindex", l_set},
{NULL, NULL}
};
lua_newuserdata(L, sizeof(void *));
luaL_newmetatable(L, "metaconfig");
luaL_register(L, NULL, metaconfig);
lua_setmetatable(L, -2);
lua_setglobal(L, "config");
So every time the user sets or gets values from the config userdata I update the C structure via the __index or__newindex methods.
you don't really need a global representing the config table, you can do with a lua_ref too.
Here this works as expected (I guess):
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
int main (void){
int idxConfig, res;
lua_State *L = luaL_newstate();
if ((res = luaL_loadfile(L,"my_config.cfg")) != 0){//Load file
printf("Got error code %d loading file my_config.cfg, exiting",res);
exit(-1);
}
lua_newtable(L); // new config table
lua_pushvalue(L,-1);// duplicate table
idxConfig = lua_ref(L,LUA_REGISTRYINDEX); // take a reference to the table (pops it)
lua_setfenv(L,-2); // pop table, set as environment for loaded chunk
lua_call(L,0,0); // load config -- nothing on stack
lua_rawgeti(L,LUA_REGISTRYINDEX,idxConfig); //push config table
lua_getfield(L,1,"display"); //read out "display"
lua_Integer disp_width = lua_tointeger(L,-1);
printf("Display width = %d",(int) disp_width);
lua_close(L);
exit(0);
}