The standard method is to send the script a SIG HUP (Hang UP) which you catch with a signal handler and do the reininitialization you need. Here is an example I use:
BEGIN {
# allow script to be reinitialized with a HUP signal
$SIG{HUP} = sub { $HUP = 1; warn "Caught HUP\n" };
}
# main loop
while ( 1 ) {
$conn = accept_new_conn();
# check if we have been HUPPED
if ( $HUP ) {
REHUP:
# reset the flag
$HUP = 0;
warn "***** Widget reinitializing\n";
do_disconnect();
do_init();
# now it is possible, but unlikely that we get another SIG HUP
+ while
# we are performing our reinit routines so we need to redo thi
+s
# stuff if that occurs, otherwise we will be partially reiniti
+alised
goto REHUP if $HUP;
}
# more code here
}
In this case I just set a var called $HUP. This is because I have multiple children that get this signal. They are not all active at the one time and all I need them to do is re-read data out of the database. To save useless database hits from children that are sitting inactive waiting for connections I have them check if they have been hupped in their main loop. That way you can send 100 HUPs but if only one child is currently active there will only be one call to the DB, rather than 100 x NUM_KIDS. If a child is active it will perform the required RE_INIT before it completes handling the client connection.
Note to send a HUP your HUPper will need to be root. In CGIs I handle this by adding this line to /etc/sudoers
apache ALL=NOPASSWD:/home/www/utility/sendHUP.pl
This lets me call the sendHUP.pl script via a system call in a CGI and have the required HUP happen without getting involved with suid scripts and all the security issues they entail.
The sendHUP.pl script forks due mostly to historical reasons as we did have a 2 second delay between HUPping each kid (so they would not all be rininitializing at once) but the delayed HUP as required technique now makes this unnecessary.
#!/usr/bin/perl -w
# sendHUP.pl
# this script need to be run as root, to do this we add an entry to
# /etc/sudoers so that apache can run it (you edit using visudo)
# visudo -f /etc/sudoers
# add this line
# apache ALL=NOPASSWD:/devel/www/utility/sendHUP.pl
# call as system('sudo', '/devel/www/utility/sendHUP.pl');
$|++;
#use strict;
use Fcntl;
use POSIX qw(setsid);
# we really really don't want to half HUP the widgets
# this can potentially occur so we ignore INT and TERM SIGs
BEGIN { $SIG{INT} = $SIG{TERM} = sub { warn $SIG{INT} ? "*****sendHUP
+caught INT" : "*****sendHUP caught TERM" } }
my $PROGRAM = 'widget.pl';
my @ps = `ps -C $PROGRAM`;
@ps = map { m/(\d+)/; $1 } grep { /\Q$PROGRAM\E/ } @ps;
# now demonize it
defined(my $pid = fork) or die "Can't fork: $!";
exit 0 if $pid;
chdir '/' or die "Can't chdir to /: $!";
umask 0;
setsid() or die "Can't start a new session: $!";
for ( @ps ) {
(kill HUP, $_) or warn "***** Failed to HUP $_\n";
}
my $time = gmtime();
warn "[$time] Sent SIGHUP to $PROGRAM @ps\n";
exit 0;
|