I am writing an application that hosts a small lua scripting environment. In my application, I want to load a script and then create a number of lua threads that will each have their own environment. Then my application can iterate over the list of threads and call each thread’s co-routine until all co-routines have completed. Each co-routine has its own “global” variable that will be unique. I have attached a trivial C file that duplicates the core functionality.
My issue is that the globals I declare in C and push to the thread stack are always nil when used in the lua script, but have the correct value when I retrieve them from C methods. Can someone tell me what I am doing wrong?
The only solution I have found is to reload the script in each thread – change #if 0 to #if 1. However, in my main application, I could be creating 10,000 or more lua threads. Re-loading the script in each thread is not ideal in this case.
I suspect that the method I invoke is using the global environment of the main thread instead of my sub-thread’s global environment. How would I change that behavior?
Marcus
-- main.c
#include "stdio.h"
#include "assert.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int l_TestRoutine(lua_State *L)
{
//When I get the global variable id from the stack
//I get the correct value
lua_getglobal(L, "id");
luaL_checktype(L, -1, LUA_TNUMBER);
printf("Id: %d\n", (int)lua_tointeger(L, -1));
lua_pop(L, 1); // remove the id
return lua_yield(L, 0);
}
int main(int argc, char ** argv)
{
lua_State* LThreads[10];
/* initialize lua */
lua_State *L = lua_open();
luaL_openlibs(L);
int error = luaL_loadfile(L, "foo.lua");
printf("Error code: %d\n", error);
if (error != 0)
{
printf("Error: %s\n",lua_tostring(L,-1));
lua_pop(L, 1);
}
error = lua_pcall(L, 0, LUA_MULTRET, 0);
printf("Error code: %d\n", error);
if (error != 0)
{
printf("Error: %s\n",lua_tostring(L,-1));
lua_pop(L, 1);
}
lua_register(L, "Test", l_TestRoutine);
lua_pushinteger(L, 9999);
lua_setglobal(L, "id");
//now create many lua threads, each with it's own global variable
//and try to access the global
int i;
for (i = 0; i < 10; ++i)
{
LThreads[i] = lua_newthread(L);
//create our own copy of the globals table
lua_newtable( LThreads[i] ); //new globals table
lua_newtable( LThreads[i] ); //metatable
lua_pushliteral( LThreads[i], "__index" );
lua_pushvalue( LThreads[i], LUA_GLOBALSINDEX ); //original globals
lua_settable( LThreads[i], -3 );
lua_setmetatable( LThreads[i], -2 );
lua_replace( LThreads[i], LUA_GLOBALSINDEX ); //replace new globals
#if 0
error = luaL_loadfile(LThreads[i], "foo.lua");
printf("Error code: %d\n", error);
if (error != 0)
{
printf("Error: %s\n",lua_tostring(L,-1));
lua_pop(LThreads[i], 1);
}
error = lua_pcall(LThreads[i], 0, LUA_MULTRET, 0);
printf("Error code: %d\n", error);
#endif
lua_pushinteger(LThreads[i], i);
lua_setglobal(LThreads[i], "id");
//setup to call main for the first time
lua_getglobal(LThreads[i], "Main");
}
int j;
for (i = 0; i < 100; ++i)
{
for (j= 0; j < 10; ++j)
{
error = lua_resume(LThreads[j], 0);
if ((error != LUA_YIELD)
&& (error != 0))
{
printf("Error: %s\n",lua_tostring(LThreads[i], -1));
lua_pop(LThreads[i], 1);
//What should I do to handle an error?
assert(0);
}
}
}
/* teardown */
lua_close(L);
return 0;
}
-- Lua script
function Mine ()
print("called Mine")
end
function Main()
while true do
print (id)
Test()
end
end