commit b10dbe5c727eedace5c84addd0573bfa1b0c027a
parent 462375ba47de2052687b3d17ff2eef4db4cab739
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 11 Apr 2012 13:35:08 -0300
bug: C libraries must be unloaded after all other finalizers have run,
because a finalizer may use a C function from a C library
Diffstat:
M | loadlib.c | | | 74 | +++++++++++++++++++++++++++++++++++++++++--------------------------------- |
1 file changed, 41 insertions(+), 33 deletions(-)
diff --git a/loadlib.c b/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.107 2011/11/30 12:58:57 roberto Exp roberto $
+** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp roberto $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -92,9 +92,9 @@
#define LUA_OFSEP "_"
-#define LIBPREFIX "LOADLIB: "
+/* table (in the registry) that keeps handles for all loaded C libraries */
+#define CLIBS "_CLIBS"
-#define POF LUA_POF
#define LIB_FAIL "open"
@@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
#endif
-
-static void **ll_register (lua_State *L, const char *path) {
- void **plib;
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
- if (!lua_isnil(L, -1)) /* is there an entry? */
- plib = (void **)lua_touserdata(L, -1);
- else { /* no entry yet; create one */
- lua_pop(L, 1); /* remove result from gettable */
- plib = (void **)lua_newuserdata(L, sizeof(const void *));
- *plib = NULL;
- luaL_setmetatable(L, "_LOADLIB");
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_pushvalue(L, -2);
- lua_settable(L, LUA_REGISTRYINDEX);
- }
+static void *ll_checkclib (lua_State *L, const char *path) {
+ void *plib;
+ lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_getfield(L, -1, path);
+ plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */
+ lua_pop(L, 2); /* pop CLIBS table and 'plib' */
return plib;
}
+static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
+ lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_pushlightuserdata(L, plib);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, path); /* CLIBS[path] = plib */
+ lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
+ lua_pop(L, 1); /* pop CLIBS table */
+}
+
+
/*
-** __gc tag method: calls library's `ll_unloadlib' function with the lib
-** handle
+** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib
+** handles in list CLIBS
*/
static int gctm (lua_State *L) {
- void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
- if (*lib) ll_unloadlib(*lib);
- *lib = NULL; /* mark library as closed */
+ int n = luaL_len(L, 1);
+ for (; n >= 1; n--) { /* for each handle, in reverse order */
+ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
+ ll_unloadlib(lua_touserdata(L, -1));
+ lua_pop(L, 1); /* pop handle */
+ }
return 0;
}
static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
- void **reg = ll_register(L, path);
- if (*reg == NULL) *reg = ll_load(L, path, *sym == '*');
- if (*reg == NULL) return ERRLIB; /* unable to load library */
+ void *reg = ll_checkclib(L, path); /* check loaded C libraries */
+ if (reg == NULL) { /* must load library? */
+ reg = ll_load(L, path, *sym == '*');
+ if (reg == NULL) return ERRLIB; /* unable to load library */
+ ll_addtoclib(L, path, reg);
+ }
if (*sym == '*') { /* loading only library (no function)? */
lua_pushboolean(L, 1); /* return 'true' */
return 0; /* no errors */
}
else {
- lua_CFunction f = ll_sym(L, *reg, sym);
+ lua_CFunction f = ll_sym(L, reg, sym);
if (f == NULL)
return ERRFUNC; /* unable to find function */
lua_pushcfunction(L, f); /* else create new function */
@@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
if (mark) {
int stat;
funcname = lua_pushlstring(L, modname, mark - modname);
- funcname = lua_pushfstring(L, POF"%s", funcname);
+ funcname = lua_pushfstring(L, LUA_POF"%s", funcname);
stat = ll_loadfunc(L, filename, funcname);
if (stat != ERRFUNC) return stat;
modname = mark + 1; /* else go ahead and try old-style name */
}
- funcname = lua_pushfstring(L, POF"%s", modname);
+ funcname = lua_pushfstring(L, LUA_POF"%s", modname);
return ll_loadfunc(L, filename, funcname);
}
@@ -672,10 +678,12 @@ static const lua_CFunction searchers[] =
LUAMOD_API int luaopen_package (lua_State *L) {
int i;
- /* create new type _LOADLIB */
- luaL_newmetatable(L, "_LOADLIB");
+ /* create table CLIBS to keep track of loaded C libraries */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_createtable(L, 0, 1); /* metatable for CLIBS */
lua_pushcfunction(L, gctm);
- lua_setfield(L, -2, "__gc");
+ lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
+ lua_setmetatable(L, -2);
/* create `package' table */
luaL_newlib(L, pk_funcs);
/* create 'searchers' table */