aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--loadlib.c75
-rw-r--r--testes/attrib.lua8
-rw-r--r--testes/libs/lib22.c51
3 files changed, 98 insertions, 36 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 */
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
447end 453end
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
453local maxint = math.maxinteger 459local 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
15struct STR {
16 void *ud;
17 lua_Alloc allocf;
18};
19
20
21static 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
28static 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*/
51static 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
11static const struct luaL_Reg funcs[] = { 60static 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}