diff options
-rw-r--r-- | loadlib.c | 75 | ||||
-rw-r--r-- | testes/attrib.lua | 8 | ||||
-rw-r--r-- | testes/libs/lib22.c | 51 |
3 files changed, 98 insertions, 36 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 | 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 | */ | ||
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 */ |
diff --git a/testes/attrib.lua b/testes/attrib.lua index d8b6e0f3..8a3462ea 100644 --- a/testes/attrib.lua +++ b/testes/attrib.lua | |||
@@ -300,6 +300,12 @@ else | |||
300 | assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2") | 300 | assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2") |
301 | assert(lib2.id("x") == true) -- a different "id" implementation | 301 | assert(lib2.id("x") == true) -- a different "id" implementation |
302 | 302 | ||
303 | for _, len in ipairs{0, 10, 39, 40, 41, 1000} do | ||
304 | local str = string.rep("a", len) | ||
305 | local str1 = lib2.newstr(str) | ||
306 | assert(str == str1) | ||
307 | end | ||
308 | |||
303 | -- test C submodules | 309 | -- test C submodules |
304 | local fs, ext = require"lib1.sub" | 310 | local fs, ext = require"lib1.sub" |
305 | assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") | 311 | assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") |
@@ -447,7 +453,7 @@ do | |||
447 | end | 453 | end |
448 | 454 | ||
449 | 455 | ||
450 | -- test of large float/integer indices | 456 | -- test of large float/integer indices |
451 | 457 | ||
452 | -- compute maximum integer where all bits fit in a float | 458 | -- compute maximum integer where all bits fit in a float |
453 | local maxint = math.maxinteger | 459 | local maxint = math.maxinteger |
diff --git a/testes/libs/lib22.c b/testes/libs/lib22.c index 8e656502..b377cce5 100644 --- a/testes/libs/lib22.c +++ b/testes/libs/lib22.c | |||
@@ -1,3 +1,7 @@ | |||
1 | /* implementation for lib2-v2 */ | ||
2 | |||
3 | #include <string.h> | ||
4 | |||
1 | #include "lua.h" | 5 | #include "lua.h" |
2 | #include "lauxlib.h" | 6 | #include "lauxlib.h" |
3 | 7 | ||
@@ -8,8 +12,54 @@ static int id (lua_State *L) { | |||
8 | } | 12 | } |
9 | 13 | ||
10 | 14 | ||
15 | struct STR { | ||
16 | void *ud; | ||
17 | lua_Alloc allocf; | ||
18 | }; | ||
19 | |||
20 | |||
21 | static void *t_freestr (void *ud, void *ptr, size_t osize, size_t nsize) { | ||
22 | struct STR *blk = (struct STR*)ptr - 1; | ||
23 | blk->allocf(blk->ud, blk, sizeof(struct STR) + osize, 0); | ||
24 | return NULL; | ||
25 | } | ||
26 | |||
27 | |||
28 | static int newstr (lua_State *L) { | ||
29 | size_t len; | ||
30 | const char *str = luaL_checklstring(L, 1, &len); | ||
31 | void *ud; | ||
32 | lua_Alloc allocf = lua_getallocf(L, &ud); | ||
33 | struct STR *blk = (struct STR*)allocf(ud, NULL, 0, | ||
34 | len + 1 + sizeof(struct STR)); | ||
35 | if (blk == NULL) { /* allocation error? */ | ||
36 | lua_pushliteral(L, "not enough memory"); | ||
37 | lua_error(L); /* raise a memory error */ | ||
38 | } | ||
39 | blk->ud = ud; blk->allocf = allocf; | ||
40 | memcpy(blk + 1, str, len + 1); | ||
41 | lua_pushexternalstring(L, (char *)(blk + 1), len, t_freestr, L); | ||
42 | return 1; | ||
43 | } | ||
44 | |||
45 | |||
46 | /* | ||
47 | ** Create an external string and keep it in the registry, so that it | ||
48 | ** will test that the library code is still available (to deallocate | ||
49 | ** this string) when closing the state. | ||
50 | */ | ||
51 | static void initstr (lua_State *L) { | ||
52 | lua_pushcfunction(L, newstr); | ||
53 | lua_pushstring(L, | ||
54 | "012345678901234567890123456789012345678901234567890123456789"); | ||
55 | lua_call(L, 1, 1); /* call newstr("0123...") */ | ||
56 | luaL_ref(L, LUA_REGISTRYINDEX); /* keep string in the registry */ | ||
57 | } | ||
58 | |||
59 | |||
11 | static const struct luaL_Reg funcs[] = { | 60 | static const struct luaL_Reg funcs[] = { |
12 | {"id", id}, | 61 | {"id", id}, |
62 | {"newstr", newstr}, | ||
13 | {NULL, NULL} | 63 | {NULL, NULL} |
14 | }; | 64 | }; |
15 | 65 | ||
@@ -18,6 +68,7 @@ LUAMOD_API int luaopen_lib2 (lua_State *L) { | |||
18 | lua_settop(L, 2); | 68 | lua_settop(L, 2); |
19 | lua_setglobal(L, "y"); /* y gets 2nd parameter */ | 69 | lua_setglobal(L, "y"); /* y gets 2nd parameter */ |
20 | lua_setglobal(L, "x"); /* x gets 1st parameter */ | 70 | lua_setglobal(L, "x"); /* x gets 1st parameter */ |
71 | initstr(L); | ||
21 | luaL_newlib(L, funcs); | 72 | luaL_newlib(L, funcs); |
22 | return 1; | 73 | return 1; |
23 | } | 74 | } |