On Sat, Jan 15, 2000 at 08:58:35PM -0500, Daniel Jacobowitz wrote:
> Thus my confusion.  On Linux, with a static libperl.a, there are no
> multiple copies of libperl.so floating around to link to.  The symbols
> only exist in one place.  Thus there is no choice about what symbols
> link to.  Still, I'm going to go over my linker logs again and see if
> something useful turns up on that front.

Ah-HA!

I believe I see the problem.  In fact, I'm almost sure I do.
>From the one useful ltrace log I was able to get:


% grep '^dl' min.ltrace.log
dlopen("/usr/lib/apache/1.3/mod_cgi.so", 258)     = 0x080a4198
dlsym(0x080a4198, "cgi_module")                   = 0x40187540
dlopen("/usr/lib/apache/1.3/mod_mime.so", 258)    = 0x080a4518
dlsym(0x080a4518, "mime_module")                  = 0x40017a00
dlopen("/usr/lib/apache/1.3/mod_perl.so", 258)    = 0x080a4850
dlsym(0x080a4850, "perl_module")                  = 0x402b6bc0
dlopen("/usr/lib/perl5/5.005/i386-linux/"..., 1)  = 0x08118e60
dlsym(0x08118e60, "boot_DBI")                     = 0x402e4834
dlclose(0x080a4850)                               = 0
dlclose(0x080a4518)                               = 0
dlclose(0x080a4198)                               = 0
dlopen("/usr/lib/apache/1.3/mod_cgi.so", 258)     = 0x0817f958
dlsym(0x0817f958, "cgi_module")                   = 0x40187540
dlopen("/usr/lib/apache/1.3/mod_mime.so", 258)    = 0x080afcb8
dlsym(0x080afcb8, "mime_module")                  = 0x4018aa00
dlopen("/usr/lib/apache/1.3/mod_perl.so", 258)    = 0x080a4170
dlsym(0x080a4170, "perl_module")                  = 0x402b9bc0
dlopen("/usr/lib/perl5/5.005/i386-linux/"..., 1)  = 0x08118e60
dlsym(0x08118e60, "boot_DBI")                     = 0x402e4834


Notice that DBI is never dlclose()'d.  But mod_perl is, when apache
unloads its modules.  The linker is not clever enough to realize that
DBI depends on symbols in mod_perl.so.  When mod_perl is reloaded at a
DIFFERENT address, DBI has no reason to be rebound; its symbols are
already resolved!

But now they are resolved to the wrong places.

This looks to be precisely contrary to the way that the linker is
supposed to work, but I'll get back to that later.

Thus my question is, is there a way to tell perl to dlclose() all
modules?  From looking through the perl code and seeing a noticeable
lack of dlclose() calls, I'd say no.  DynaLoader doesn't seem to
support unloading things.  It does, however, store the loaded dlopen
handles in @DynaLoader::dl_librefs, which we could get at in a cleanup.

Woah!

This worked!  Can I get opinions on the attached patch?


Dan

/--------------------------------\  /--------------------------------\
|       Daniel Jacobowitz        |__|        SCS Class of 2002       |
|   Debian GNU/Linux Developer    __    Carnegie Mellon University   |
|         [EMAIL PROTECTED]         |  |       [EMAIL PROTECTED]      |
\--------------------------------/  \--------------------------------/
--- mod_perl.c.orig     Sat Jan 15 22:08:27 2000
+++ mod_perl.c  Sat Jan 15 22:13:01 2000
@@ -417,23 +417,30 @@
 #if MODULE_MAGIC_NUMBER >= MMN_130
 static void mp_dso_unload(void *data) 
 { 
-    module *modp;
-
-    if(!PERL_DSO_UNLOAD)
-       return;
-
-    if(strEQ(top_module->name, "mod_perl.c"))
-       return;
-
-    for(modp = top_module; modp; modp = modp->next) {
-       if(modp->dynamic_load_handle) {
-           MP_TRACE_g(fprintf(stderr, 
-                              "mod_perl: cancel dlclose for %s\n", 
-                              modp->name));
-           modp->dynamic_load_handle = NULL;
+       I32 i;
+       void *handle;
+       AV *librefs;
+       SV *handle_sv;
+       
+       librefs = perl_get_av("DynaLoader::dl_librefs", FALSE);
+       if (!librefs) {
+               MP_TRACE(fprintf(stderr, "Could not get @dl_librefs for 
+unloading.\n"));
+               return;
        }
-    }
-} 
+       
+       for(i = 0; i <= AvFILL(librefs); i++) {
+               handle_sv = *av_fetch(librefs, i, FALSE);
+               if(!handle_sv) {
+                       MP_TRACE(fprintf(stderr, "Could not fetch $dl_librefs[%d]!\n", 
+i));
+                       continue;
+               }
+               handle = (void *)SvIV(handle_sv);
+               if(dlclose(handle) < 0) {
+                       fprintf(stderr, "Could not close $dl_librefs[%d]: %s\n", i, 
+dlerror());
+                       continue;
+               }
+       }
+}
 #endif
 
 static void mp_server_notstarting(void *data) 

Reply via email to