I have this simple perl daemon:
#!/usr/bin/perl
use strict;
use warnings;
use Proc::Daemon;
Proc::Daemon::Init;
my $continue = 1;
$SIG{TERM} = sub { $continue = 0 };
$SIG{USR1} = sub { do_process(1) };
# basic daemon
boxesd_log("started boxesd");
while ($continue) {
do_process(0);
sleep(30);
}
boxesd_log("finished boxesd");
exit(0);
# required subroutines
sub do_process {
my ($notified) = @_;
boxesd_log("doing it $notified");
}
But there is something that is not working right.
When the daemon starts, it logs every 30 seconds without the notification as expected:
Sat Oct 30 21:05:47 2010 doing it 0 Sat Oct 30 21:06:17 2010 doing it 0 Sat Oct 30 21:06:47 2010 doing it 0
The problem comes when I send the USR1
signal to the process using kill -USR1 xxxxx
. The output is not what I expect:
Sat Oct 30 21:08:25 2010 doing it 1 Sat Oct 30 21:08:25 2010 doing it 0
I get two continuous entries, one from the signal handling subroutine and another form the ever running loop. It seems as if the sleep gets interrupted whenever the USR1
signal is received.
What is going on?
Sleeping processes can be interruptible or uninterruptible. If a process receives a signal when it is in an interruptible sleep state, for example, waiting for terminal I/O, the kernel will awaken the process to handle the signal.
The %SIG array contains values for only the signals actually set within the Perl script. Here are some other examples: $SIG{"PIPE"} = Plumber; # SCARY!!
In Perl, signals can be caught and handled by using a global %SIG hash variable. This %SIG hash variable is keyed by signal numbers, and contains references to corresponding signal handlers.
The sleep is getting interrupted in the sense that your program will handle the incoming signal, but the loop will continue (going back to sleep) until a TERM signal is received. This is documented behaviour for the sleep() function:
May be interrupted if the process receives a signal such as "SIGALRM".
Note that if you need to sleep for 30 seconds, even if interrupted by a signal, you can determine the number of seconds slept and then sleep again for the remainder:
while (1)
{
my $actual = sleep(30);
sleep(30 - $actual) if $actual < 30;
}
PS. You can read more about signal handling in perldoc perlipc, and in virtually any unix programming book by W. Richard Stevens. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With