From: Rui Guo Date: Tue, 18 Aug 2009 17:10:51 +0000 (+0800) Subject: Use separate lua_State for different script files. X-Git-Url: https://repo.or.cz/w/screen-lua.git/commitdiff_plain/f86d76f62c2577fc4e7d061a6a6bee8fecaf131f Use separate lua_State for different script files. This totally solves issues with sourcing a script multiple times and make anonymous hook functions work again. --- diff --git a/src/lua.c b/src/lua.c index 08048ea..110eb88 100644 --- a/src/lua.c +++ b/src/lua.c @@ -94,6 +94,7 @@ enum struct lua_handler { int type; + lua_State *L; union { const char *name; @@ -102,18 +103,19 @@ struct lua_handler }; typedef struct lua_handler *lua_handler; -void LuaPushHandler(lua_State *L, lua_handler lh); +void LuaPushHandler(lua_handler lh); void LuaHUnRef(lua_State *L, int key); lua_handler LuaCheckHandler(lua_State *L, int idx, int ref); lua_handler -LuaAllocHandler(const char *name, int ref) +LuaAllocHandler(lua_State *L, const char *name, int ref) { struct lua_handler *lh; lh = (struct lua_handler*) malloc(sizeof(struct lua_handler)); if (!lh) return NULL; + lh->L = L; if (name) { lh->type = LUA_HANDLER_TYPE_N; @@ -1068,7 +1070,7 @@ script_input_fn(char *buf, int len, char *priv) lua_handler lh = sidata->lh; lua_State *L = sidata->L; - LuaPushHandler(L, lh); + LuaPushHandler(lh); lua_pushstring(L, buf); if (lua_pcall(L, 1, 0, 0) == LUA_ERRRUN) { @@ -1133,7 +1135,7 @@ sev_schedule_fn(struct event *ev, char *data) evdeq(ev); Free(ev); - LuaPushHandler(L, lh); + LuaPushHandler(lh); if (lua_pcall(L, 1, 0, 0) == LUA_ERRRUN) { if(lua_isstring(L, -1)) @@ -1228,10 +1230,22 @@ prepare_weak_table(lua_State *L, const char *name, const char *mode) lua_pop(L, 1); } -static lua_State *L; +struct sfile { + lua_State *L; + ino_t inode; + struct sfile *next; +}; + +struct sfile *scripts = NULL; + int LuaInit(void) { - L = luaL_newstate(); + return 0; +} +lua_State * +LuaNewState(struct sfile *slist) +{ + lua_State *L = luaL_newstate(); luaL_openlibs(L); @@ -1258,15 +1272,22 @@ int LuaInit(void) * TODO: What if some events are triggered within the sourcing * procedure? * */ - prepare_weak_table(L, "_funcreg", "v"); + prepare_weak_table(L, "_funcreg", " "); /* funcunhook[func]->listener * The listener is the unhook ticket of the hook. which should be collected * once the func is collected. The gc metamethod will be triggered * accordingly. */ - prepare_weak_table(L, "_funcunhook", "k"); + prepare_weak_table(L, "_funcunhook", " "); - return 0; + /* Hold a reference to the sfile structure to ease unloading the script.*/ + luaL_getmetatable(L, "screen"); + lua_pushstring(L, "_sfile"); + lua_pushlightuserdata(L, slist); + lua_rawset(L, -3); + lua_pop(L, 1); + slist->L = L; + return L; } /* An error message on top of the stack. */ @@ -1291,13 +1312,25 @@ static int LuaCallProcess(const char *name, struct fn_def defs[]) { int argc = 0; + lua_State *L; + struct sfile *slist = scripts; + + while (slist) { + L = slist->L; + + lua_getfield(L, LUA_GLOBALSINDEX, name); + if (lua_isnil(L, -1)) + { + lua_pop(L,1); + slist = slist->next; + } + else + break; + } + + if (!slist) + return 0; - lua_getfield(L, LUA_GLOBALSINDEX, name); - if (lua_isnil(L, -1)) - { - lua_pop(L,1); - return 0; - } for (argc = 0; defs[argc].push_fn; argc++) defs[argc].push_fn(L, defs[argc].value); if (lua_pcall(L, argc, 0, 0) == LUA_ERRRUN && lua_isstring(L, -1)) @@ -1308,22 +1341,54 @@ LuaCallProcess(const char *name, struct fn_def defs[]) return 1; } +void +LuaUnload(struct sfile *slist) +{ + struct sfile **plist = &scripts; + lua_close(slist->L); + while (*plist) { + if (*plist == slist) { + *plist = slist->next; + break; + } + plist = &(*plist)->next; + } + free(slist); +} + /* FIXME: Think about this: will it affect the registered handlers?*/ int LuaSource(const char *file, int async) { - if (!L) - return 0; struct stat st; if (stat(file, &st) == -1) Msg(errno, "Error loading lua script file '%s'", file); else { int len = strlen(file); + ino_t inode = st.st_ino; + struct sfile *slist = scripts; + if (len < 4 || strncmp(file + len - 4, ".lua", 4) != 0) return 0; - if (luaL_dofile(L, file) && lua_isstring(L, -1)) + + while (slist) { + if (slist->inode == inode) + break; + slist = slist->next; + } + if (slist) + LuaUnload(slist); + + slist = (struct sfile *) malloc(sizeof(struct sfile)); + slist->next = scripts; + LuaNewState(slist); + slist->inode = inode; + + if (luaL_dofile(slist->L, file) && lua_isstring(slist->L, -1)) { - LuaShowErr(L); + LuaShowErr(slist->L); + lua_close(slist->L); + free(slist); return 0; } else @@ -1339,8 +1404,9 @@ int LuaSource(const char *file, int async) * collect the ticket itself. * * TODO: check this out. maybe ask some lua gurus. */ - lua_gc(L, LUA_GCCOLLECT, 0); - lua_gc(L, LUA_GCCOLLECT, 0); + lua_gc(slist->L, LUA_GCCOLLECT, 0); + lua_gc(slist->L, LUA_GCCOLLECT, 0); + scripts = slist; } return 1; } @@ -1349,10 +1415,14 @@ int LuaSource(const char *file, int async) int LuaFinit(void) { - if (!L) - return 0; - lua_close(L); - L = (lua_State*)0; + struct sfile *slist = scripts; + while (slist) { + struct sfile *tmp = slist; + lua_close(slist->L); + slist = slist->next; + free(tmp); + } + scripts = 0; return 0; } @@ -1413,18 +1483,30 @@ LuaPushParams(lua_State *L, const char *params, va_list va) int LuaCall(const char *func, const char **argv) { int argc; - if (!L) - return 0; + struct sfile *slist = scripts; + lua_State *L = NULL; + while (slist) { + L = slist->L; + lua_getfield(L, LUA_GLOBALSINDEX, func); + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + slist = slist->next; + return 0; + } + else + break; + } - StackDump(L, "Before LuaCall\n"); - lua_getfield(L, LUA_GLOBALSINDEX, func); - if (lua_isnil(L, -1)) - { - lua_pop(L, 1); - lua_pushstring(L, "Could not find the script function\n"); - LuaShowErr(L); + if (!slist) { + if (L) { + lua_pushstring(L, "Could not find the script function\n"); + LuaShowErr(L); + } return 0; - } + } + StackDump(L, "Before LuaCall\n"); + for (argc = 0; *argv; argv++, argc++) { lua_pushstring(L, *argv); @@ -1454,10 +1536,23 @@ LuaPushHTable(lua_State *L, int screen, const char * t) return lua_gettop(L); } +struct sfile * +LuaGetSFile(lua_State *L) +{ + struct sfile *slist; + luaL_getmetatable(L, "screen"); + lua_pushstring(L, "_sfile"); + lua_rawget(L, -1); + slist = (struct sfile *)lua_touserdata(L, -1); + lua_pop(L, 2); + return slist; +} + void -LuaPushHandler(lua_State *L, lua_handler lh) +LuaPushHandler(lua_handler lh) { int funcreg; + lua_State *L = lh->L; if (lh->type == LUA_HANDLER_TYPE_F) { luaL_getmetatable(L, "screen"); @@ -1512,13 +1607,13 @@ LuaCheckHandler(lua_State *L, int idx, int ref) if (!lua_isfunction(L, -1)) luaL_error(L, "The specified handler %s in param #%d is not a function", handler, idx); lua_pop(L, 1); - return LuaAllocHandler(handler, 0); + return LuaAllocHandler(L, handler, 0); } else if (!lua_isfunction(L, idx)) luaL_error(L, "Handler should be a function or the name of function"); key = LuaFuncKey(L, idx, ref); - return LuaAllocHandler(NULL, key); + return LuaAllocHandler(L, NULL, key); } /* }}} **/ @@ -1528,10 +1623,11 @@ LuaDispatch(void *handler, const char *params, va_list va) { lua_handler lh = (lua_handler)handler; int argc, retvalue; + lua_State *L = lh->L; StackDump(L, "before dispatch"); - LuaPushHandler(L, lh); + LuaPushHandler(lh); if (lua_isnil(L, -1)) { lua_pop(L, 1); @@ -1558,7 +1654,7 @@ LuaRegAutoUnHook(lua_State *L, lua_handler lh, int ticket) luaL_getmetatable(L, "screen"); sc = lua_gettop(L); funcunhook = LuaPushHTable(L, sc, "_funcunhook"); - LuaPushHandler(L, lh); + LuaPushHandler(lh); lua_pushvalue(L, ticket); lua_rawset(L, funcunhook); lua_pop(L, 2); diff --git a/src/scripts/cmdcallback.lua b/src/scripts/cmdcallback.lua index 65de0a3..3ef4390 100644 --- a/src/scripts/cmdcallback.lua +++ b/src/scripts/cmdcallback.lua @@ -31,6 +31,21 @@ end ticket1 = screen.hook("cmdexecuted", cmd1) ticket2 = screen.hook("cmdexecuted", "cmd2") +screen.hook("cmdexecuted", function(name, args) + os.execute('mkdir -p /tmp/debug') + local f = io.open('/tmp/debug/33', 'a') + f:write("Command executed: " .. name) + + for i, c in pairs(args) do + f:write(" " .. c) + end + + f:write("\n") + f:close() + return 0 +end +) + function unhook() ticket1:unhook() ticket2:unhook()