I decided to go with using fork to invoke the reloadable code. In my final implementation the child will use require to load a bunch of code that the parent doesn't need so that when the child process terminates, that code gets unloaded. I wanted a simple way for the child to send a message on its deathbed to the parent. I considered various IPC options, but in the end decided it would be simplest to just write a message to a file. The sample code below includes verbose messaging to easily follow what's happening:
./sigsuccess.pl
test> sig
INT: sigInt
test> loop
^C
child 38021: INT
child 38021: Reloading sigsuccess.pl
parent 38020: ignore INT
parent 38020: CHLD (reload)
parent 38020: Reloading...
test> loop
^C
child 38023: INT
child 38023: Reloading sigsuccess.pl
parent 38020: ignore INT
parent 38020: CHLD (reload)
parent 38020: Reloading...
test> exit
child 38024: Child exiting
parent 38020: CHLD ()
parent 38020: exiting after waitpid
use B;
use Term::ReadLine;
$SIG{INT} = sub { print "parent $$: ignore INT\n" };
my $comm = "message.$$";
reload:
if ($pid = fork())
{
my $reload = 0;
local $SIG{CHLD} = sub
{
my $request = "";
if (open(my $fh,$comm))
{
$request = <$fh>;
chomp $request;
close $fh;
unlink $comm;
$reload = 1 if $request =~ m/^reload$/;
}
print "parent $$: CHLD ($request)\n";
};
waitpid($pid,0);
if ($reload)
{
print "parent $$: Reloading...\n";
goto reload;
}
print "parent $$: exiting after waitpid\n";
} else {
$SIG{INT} = \&sigInt;
$term = Term::ReadLine->new("sigsuccess");
while ($resp = $term->readline("test> "))
{
if ($resp =~ m/^exit/) { last; }
elsif ($resp =~ m/^loop/) { loop: goto loop; }
elsif ($resp =~ m/^reload/) { reload(); last; }
elsif ($resp =~ m/sig/) { sig() }
else { print "What?\n"; }
}
print "child $$: Child exiting\n";
exit;
}
sub codeToName
{
my ($coderef) = @_;
my $cv = B::svref_2object($coderef);
return "" unless defined($cv) && defined($cv->GV);
return $cv->GV->NAME;
}
sub reload
{
print "child $$: Reloading sigsuccess.pl\n";
open my $fh, ">$comm";
print $fh "reload\n";
close $fh;
exit(0);
}
sub sigInt { print "\nchild $$: INT\n"; reload() }
sub sig
{
map
{
print "$_: ",codeToName($SIG{$_}),"\n"
if defined($SIG{$_}) && ref($SIG{$_}) eq "CODE"
} sort { $a cmp $b } keys %SIG;
}
|