diff --git a/modules/modperl/modperl.i b/modules/modperl/modperl.i index 051964d3..424c895b 100644 --- a/modules/modperl/modperl.i +++ b/modules/modperl/modperl.i @@ -189,6 +189,12 @@ typedef vector > VPair; } %} +%inline %{ + void _CleanupStash(const CString& sModname) { + hv_clear(gv_stashpv(sModname.c_str(), 0)); + } +%} + %perlcode %{ package ZNC; *CONTINUE = *ZNC::CModule::CONTINUE; diff --git a/modules/modperl/startup.pl b/modules/modperl/startup.pl index adc912b7..ef818157 100644 --- a/modules/modperl/startup.pl +++ b/modules/modperl/startup.pl @@ -18,6 +18,7 @@ package ZNC::Core; my $uuidtype; my $uuidgen; our %pmods; +my %modrefcount; sub Init { if (eval { require Data::UUID }) { @@ -53,6 +54,8 @@ sub CreateUUID { sub unloadByIDUser { my ($id, $user) = @_; + my $modpath = $pmods{$id}{_cmod}->GetModPath; + my $modname = $pmods{$id}{_cmod}->GetModName; $pmods{$id}->OnShutdown; $user->GetModules->removeModule($pmods{$id}{_cmod}); delete $pmods{$id}{_cmod};# Just for the case @@ -60,6 +63,11 @@ sub unloadByIDUser { delete $pmods{$id}{_ptimers}; delete $pmods{$id}{_sockets}; delete $pmods{$id}; + unless (--$modrefcount{$modname}) { + say "Unloading $modpath from perl"; + ZNC::_CleanupStash($modname); + delete $INC{$modpath}; + } } sub UnloadModule { @@ -89,7 +97,16 @@ sub LoadModule { ZNC::CModules::FindModPath("$modname.pm", $modpath, $datapath) or return ($ZNC::Perl_NotFound, "Unable to find module [$modname]"); $modpath = $modpath->GetPerlStr; return ($ZNC::Perl_LoadError, "Incorrect perl module.") unless IsModule $modpath, $modname; - require $modpath; + eval { + require $modpath; + }; + if ($@) { + # modrefcount was 0 before this, otherwise it couldn't die. + # so can safely remove module from %INC + delete $INC{$modpath}; + die $@; + } + $modrefcount{$modname}++; my $id = CreateUUID; $datapath = $datapath->GetPerlStr; $datapath =~ s/\.pm$//;