lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


2010/1/6 Christian Tellefsen <christian.tellefsen@funcom.com>:
> Hi,
>
> I have a question about the Lua registry, environment, and threads. I have
> the following code:
>
> int Test(lua_State * L )
> {
>  lua_getglobal(L, "print");
>  lua_getglobal(L, "a");
>  lua_pcall(L, 1, 0, 0);
>
>  return 0;
> }
>
> int main (void) {
>  int error;
>  lua_State * L = lua_open();   /* opens Lua */
>  luaL_openlibs(L);
>
>  lua_pushnumber(L, 0);  // In the global environment, a = 0
>  lua_setglobal(L, "a");
>
>  // Create a thread with its own environment.
>  lua_State * L1 = lua_newthread(L);
>
>  lua_pushthread(L1);                  // thread
>  lua_newtable(L1);                    // thread, t
>  lua_pushvalue(L1, LUA_GLOBALSINDEX); // thread, t, _G
>  lua_setfield(L1, -2, "__index");     // thread, t
>  lua_pushvalue(L1, -1);               // thread, t, t
>  lua_setmetatable(L1, -2);            // thread, t
>  lua_setfenv(L1, -2);                 // thread
>
>  lua_pushnumber(L1, 1);  // In the thread environment, a = 1
>  lua_setglobal(L1, "a");
>
>  lua_pop(L1, 1);                      // -
>
>  // Put the C function in the registry, and retrieve it and call it from the
> root and the child thread.
>  lua_pushcfunction(L, &Test);
>  int r0 = luaL_ref(L, LUA_REGISTRYINDEX);
>
>  lua_rawgeti(L, LUA_REGISTRYINDEX, r0);
>  lua_pcall(L, 0, 0, 0);
>
>  lua_rawgeti(L1, LUA_REGISTRYINDEX, r0);
>  lua_pcall(L1, 0, 0, 0);
>
>  // Load the buffer and store it in registry, and retrieve it and call it
> from the root and the child thread.
>  const char * txt = "print(a)";
>  luaL_loadbuffer(L, txt, strlen(txt), "x");
>
>  int r1 = luaL_ref(L, LUA_REGISTRYINDEX);
>
>  lua_rawgeti(L, LUA_REGISTRYINDEX, r1);
>  lua_pcall(L, 0, 0, 0);
>
>  lua_rawgeti(L1, LUA_REGISTRYINDEX, r1);
>  lua_pcall(L1, 0, 0, 0);
> }
>
> This prints:
>
> 0
> 1
> 0
> 0
>
> So, as far as I can tell, the C function will print out the 'a' in the
> thread's environment, but the identical Lua function loaded through
> luaL_loadbuffer() will always print out the 'a' in the global environment.
>
> Does anyone know why this gives a different result? And is there any way I
> can get the second case to work in the same way as the first one, that is,
> print the 'a' in the thread's environment?

At any point in a Lua function (be it implemented in C or Lua), you
have three possible environments: the function environment
(LUA_ENVIRONINDEX), the thread environment (LUA_GLOBALSINDEX), and the
interpreter environment (LUA_REGISTRYINDEX).

Functions implemented in Lua use the function environment when
accessing globals (and you have to use the debug library to access the
other ones).

Functions implemented in C can choose which one to use. The
lua_getglobal macro uses LUA_GLOBALSINDEX, which is accessing the
thread environment rather than the function environment, and which is
kind of misleading since it doesn't mimick the behavior of global
variables in Lua code.