You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by "Philippe M. Chiasson" <go...@ectoplasm.org> on 2004/08/25 21:28:00 UTC

Safely unloading a package

I have come across the interesting problem of reloading a module.

There is Symbol::delete_package(), but if called to delete 'Foo::Bar', it will
delete $Foo::{Bar::} stash, effectively wiping along every Foo::Bar::* package.

I need to be able to 'unload' package Foo::Bar, so I can reload it with the
equivalent of eval "use Foo::Bar";

Here is the solution I came up with and I wanted to get some feedback on it.

Basically, instead of just wiping the child stash from the parent stash, I
iterate over stash entries for that package, wiping everything that's not a
substash (i.e. ending in '::').

I also unload the module with DynaLoader if it was an XS module so it will be
reloaded on the second 'use'.

Am I doing something terribly wrong ? Is there any harm in doing something like
this ?

I realize that, for instance, if some other package took a ref to a subroutine
in package Foo::Bar, after reloading Foo::Bar would still hold a ref to the _old_
instance of that subroutine. And that's a good thing, AFAIK

sub package2filename {
     my $package = shift;
     $package =~ s[::][/]g;
     $package .= '.pm';
     return $package;
}

sub unload_package {
     my $package = shift;
     my ($stash, $dynamic);

     {
         no strict 'refs';
         $stash = \%{$package . '::'};
     }

     # Figure out if this module was dynamically loaded
     for (my $i = 0 ; $i < @DynaLoader::dl_modules ; $i++) {
         if ($DynaLoader::dl_modules[$i] eq $package) {
             $dynamic = splice(@DynaLoader::dl_librefs, $i);
             splice(@DynaLoader::dl_modules, $i);
         }
     }

     # wipe every entry in the stash except the sub-stashes
     while (my ($name, $glob) = each %$stash) {
         if ($name !~ /::$/) {
             delete $stash->{$name};
         }
     }

     # Unload the .so
     if ($dynamic) {
         DynaLoader::dl_unload_file($dynamic);
     }

     # Clear package from %INC
     delete $INC{package2filename($package)};
}


-- 
--------------------------------------------------------------------------------
Philippe M. Chiasson m/gozer\@(apache|cpan|ectoplasm)\.org/ GPG KeyID : 88C3A5A5
http://gozer.ectoplasm.org/     F9BF E0C2 480E 7680 1AE5 3631 CB32 A107 88C3A5A5

Re: Safely unloading a package

Posted by "Randal L. Schwartz" <me...@stonehenge.com>.
>>>>> "Philippe" == Philippe M Chiasson <go...@ectoplasm.org> writes:

Philippe> I need to be able to 'unload' package Foo::Bar, so I can reload it with the
Philippe> equivalent of eval "use Foo::Bar";

If you're gonna horse around that much, you might want to look
at Safe::World.

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<me...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@perl.apache.org
For additional commands, e-mail: dev-help@perl.apache.org