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.
Related
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.
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
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'm not sure if the title correctly reflects my question.
I have a library implemented in C for lua provided to me by my employer.
They have it reading a bunch of data out of a modbus device such that:
readFunc(Address, numReads)
will start at Address and read numRead amount of registers. Currently this returns data in the following way:
A, B, C, D = readFunc(1234, 4)
However, we need to do 32+ reads at a time for some of our functions and I really don't want to have reply1, reply2... reply32+ listed in my code every time I do this.
Ideally, I would like to do something like:
array_of_awesome_data = {}
array_of_awesome_data = readFunc(1234, 32)
where array_of_awesome_data[1] would correspond to A in the way we do it now.
In the current C code I was given, each data is returned in a loop:
lua_pushinteger(L, retData);
How would I go about adjusting a C implemented lua library to allow the lua function to return an array?
Note: a loop of multiple reads is too inefficient on our device so we need to do 1 big read. I do not know enough of the details to justify why, but it is what I was told.
In Lua, you can receive a list returned from a function using table.pack, e.g.:
array_of_awesome_data = table.pack(readFunc(1234, 32))
Or in C, if you want to return a table instead of a list of results, you need to first push a table onto the stack, and then push each item on the stack and add it to the table. It would have something like the following:
num_results=32; /* set this dynamically */
lua_createtable(L, num_results, 0);
for (i=0; i<num_results; i++) {
lua_pushinteger(L, retData[i]);
lua_rawseti (L, -2, i+1); /* In lua indices start at 1 */
}
I'm a bit confused about how Ruby handles the creation of Enumerators. Block-based iteration makes sense and is working for me; I am still confused how the return of an Enumerator is supposed to function code-wise.
Here is the code I am working with:
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
VALUE* args,
VALUE rb_self ) {
rb_thread_t* c_thread = GET_THREAD();
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
// c_top_of_control_frame describes the top edge of the stack trace
// set c_top_of_control_frame to the first frame in <main>
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
// for each control frame:
while ( c_current_context_frame < c_top_of_control_frame ) {
VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
// if we don't have a block, return enumerator
RETURN_ENUMERATOR( rb_self, 0, NULL );
// otherwise, yield the block
rb_yield( rb_frame_hash );
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
}
return Qnil;
}
How would the final line in the while loop be called in the case of an Enumerator?
Does all of my loop activity have to take place before calls to RETURN_ENUMERATOR (since RETURN_ENUMERATOR presumably has to come before rb_yield())?
What if I want something to happen once the internal iteration finishes? With the block I can simply put it after the while loop; presumably the same works in the case of an Enumerator- but how? It seems like every time through the loop it returns an Enumerator, so how does the Enumerator know to return the appropriate corresponding object? rb_yield gets rb_frame_hash as a passed arg, but RETURN_ENUMERATOR seems to take the args that are relayed to the method when the Enumerator calls the method internally. So clearly the Enumerator is calling the method itself- perhaps with some sort of internal block that simply returns the instance of rb_frame_hash?
Any insight into the internals is appreciated.
-Asher
To attempt to answer my own question:
When RETURN_ENUMERATOR is called, rb_enumeratorize is called, which creates an Enumerator. The Enumerator is returned; when :next is called on the Enumerator, a Fiber is initialized (if necessary) or resumed. Each time :next is called, the Fiber iterates an internally provided block once in order to get the next iterator item (setting no_next in the Enumerator's C struct and calling rb_fiber_yield on the Enumerator's Fiber).
So it would seem that the loop activity does not have to take place before RETURN_ENUMERATOR. I'm not yet clear on actions after enumeration in the function returning an Enumerator in the case that a block was not provided.