Lua setfenv on threads doesnt seem to work - c

I want to load some functions on a lua state, and then be able to invoke the functions from lua threads.
I am trying to setfenv on the threads, so that the variables created by them are confined to the threads and not appear in the global env.
lua_State *L = luaL_newstate();
luaL_openlibs(L);
dostring(L, "function f1() my_var = 100 print('var set') end");/* create func on state */
/* ^-- a wrapper which does loadstring + pcall with error handling */
lua_State *l1 = lua_newthread(L);
lua_pushthread(l1); /* l1: t */
lua_newtable(l1); /* l1: t T1{} */
lua_newtable(l1); /* l1: t T1{} T2{} */
lua_getglobal(l1, "_G"); /* l1: t T1{} T2{} _G */
lua_setfield(l1, -2, "__index"); /* l1: t T1{} T2{} ( T2.__index = _G) */
lua_setmetatable(l1, -2); /* l1: t T1 ( T1{}.mt = T2 ) */
if (!lua_setfenv(l1, -2)) /* l1: t (t.fenv = T1) */
printf("setfenv fail!\n");
lua_pop(l1, 1);
dostring(l1, "print('l1: ', my_var)"); /* --> nil (expected) */
dostring(l1, "f1() print('l1: ', my_var)"); /* --> l1: 100 (ok) */
dostring(L, "print('L: ', my_var)"); /* --> L: 100 (No!) */
Am I doing anything wrong here ?
(I don't want to load the function on the threads, because there can be a lot of them, and
loading them once on the state seems to be the right approach)
--Edit--
The solution, seems to be:
create a new env table for each thread (with __index = _G)
for each function which runs within it, do setfenv(f1, getfenv(0))

Each function has its own fenv. f1's fenv is _G, so when called (no matter which thread it is called in), it sets the global variable in _G.
One option is to explicitly reference the thread environment from f1 e.g.
function f1()
local env = getfenv(0)
env.my_var = 100
print('var set')
end
Another is to give each thread a private copy of f1.
A third option is to create a proxy fenv (the same one for all threads & functions) with __index and __newindex metamethods that delegate to the current thread environment (i.e. getfenv(0).):
-- Step 1: Create the shared proxy object that delegates to the
-- current thread environment.
local tlproxy = {} -- Always empty
local tlproxy_mt = {}
function tlproxy_mt:__index(k)
return getfenv(0)[k]
end
function tlproxy_mt:__newindex(k, v)
getfenv(0)[k] = v
end
setmetatable(tlproxy, tlproxy_mt)
-- Step 2: Give each new thread a new, empty environment table.
local tenv_mt = {}
tenv_mt.__index = _G -- allows access to _G.math etc.
local function createThread(f)
local thread = coroutine.create(f)
-- These functions will not work as expected if called from the new thread,
-- so disable them.
local tenv = {
load=false, loadfile=false, loadstring=false,
module=false, require=false
}
setmetatable(tenv, tenv_mt)
debug.setfenv(thread, tenv)
return thread
end
-- Step 3: When a function should use thread-local variables, it should be
-- given 'tlproxy' as its fenv.
function f1()
my_var = 0
while true do
my_var = my_var + 1
coroutine.yield(my_var)
end
end
setfenv(f1, tlproxy)
local c1 = createThread(f1)
local c2 = createThread(f1)
-- Output should be 1, 1, 2, 2...
-- Without thread-locals it would be 1, 2, 3, 4...
for _ = 1, 100 do
print(coroutine.resume(c1))
print(coroutine.resume(c2))
end
52,1 Bot

Related

Lua C API - attaching data to a coroutine

