gozer       2004/09/09 15:16:38

  Modified:    .        Changes
               ModPerl-Registry/lib/ModPerl RegistryCooker.pm
               lib/Apache Reload.pm
               src/modules/perl modperl_cmd.c modperl_util.c modperl_util.h
               t/response/TestModules reload.pm
               todo     features_optimization release
               xs/ModPerl/Util ModPerl__Util.h
               xs/maps  modperl_functions.map
               xs/tables/current/ModPerl FunctionTable.pm
  Log:
  Added ModPerl::Util::unload_package() to remove a loaded package
  as thoroughly as possible by clearing it's stash.
  
  Adjusted <Perl> sections, Apache::Reload and ModPerl::Registry to use
  the new function.
  
  Revision  Changes    Path
  1.480     +3 -0      modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.479
  retrieving revision 1.480
  diff -u -r1.479 -r1.480
  --- Changes   9 Sep 2004 18:48:03 -0000       1.479
  +++ Changes   9 Sep 2004 22:16:37 -0000       1.480
  @@ -12,6 +12,9 @@
   
   =item 1.99_17-dev
   
  +Added ModPerl::Util::unload_package() to remove a loaded package
  +as thoroughly as possible by clearing it's stash. [Gozer]
  +
   fix Apache->request($r) to be set-able even w/: PerlOptions
   -GlobalRequest [Stas]
   
  
  
  
  1.51      +1 -42     modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryCooker.pm
  
  Index: RegistryCooker.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/ModPerl-Registry/lib/ModPerl/RegistryCooker.pm,v
  retrieving revision 1.50
  retrieving revision 1.51
  diff -u -r1.50 -r1.51
  --- RegistryCooker.pm 27 Jun 2004 21:26:45 -0000      1.50
  +++ RegistryCooker.pm 9 Sep 2004 22:16:37 -0000       1.51
  @@ -525,48 +525,7 @@
       my $self = shift;
   
       $self->debug("flushing namespace") if DEBUG & D_NOISE;
  -
  -    no strict 'refs';
  -    my $tab = \%{ $self->{PACKAGE} . '::' };
  -
  -    # below we assign to a symbol first before undef'ing it, to avoid
  -    # nuking aliases. If we undef directly we may undef not only the
  -    # alias but the original function as well
  -
  -    for (keys %$tab) {
  -        my $fullname = join '::', $self->{PACKAGE}, $_;
  -        # code/hash/array/scalar might be imported make sure the gv
  -        # does not point elsewhere before undefing each
  -        if (%$fullname) {
  -            *{$fullname} = {};
  -            undef %$fullname;
  -        }
  -        if (@$fullname) {
  -            *{$fullname} = [];
  -            undef @$fullname;
  -        }
  -        if ($$fullname) {
  -            my $tmp; # argh, no such thing as an anonymous scalar
  -            *{$fullname} = \$tmp;
  -            undef $$fullname;
  -        }
  -        if (defined &$fullname) {
  -            no warnings;
  -            local $^W = 0;
  -            if (defined(my $p = prototype $fullname)) {
  -                *{$fullname} = eval "sub ($p) {}";
  -            }
  -            else {
  -                *{$fullname} = sub {};
  -            }
  -            undef &$fullname;
  -        }
  -        if (*{$fullname}{IO}) {
  -            if (fileno $fullname) {
  -                close $fullname;
  -            }
  -        }
  -    }
  +    ModPerl::Util::unload_package($self->{PACKAGE});
   }
   
   
  
  
  
  1.16      +13 -31    modperl-2.0/lib/Apache/Reload.pm
  
  Index: Reload.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/lib/Apache/Reload.pm,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- Reload.pm 9 Sep 2004 18:29:09 -0000       1.15
  +++ Reload.pm 9 Sep 2004 22:16:37 -0000       1.16
  @@ -27,7 +27,9 @@
   use Apache::ServerUtil;
   use Apache::RequestUtil;
   
  -use vars qw(%INCS %Stat $TouchTime %UndefFields);
  +use ModPerl::Util ();
  +
  +use vars qw(%INCS %Stat $TouchTime);
   
   %Stat = ($INC{"Apache/Reload.pm"} => time);
   
  @@ -47,6 +49,13 @@
       return $package;
   }
   
  +sub module_to_package {
  +    my $module = shift;
  +    $module =~ s/\//::/g;
  +    $module =~ s/\.pm$//g;
  +    return $module;
  +}
  +
   sub register_module {
       my($class, $package, $file) = @_;
       my $module = package_to_module($package);
  @@ -59,11 +68,6 @@
           return unless $file;
           $INCS{$module} = $file;
       }
  -
  -    no strict 'refs';
  -    if (%{"${package}::FIELDS"}) {
  -        $UndefFields{$module} = "${package}::FIELDS";
  -    }
   }
   
   sub unregister_module {
  @@ -116,15 +120,6 @@
                   foreach my $match (keys %INC) {
                       if ($match =~ /^\Q$prefix\E/) {
                           $Apache::Reload::INCS{$match} = $INC{$match};
  -                        my $package = $match;
  -                        $package =~ s/\//::/g;
  -                        $package =~ s/\.pm$//;
  -                        no strict 'refs';
  -#                        warn "checking for FIELDS on $package\n";
  -                        if (%{"${package}::FIELDS"}) {
  -#                            warn "found fields in $package\n";
  -                            $UndefFields{$match} = "${package}::FIELDS";
  -                        }
                       }
                   }
               }
  @@ -158,29 +153,16 @@
           }
   
           if ($mtime > $Stat{$file}) {
  -            delete $INC{$key};
  -#           warn "Reloading $key\n";
  -            if (my $symref = $UndefFields{$key}) {
  -#                warn "undeffing fields\n";
  -                no strict 'refs';
  -                undef %{$symref};
  -            }
  -            no warnings FATAL => 'all';
  -            local $SIG{__WARN__} = \&skip_redefine_const_sub_warn
  -                unless $ConstantRedefineWarnings;
  +            my $package = module_to_package($key);
  +            ModPerl::Util::unload_package($package);
               require $key;
  -            warn("Apache::Reload: process $$ reloading $key\n")
  +            warn("Apache::Reload: process $$ reloading $package from $key\n")
                       if $DEBUG;
           }
           $Stat{$file} = $mtime;
       }
   
       return Apache::OK;
  -}
  -
  -sub skip_redefine_const_sub_warn {
  -    return if $_[0] =~ /^Constant subroutine [\w:]+ redefined at/;
  -    CORE::warn(@_);
   }
   
   1;
  
  
  
  1.65      +1 -4      modperl-2.0/src/modules/perl/modperl_cmd.c
  
  Index: modperl_cmd.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_cmd.c,v
  retrieving revision 1.64
  retrieving revision 1.65
  diff -u -r1.64 -r1.65
  --- modperl_cmd.c     23 Aug 2004 21:16:27 -0000      1.64
  +++ modperl_cmd.c     9 Sep 2004 22:16:37 -0000       1.65
  @@ -577,10 +577,7 @@
           SvREFCNT_dec((SV*)args);
   
           if (!(saveconfig && SvTRUE(saveconfig))) {
  -            HV *symtab = (HV*)gv_stashpv(pkg_name, FALSE);
  -            if (symtab) {
  -                modperl_clear_symtab(aTHX_ symtab);
  -            }
  +            modperl_package_unload(aTHX_ pkg_name);
           }
           
           if (status != OK) {
  
  
  
  1.80      +95 -54    modperl-2.0/src/modules/perl/modperl_util.c
  
  Index: modperl_util.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_util.c,v
  retrieving revision 1.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- modperl_util.c    9 Sep 2004 15:08:38 -0000       1.79
  +++ modperl_util.c    9 Sep 2004 22:16:37 -0000       1.80
  @@ -303,6 +303,59 @@
       free(handles);
   }
   
  +/* XXX: There is no XS accessible splice() */
  +static void modperl_av_remove_entry(pTHX_ AV *av, I32 index)
  +{
  +    I32 i;
  +    AV *tmpav = newAV();
  +
  +    /* stash the entries _before_ the item to delete */
  +    for (i=0; i<=index; i++) {
  +        av_store(tmpav, i, SvREFCNT_inc(av_shift(av)));
  +    }
  +    
  +    /* make size at the beginning of the array */
  +    av_unshift(av, index-1);
  +    
  +    /* add stashed entries back */
  +    for (i=0; i<index; i++) {
  +        av_store(av, i, *av_fetch(tmpav, i, 0));
  +    }
  +    
  +    SvREFCNT_dec(tmpav);
  +}
  +
  +static void modperl_package_unload_dynamic(pTHX_ const char *package, 
  +                                           I32 dl_index)
  +{
  +    AV *librefs = get_av(dl_librefs, 0);
  +    SV *libref = *av_fetch(librefs, dl_index, 0);
  +
  +    modperl_sys_dlclose((void *)SvIV(libref));
  +    
  +    /* remove package from @dl_librefs and @dl_modules */
  +    modperl_av_remove_entry(aTHX_ get_av(dl_librefs, 0), dl_index);
  +    modperl_av_remove_entry(aTHX_ get_av(dl_modules, 0), dl_index);
  +    
  +    return;    
  +}
  +
  +static int modperl_package_is_dynamic(pTHX_ const char *package,
  +                                      I32 *dl_index)
  +{
  +   I32 i;
  +   AV *modules = get_av(dl_modules, FALSE);
  +    
  +   for (i=0; i<av_len(modules); i++) {
  +        SV *module = *av_fetch(modules, i, 0);
  +        if (strEQ(package, SvPVX(module))) {
  +            *dl_index = i;
  +            return TRUE;
  +        }
  +    }
  +    return FALSE;
  +}
  +
   modperl_cleanup_data_t *modperl_cleanup_data_new(apr_pool_t *p, void *data)
   {
       modperl_cleanup_data_t *cdata =
  @@ -526,60 +579,6 @@
       return (svp && *svp != &PL_sv_undef) ? 1 : 0;
   }
   
  -static int modperl_gvhv_is_stash(GV *gv)
  -{
  -    int len = GvNAMELEN(gv);
  -    char *name = GvNAME(gv);
  -
  -    if ((len > 2) && (name[len - 1] == ':') && (name[len - 2] == ':')) {
  -        return 1;
  -    }
  -
  -    return 0;
  -}
  -
  -/*
  - * we do not clear symbols within packages, the desired behavior
  - * for directive handler classes.  and there should never be a package
  - * within the %Apache::ReadConfig.  nothing else that i'm aware of calls
  - * this function, so we should be ok.
  - */
  -
  -void modperl_clear_symtab(pTHX_ HV *symtab) 
  -{
  -    SV *val;
  -    char *key;
  -    I32 klen;
  -
  -    hv_iterinit(symtab);
  -    
  -    while ((val = hv_iternextsv(symtab, &key, &klen))) {
  -        SV *sv;
  -        HV *hv;
  -        AV *av;
  -        CV *cv;
  -
  -        if ((SvTYPE(val) != SVt_PVGV) || GvIMPORTED((GV*)val)) {
  -            continue;
  -        }
  -        if ((sv = GvSV((GV*)val))) {
  -            sv_setsv(GvSV((GV*)val), &PL_sv_undef);
  -        }
  -        if ((hv = GvHV((GV*)val)) && !modperl_gvhv_is_stash((GV*)val)) {
  -            hv_clear(hv);
  -        }
  -        if ((av = GvAV((GV*)val))) {
  -            av_clear(av);
  -        }
  -        if ((cv = GvCV((GV*)val)) && (GvSTASH((GV*)val) == GvSTASH(CvGV(cv)))) {
  -            GV *gv = CvGV(cv);
  -            cv_undef(cv);
  -            CvGV(cv) = gv;
  -            GvCVGEN(gv) = 1; /* invalidate method cache */
  -        }
  -    }
  -}
  -
   #define SLURP_SUCCESS(action) \
       if (rc != APR_SUCCESS) { \
           SvREFCNT_dec(sv); \
  @@ -784,4 +783,46 @@
       }
   
       return array;
  +}
  +
  +/* Remove a package from %INC */
  +static void modperl_package_delete_from_inc(pTHX_ const char *package)  
  +{
  +    int len;
  +    char *filename = package2filename(package, &len);
  +    hv_delete(GvHVn(PL_incgv), filename, len, G_DISCARD);
  +    free(filename);
  +}
  +
  +/* Destroy a package's stash */
  +static void modperl_package_clear_stash(pTHX_ const char *package)
  +{
  +    HV *stash;
  +    if ((stash = gv_stashpv(package, FALSE))) {
  +        HE *he;
  +        I32 len;
  +        char *key;
  +        hv_iterinit(stash);
  +        while ((he = hv_iternext(stash))) {
  +            key = hv_iterkey(he, &len);
  +            /* We skip entries ending with ::, they are sub-stashes */
  +            if (len > 2 && key[len] != ':' && key[len-1] != ':') {
  +                hv_delete(stash, key, len, G_DISCARD);
  +            }
  +        }
  +    }
  +}
  +
  +/* Unload a module as completely and cleanly as possible */
  +void modperl_package_unload(pTHX_ const char *package)
  +{
  +    I32 dl_index;
  +    
  +    modperl_package_clear_stash(aTHX_ package);
  +    modperl_package_delete_from_inc(aTHX_ package);
  +    
  +    if (modperl_package_is_dynamic(aTHX_ package, &dl_index)) {
  +        modperl_package_unload_dynamic(aTHX_ package, dl_index);
  +    }
  +    
   }
  
  
  
  1.67      +1 -0      modperl-2.0/src/modules/perl/modperl_util.h
  
  Index: modperl_util.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_util.h,v
  retrieving revision 1.66
  retrieving revision 1.67
  diff -u -r1.66 -r1.67
  --- modperl_util.h    22 Aug 2004 20:47:37 -0000      1.66
  +++ modperl_util.h    9 Sep 2004 22:16:37 -0000       1.67
  @@ -109,6 +109,7 @@
   SV *modperl_apr_array_header2avrv(pTHX_ apr_array_header_t *array);
   apr_array_header_t *modperl_avrv2apr_array_header(pTHX_ apr_pool_t *p,
                                                     SV *avrv);
  +void modperl_package_unload(pTHX_ const char *package);
   #if defined(MP_TRACE) && defined(APR_HAS_THREADS)
   #define MP_TRACEf_TID   "/tid 0x%lx"
   #define MP_TRACEv_TID   (unsigned long)apr_os_thread_current()
  
  
  
  1.4       +0 -1      modperl-2.0/t/response/TestModules/reload.pm
  
  Index: reload.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/response/TestModules/reload.pm,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- reload.pm 9 Sep 2004 18:29:09 -0000       1.3
  +++ reload.pm 9 Sep 2004 22:16:38 -0000       1.4
  @@ -29,5 +29,4 @@
   PerlModule Apache::Reload
   PerlInitHandler Apache::TestHandler::same_interp_fixup Apache::Reload
   PerlSetVar ReloadDebug Off
  -PerlSetVar ReloadConstantRedefineWarnings Off
   PerlSetVar ReloadAll Off
  
  
  
  1.4       +3 -0      modperl-2.0/todo/features_optimization
  
  Index: features_optimization
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/todo/features_optimization,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- features_optimization     4 Mar 2004 01:04:28 -0000       1.3
  +++ features_optimization     9 Sep 2004 22:16:38 -0000       1.4
  @@ -15,3 +15,6 @@
   * currently when ithreads-enabled perl is used anon-sub handlers are
     always deparsed and non-cached. there are several cases when this
     can be optimized. See modperl_handler_new_anon in modperl_handler.c
  +
  +* modperl_package_unload() and modperl_xs_dl_*() share some duplicated
  +  logic. The managment of DynaLoaded modules could be somewhat cleaner. 
  
  
  
  1.55      +0 -4      modperl-2.0/todo/release
  
  Index: release
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/todo/release,v
  retrieving revision 1.54
  retrieving revision 1.55
  diff -u -r1.54 -r1.55
  --- release   25 Aug 2004 23:47:33 -0000      1.54
  +++ release   9 Sep 2004 22:16:38 -0000       1.55
  @@ -100,10 +100,6 @@
                  not sure when. we need to ping him every so often. but
                  it'll probably won't happen by the time we release 2.0.
   
  -* Apache::Reload
  -  - needs to handle properly redefined subs warnings
  -  owner: gozer
  -
   * Apache->unescape_url{_info}:
     not yet implemented.  should be moved to Apache::Util (or may be
     APR::URI?)
  
  
  
  1.7       +2 -0      modperl-2.0/xs/ModPerl/Util/ModPerl__Util.h
  
  Index: ModPerl__Util.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/ModPerl/Util/ModPerl__Util.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ModPerl__Util.h   25 Aug 2004 21:51:21 -0000      1.6
  +++ ModPerl__Util.h   9 Sep 2004 22:16:38 -0000       1.7
  @@ -29,5 +29,7 @@
   #define mpxs_ModPerl__Util_current_callback \
           modperl_callback_current_callback_get
   
  +#define mpxs_ModPerl__Util_unload_package(pkg) \
  +        modperl_package_unload(aTHX_ pkg)
   
   
  
  
  
  1.86      +1 -0      modperl-2.0/xs/maps/modperl_functions.map
  
  Index: modperl_functions.map
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/maps/modperl_functions.map,v
  retrieving revision 1.85
  retrieving revision 1.86
  diff -u -r1.85 -r1.86
  --- modperl_functions.map     25 Aug 2004 21:51:21 -0000      1.85
  +++ modperl_functions.map     9 Sep 2004 22:16:38 -0000       1.86
  @@ -7,6 +7,7 @@
    mpxs_ModPerl__Util_untaint | | ...
    DEFINE_exit | | int:status=0
    char *:DEFINE_current_callback 
  + DEFINE_unload_package | | const char *:package
   
   MODULE=ModPerl::Global
    mpxs_ModPerl__Global_special_list_call
  
  
  
  1.178     +15 -1     modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm
  
  Index: FunctionTable.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v
  retrieving revision 1.177
  retrieving revision 1.178
  diff -u -r1.177 -r1.178
  --- FunctionTable.pm  8 Sep 2004 00:42:02 -0000       1.177
  +++ FunctionTable.pm  9 Sep 2004 22:16:38 -0000       1.178
  @@ -2,7 +2,7 @@
   
   # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   # ! WARNING: generated by ModPerl::ParseSource/0.01
  -# !          Mon Aug 30 22:40:23 2004
  +# !          Wed Sep  8 15:12:22 2004
   # !          do NOT edit, any changes will be lost !
   # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   
  @@ -3875,6 +3875,20 @@
         {
           'type' => 'apr_size_t *',
           'name' => 'len'
  +      }
  +    ]
  +  },
  +  {
  +    'return_type' => 'void',
  +    'name' => 'modperl_package_unload',
  +    'args' => [
  +      {
  +        'type' => 'PerlInterpreter *',
  +        'name' => 'my_perl'
  +      },
  +      {
  +        'type' => 'const char *',
  +        'name' => 'package'
         }
       ]
     },
  
  
  

Reply via email to