lua-users home
lua-l archive

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



Dylan Cuthbert wrote:
I may have read the documentation wrong, but I don't like the way lua lets
all lua co-routines/functions have access to the global scope.

Is there a way to have multiple global scopes, so I don't have to worry
about script writers breaking other people's data or accessing stuff they
shouldn't?  I'd like to keep these "global" scopes local to each object (and
have multiple coroutines running within the same "space" on an object).

Also, if this is possible, what kind of overhead (memory footprint/creation
time) does the lua_state structure have? (I presume I'll need multiples of
these)

Hi Dylan,

The lua_State structure is 96 bytes when compiled with gcc on a PC.

You can use lua_replace(L, LUA_GLOBALSINDEX);
to change the globals for a thread.
Here is an example:

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

static int report (lua_State *L, int status) {
  const char *msg;
  if (status) {
    msg = lua_tostring(L, -1);
    if (msg == NULL) msg = "(error with no message)";
    fprintf(stderr, "%s\n", msg);
    lua_pop(L, 1);
  }
  return status;
}

static int fixglobals (lua_State *L) {
  lua_newtable(L); /* new table for globals */
  lua_newtable(L); /* metatable for new globals */
  lua_pushliteral(L, "__index");
lua_pushvalue(L, LUA_GLOBALSINDEX); /* __index tries old common globals */
  lua_settable(L, -3);
  lua_setmetatable(L, -2);
  lua_replace(L, LUA_GLOBALSINDEX);
}

int main(int argc, char *argv[])
{
  lua_State *L = lua_open();

  luaopen_base(L);
  luaopen_table(L);
  luaopen_io(L);
  luaopen_string(L);
  luaopen_math(L);
  luaopen_debug(L);

  if(argc>2) {
    int status, i;
    lua_State *C1 = lua_newthread(L);
    lua_State *C2 = lua_newthread(L);

    fixglobals(C1);
    lua_pushliteral(C1, "c1");
    lua_setglobal(C1, "name");
    lua_pushnumber(C1, 2);
    lua_setglobal(C1, "N");

    fixglobals(C2);
    lua_pushliteral(C2, "c2");
    lua_setglobal(C2, "name");
    lua_pushnumber(C2, 3);
    lua_setglobal(C2, "N");

    printf("loading %s\n", argv[1]);
    if (report(C1, luaL_loadfile(C1, argv[1]) )) exit(1);
    printf("loading %s\n", argv[2]);
    if (report(C2, luaL_loadfile(C2, argv[2]) )) exit(2);

    printf("start looping\n");
    for (i=0; i<10; i++) {
      if (report(C1, lua_resume(C1, 0) )) exit(3);
      if (report(C2, lua_resume(C2, 0) )) exit(4);
      printf("i = %d\n", i);
    }
  }

  lua_setgcthreshold(L, 0);  /* collected garbage */
  lua_close(L);
  return 0;
}

$ gcc -g -o test coroutine.c  -Llib -llua -llualib

$ cat c2.lua

print('env', name, getfenv())

not_dead_yet = true

while not_dead_yet do
  for i = 1,N do
    print(name, i)
    coroutine.yield(i)
  end
end

$ ./test c2.lua c2.lua
loading c2.lua
loading c2.lua
start looping
env     c1      table: 0xa045980
c1      1
env     c2      table: 0xa045a60
c2      1
i = 0
c1      2
c2      2
i = 1
c1      1
c2      3
i = 2
c1      2
c2      1
i = 3
c1      1
c2      2
i = 4
c1      2
c2      3
i = 5
c1      1
c2      1
i = 6
c1      2
c2      2
i = 7
c1      1
c2      3
i = 8
c1      2
c2      1
i = 9