Is there a way to attach data to a coroutine, or at least to somehow identify different coroutines?
I am trying to implement a timer API where the timers are controlled by the host, that looks something like the following on the Lua side:
function callback()
local timer = ElapsedTimer()
...
end
function main()
local timer = CreateTimer(...)
StartTimer(timer, callback, ...)
end
The StartTimer() call sends the timer and callback to the C side, and the C side will eventually call the callback in a new coroutine.
The call to ElapsedTimer() needs to return data that is specific to this coroutine/thread, i.e. in this case the timer.
In pseudo code:
int StartTimer(lua_State* L) {
auto timer = ...;
auto coroutine = ???
coroutine.userdata = &timer; // But probably store an actual structure with more pointers
return 0;
}
int ElapsedTimer(lua_State* L) {
auto coroutine = ???
auto timer = (Timer*)coroutine.userdata;
lua_pushlightuserdata(L, timer)
return 1;
}
This is what userdata is for:
int StartTimer(lua_State* L) {
TimerStruct timer = (TimerStruct*)lua_newuserdata(L, sizeof(TimerStruct));
//allocates some memory and returns pointer to it
timer->//...
// lua_setuservalue will let you bind the callback to the timer
return 1; //actually return it
}
Also it is going to be easier to pass the timer along
function callback(timer)
...
end
That way the lua code doesn't need to query that value. It already got it.
I just now realized I need to use lua_newthread to create the coroutine, which means I have a separate lua_State object.
This means I can always create a mapping between the coroutine's state and whatever data I want in the host language (e.g. in a map data structure)

Lua - pcall with "entry point"

