lua-users home
lua-l archive

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



On 03/12/2019 12.57, Abhijit Nandy wrote:
/*
** return registry.CLIBS[path]
*/
static void *checkclib (lua_State *L, const char *path) {
   void *plib;
   lua_rawgetp(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;
}

So how can I safely clear the LUA_REGISTRYINDEX ( registry.CLIBS[path] specifically), so that plib is set to NULL in the function and the DLL is again loaded in lsys_load() and the open function in it is called?

Not sure about this… I don't think there's an official way.  As no one
else replied to this so far, what could you do to manually achieve this?
(Not sure if I'm missing anything.)

Beyond the loaded library in `package.loaded`, the C library loading
keeps a table behind a userdata/pointer in the registry.  (If you search
for that userdata key very early / before loading other libraries, it
should be the only one in the registry.  So on the Lua side, you could go

  local clibs
  for k, v in pairs( debug.getregistry( ) ) do
     if type( k ) == "userdata" and type( v ) == "table" then
        clibs = v ; break
     end
  end

and from C you'd use LUA_REGISTRYINDEX for the same purpose.)

Now this table maps both the path to the library and also keeps an array
so that it can unload them in reverse order of loading.  It has a __gc
metamethod that closes all C libraries, but that's not useful to unload
single libraries.  If (as you say) you're closing the library on your
own, (I think) you only need to

  function removelib( path )
     local ptr = clibs[path]
     clibs[path] = nil
     for i, v in ipairs( clibs ) do
       -- shift down rest of array
       if v == ptr then  table.remove( clibs, i ) ; break  end
     end
  end

and then it's gone from there.  I've only skimmed the other loadlib
code, so not sure if I missed anything not related to this table.

Also is there any other cleanup I need to do when unloading the C library, so it works exactly as if it has been loaded the first time :)

I haven't a clue…

-----

If you know what OSen you want to support, another approach would be to
use your own library opening routines to load the library.  (`require` &
friends are intended for loading stable libraries once and for all
(caching them etc.), whereas you seem to be doing dynamic code
generation or something like that.)  That'd do pretty much what openlib
does – open the library, search for lua_openFOO, return that (or call it
directly w/ some arguments & return the result).

My approach would be to push the library reference as a full userdata
with a __gc metamethod that closes it.  You'd slightly modify the
lua_openFOO protocol for this:  When opening a library, you push the
lua_openFOO function, then the library userdata, then call w/ 1
argument.  In lua_openFOO, you add an upvalue to all functions (push the
library reference before calling luaL_setfuncs and specify 1 upvalue for
all (or one more if you already have upvalues).)

Now every function from that library has a reference to the library.
Once you remove the last function, all of them will be gone which means
Lua will collect the upvalue, which means the library will be closed.
Further, there's no caching of the library name / library mapping, so
you (probably) can immediately reuse the name even while the old one
wasn't unloaded yet.  (Not sure about dynamic library specifics for
different platforms… I *think* usually the filename only matters for
searching the library to load.)

(Currently in a hurry, hope this is somewhat comprehensible…)

-- nobody