Commits

Harald Klimach  committed 2583edd

3. Patch for Lua 5.2.0
Finalizers may call functions from a dynamic library after the library has been unloaded.

  • Participants
  • Parent commits c8b7a92

Comments (0)

Files changed (1)

File external/lua-5.2.0/src/loadlib.c

 #define LUA_OFSEP	"_"
 
 
-#define LIBPREFIX	"LOADLIB: "
+#define CLIBS		"_CLIBS"
 
 #define POF		LUA_POF
 #define LIB_FAIL	"open"
 #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 */
 
 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_setmetatable(L, -2);
   /* create `package' table */
   luaL_newlib(L, pk_funcs);
   /* create 'searchers' table */