diff options
Diffstat (limited to '')
-rw-r--r-- | loadlib.c | 75 |
1 files changed, 40 insertions, 35 deletions
@@ -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 | */ |
312 | static void *checkclib (lua_State *L, const char *path) { | 322 | static 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 | */ |
326 | static void addtoclib (lua_State *L, const char *path, void *plib) { | 336 | static 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 | */ |
340 | static int gctm (lua_State *L) { | 347 | static void createlibstr (lua_State *L, void *plib) { |
341 | lua_Integer n = luaL_len(L, 1); | 348 | /* common content for all library strings */ |
342 | for (; n >= 1; n--) { /* for each handle, in reverse order */ | 349 | static const char dummy[] = "01234567890"; |
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 | */ | ||
359 | static 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 | */ |
367 | static int lookforfunc (lua_State *L, const char *path, const char *sym) { | 384 | static 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 | */ | ||
711 | static 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 | |||
720 | LUAMOD_API int luaopen_package (lua_State *L) { | 724 | LUAMOD_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 */ |