I am loading Lua script with:
lua_State * L = lua_open();
luaL_openlibs(L);
const char lua_script[] = "function sum(a, b) return a+b; end print(\"_lua_\")";
int load_stat = luaL_loadbuffer(L,lua_script,strlen(lua_script),lua_script);
lua_pcall(L, 0, 0, 0);
Now I can call
lua_getglobal(L,"sum");
and get result from it on C-side
However, when I call lua_pcall, script is executed and it leads to output "_lua_" to console. Without lua_pcall, I cannot later access lua_getglobal. Is there any way around this? I dont want to call lua_pcall before setting "entry point" function via lua_getglobal.
If you can modify the script, a different approach to this is to pack your initialization code (the print and whatever else may be there) into a separate function, like so:
lua_State * L = lua_open();
luaL_openlibs(L);
const char lua_script[] = "function sum(a,b) return a+b end return function() print'_lua_' end";
int load_stat = luaL_loadbuffer(L,lua_script,strlen(lua_script),lua_script);
lua_pcall(L, 0, 1, 0); // run the string, defining the function(s)…
// also puts the returned init function onto the stack, which you could just leave
// there, save somewhere else for later use, … then do whatever you need, e.g.
/* begin other stuff */
lua_getglobal(L, "sum");
lua_pushinteger( L, 2 );
lua_pushinteger( L, 3 );
lua_pcall(L, 2, 1, 0);
printf( "2+3=%d\n", lua_tointeger(L,-1) );
lua_pop(L, 1);
/* end other stuff (keep stack balanced!) */
// and then run the init code:
lua_pcall(L, 0, 0, 0); // prints "_lua_"
Now, while you still have to run the chunk to define the function(s), the other initialization code is returned as a function which you can run at a later time / with a modified environment / … (or not at all, if it's unnecessary in your case.)
The function sum is not defined until you run the script because function definition is an assignment in Lua, and it needs to be executed.
So, there is no way to avoid running the script that defines sum. That is what lua_pcall does. You could use lua_call, but then you wouldn't be able to handle errors.

How to construct a named list (a SEXP) to be returned from the C function called with .Call()?

I call C code via .Call("foo", <args>), where foo calls other C
functions, computes the result and returns it. The result is a list
of length 3 and I would like to name this list. To this end, foo
does this:
/* Construct result list from variables containing the results */
SEXP res = PROTECT(allocVector(VECSXP, 3)); /* list of length 3 */
SET_VECTOR_ELT(res, 0, ScalarReal(a)); /* numeric(1) */
SET_VECTOR_ELT(res, 1, somenumericvector); /* numeric(<some length>) */
SET_VECTOR_ELT(res, 2, ScalarInteger(i)); /* integer(1) */
/* Name components and return */
SEXP nms = PROTECT(allocVector(STRSXP, 3)); /* names as SEXP */
char *nms_ = CHAR(STRING_ELT(nms, 0)); /* pointer to names */
char *names[3] = {"result_numeric", "result_numeric_vector", "result_integer"};
for(i = 0; i < 3; i++) nms_[i] = names[i];
setAttrib(res, R_NamesSymbol, nms);
UNPROTECT(1);
return res;
Is this a/the correct way of constructing a named list of length 3?
The C function indeed returns back to R but once I assign the output to a
variable in R, I immediately get a segmentation fault. What might be wrong? I
can put 'debug statement's' (simple printf("...\n") right before the above 'return
res;' and they are executed fine.
Is there any convenient way to debug C code called from R?
An alternative to BrodieG's answer is to use mkNamed from Rinlinedfuns.h (which contains an example of how to use mkNamed).
/* Construct named result list from variables containing the results */
const char *names[] = {"result_numeric", "result_numeric_vector",
"result_integer", ""}; /* note the null string */
SEXP res = PROTECT(mkNamed(VECSXP, names)); /* list of length 3 */
SET_VECTOR_ELT(res, 0, ScalarReal(a)); /* numeric(1) */
SET_VECTOR_ELT(res, 1, somenumericvector); /* numeric(<some length>) */
SET_VECTOR_ELT(res, 2, ScalarInteger(i)); /* integer(1) */
UNPROTECT(1);
return res;
Since you ask for the plain vanilla way, you need to create an R character vector from the C strings using mkChar and SET_STRING_ELT:
for(i = 0; i < 3; i++) SET_STRING_ELT(nms, i, mkChar(names[i]));
Right now, you are trying to use the raw C string as an R object, which won't work.
Re:debugging, you can use PrintValue in C code to print out R objects.
All this said, unless you have a very specific reason for wanting plain vanilla, you should consider Rcpp.
Per #nrussell's good advice, a solution in a single statement (broken over four lines for legibility)
R> cppFunction('List marius(double a, NumericVector b, int c) \
{ return List::create(Named("resnum")=a,\
Named("resvec")=b, \
Named("resint")=c); }')
R> marius(1.2, sqrt(3:5), 42L)
$resnum
[1] 1.2
$resvec
[1] 1.73205 2.00000 2.23607
$resint
[1] 42
R>

How to retrieve a value in stack in lua script?

I'm embedding lua in my C application.
I'm pushing a variable into stack from C side, and want to retrieve it in the lua script itself.
What can I use to get the pushed value in the stack in the script file?
C code:
// ...
result = lua_load(L, luaByteCodeReader, file, "script", "bt");
lua_pushinteger(L, session_id);
if( lua_pcall(L, 1, 0, 0) != 0 )
// ...
In the Script I want to retrieve the session_id value
local session_id = ...
print "Start"
for i = 1, 10 do
print(i, session_id)
end
print "End"
Problem is you're passing parameters to the script loading, depending on your situation you may set a global value instead or call a function.
For instance, say you have a on_init function on your script:
function on_init(session_id)
...do something...
end
You can load the script as you're doing, then get the on_init function on top of the stack and call it with your parameter:
lua_getglobal(L, "on_init");
lua_pushnumber(L, session_id);
/* call the function with 1 arguments, return 0 result */
lua_call(L, 1, 0);
And it's a little bit cleaner.

Lua references between objects

I implemented Simple Lua class in C. Usage of class:
require("test")
function foo()
local t1 = test()
local t2 = test()
t1:attach(t2)
return t1
end
o = foo()
-- some code
o = nil
attach function:
int class_attach(lua_State *L)
{
module_data_t *mod = luaL_checkudata(L, 1, "test");
luaL_checktype(L, 2, LUA_TUSERDATA);
module_data_t *child = lua_touserdata(L, 2);
printf("%p->%p\n", (void *)mod, (void *)child);
return 0;
}
After return from function t2 object is cleaned by gc.
Is it possible to prevent that. Set reference between t1 and t2 objects? (calling __gc metamethod (of t2 object) only after parent module (t1) is cleaned).
Simple way is use table:
function foo()
ret = {}
ret[1] = test()
ret[2] = test()
ret[1]:attach(ret[2])
return ret
end
but that is not fun way.
Thanks!
You can set it in the Lua registry. This is effectively a global table which can only be accessed in C code. You can set registry[t1] = t2;. As long as you unset this appropriately in t1's __gc. This can also scale to 1:n mappings, as you could do, for example, registry[t1].insert(t2) for multiple "children".
I've had the same issue in the past. The simple reason for this is that Lua doesn't know about the connection established in C code (there's none right now, but I guess it's going to be done somewhere).
You don't have to do the table approach, just link the two objects/tables/whatever on the Lua side as well:
function foo()
local t1 = test()
local t2 = test()
t1:attach(t2)
t1._dummy_link = t2
return t1
end
Just keep in mind that's only good for 1:1 relationships. For more complex stuff you'll still have to use some kind of table or a similar approach. The probably cleanest way to do this would be doing the linking on the Lua side and just adding a callback to C in case there's C code to be run as well.

Resources