aboutsummaryrefslogtreecommitdiff
path: root/loadlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-07-09 14:40:36 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-07-09 14:40:36 -0300
commit85a3c1699c9587a9e952b4ab75b1c6c310ebebea (patch)
tree67e17e9e8f74259a56690456e705a4158e5cc33e /loadlib.c
parentf65d1f9e02d891733d4ff1cf8d4bc91291e0098e (diff)
downloadlua-85a3c1699c9587a9e952b4ab75b1c6c310ebebea.tar.gz
lua-85a3c1699c9587a9e952b4ab75b1c6c310ebebea.tar.bz2
lua-85a3c1699c9587a9e952b4ab75b1c6c310ebebea.zip
New method to unload DLLs
External strings created by DLLs may need the DLL code to be deallocated. This implies that a DLL can only be unloaded after all its strings were deallocated, which happen only after the run of all finalizers. To ensure that order, we create a 'library string' to represent each DLL and keep it locked. When this string is deallocated (after the deallocation of any string created by the DLL) it closes its corresponding DLL.
Diffstat (limited to 'loadlib.c')
-rw-r--r--loadlib.c75
1 files changed, 40 insertions, 35 deletions
diff --git a/loadlib.c b/loadlib.c
index 5f0c1702..2cd95ca3 100644
--- a/loadlib.c
+++ b/loadlib.c
@@ -307,6 +307,16 @@ static void setpath (lua_State *L, const char *fieldname,
307 307
308 308
309/* 309/*
310** External strings created by DLLs may need the DLL code to be
311** deallocated. This implies that a DLL can only be unloaded after all
312** its strings were deallocated. To ensure that, we create a 'library
313** string' to represent each DLL, and when this string is deallocated
314** it closes its corresponding DLL.
315** (The string itself is irrelevant; its userdata is the DLL pointer.)
316*/
317
318
319/*
310** return registry.CLIBS[path] 320** return registry.CLIBS[path]
311*/ 321*/
312static void *checkclib (lua_State *L, const char *path) { 322static void *checkclib (lua_State *L, const char *path) {
@@ -320,34 +330,41 @@ static void *checkclib (lua_State *L, const char *path) {
320 330
321 331
322/* 332/*
323** registry.CLIBS[path] = plib -- for queries 333** Deallocate function for library strings.
324** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries 334** Unload the DLL associated with the string being deallocated.
325*/ 335*/
326static void addtoclib (lua_State *L, const char *path, void *plib) { 336static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) {
327 lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); 337 /* string itself is irrelevant and static */
328 lua_pushlightuserdata(L, plib); 338 (void)ptr; (void)osize; (void)nsize;
329 lua_pushvalue(L, -1); 339 lsys_unloadlib(ud); /* unload library represented by the string */
330 lua_setfield(L, -3, path); /* CLIBS[path] = plib */ 340 return NULL;
331 lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
332 lua_pop(L, 1); /* pop CLIBS table */
333} 341}
334 342
335 343
336/* 344/*
337** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib 345** Create a library string that, when deallocated, will unload 'plib'
338** handles in list CLIBS
339*/ 346*/
340static int gctm (lua_State *L) { 347static void createlibstr (lua_State *L, void *plib) {
341 lua_Integer n = luaL_len(L, 1); 348 static const char dummy[] = /* common long body for all library strings */
342 for (; n >= 1; n--) { /* for each handle, in reverse order */ 349 "01234567890123456789012345678901234567890123456789";
343 lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ 350 lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib);
344 lsys_unloadlib(lua_touserdata(L, -1));
345 lua_pop(L, 1); /* pop handle */
346 }
347 return 0;
348} 351}
349 352
350 353
354/*
355** registry.CLIBS[path] = plib -- for queries.
356** Also create a reference to strlib, so that the library string will
357** only be collected when registry.CLIBS is collected.
358*/
359static void addtoclib (lua_State *L, const char *path, void *plib) {
360 lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
361 lua_pushlightuserdata(L, plib);
362 lua_setfield(L, -2, path); /* CLIBS[path] = plib */
363 createlibstr(L, plib);
364 luaL_ref(L, -2); /* keep library string in CLIBS */
365 lua_pop(L, 1); /* pop CLIBS table */
366}
367
351 368
352/* error codes for 'lookforfunc' */ 369/* error codes for 'lookforfunc' */
353#define ERRLIB 1 370#define ERRLIB 1
@@ -361,8 +378,8 @@ static int gctm (lua_State *L) {
361** Then, if 'sym' is '*', return true (as library has been loaded). 378** Then, if 'sym' is '*', return true (as library has been loaded).
362** Otherwise, look for symbol 'sym' in the library and push a 379** Otherwise, look for symbol 'sym' in the library and push a
363** C function with that symbol. 380** C function with that symbol.
364** Return 0 and 'true' or a function in the stack; in case of 381** Return 0 with 'true' or a function in the stack; in case of
365** errors, return an error code and an error message in the stack. 382** errors, return an error code with an error message in the stack.
366*/ 383*/
367static int lookforfunc (lua_State *L, const char *path, const char *sym) { 384static int lookforfunc (lua_State *L, const char *path, const char *sym) {
368 void *reg = checkclib(L, path); /* check loaded C libraries */ 385 void *reg = checkclib(L, path); /* check loaded C libraries */
@@ -704,21 +721,9 @@ static void createsearcherstable (lua_State *L) {
704} 721}
705 722
706 723
707/*
708** create table CLIBS to keep track of loaded C libraries,
709** setting a finalizer to close all libraries when closing state.
710*/
711static void createclibstable (lua_State *L) {
712 luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
713 lua_createtable(L, 0, 1); /* create metatable for CLIBS */
714 lua_pushcfunction(L, gctm);
715 lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
716 lua_setmetatable(L, -2);
717}
718
719
720LUAMOD_API int luaopen_package (lua_State *L) { 724LUAMOD_API int luaopen_package (lua_State *L) {
721 createclibstable(L); 725 luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
726 lua_pop(L, 1); /* will not use it now */
722 luaL_newlib(L, pk_funcs); /* create 'package' table */ 727 luaL_newlib(L, pk_funcs); /* create 'package' table */
723 createsearcherstable(L); 728 createsearcherstable(L);
724 /* set paths */ 729 /* set paths */