Link to home
Start Free TrialLog in
Avatar of jjharr
jjharr

asked on

signal trapping in a daemonized server

I have a Perl daemon that operates as both a networking client and a server using various modules. It works fine.

Except... I need to introduce use of a periodic SIGALRM handler and that doesn't work fine. The handler runs once and then the program dies silently. Alarm code is below. I've grepped through most of the module sources and as far as I'm aware, none of them are using SIGALRM. If I eliminate the networking and just run a daemon with a while(1) loop, it works fine (but that's not so useful). I don't even know how to debug it. Any help would be very welcome.
local $SIG{'ALRM'} = \&logme;
setitimer(ITIMER_REAL, 10, 10);
 
sub { $log->info("Alarm handler");}

Open in new window

Avatar of Adam314
Adam314

You haven't provided the code for the logme subroutine.  It could be something in that is causing a problem.  If the logme subroutine is not defined, the code will run, but when the alarm comes, your program will error.  You could try opening STDERR to a file, and see if anything shows up there.
    open(STDERR, ">/var/log/your_program.error");


The interval timers are not supported by windows.  You didn't say which OS you were using, but I'm guessing some form of linux from your Tag.

Avatar of jjharr

ASKER

Here's a super simple test case to illustrate the problem. As shown it breaks on the first run of the handler. Comment setitimer() out, and the problem goes away.
#!/usr/bin/perl
 
use IO::Socket;
 
use Time::HiRes qw(setitimer ITIMER_REAL time);
 
defined(my $pid=fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!";
 
$SIG{'ALRM'} = \&logme;
setitimer(ITIMER_REAL, 10, 10);
 
my $sock = new IO::Socket::INET (
                        "Proto" => "tcp",
                        "LocalPort" => 8819,
                        "Reuse" => 1,
                        "Listen" => 1
                                ) or die "Server croaked";
 
while($client = $sock->accept())
{
}
 
sub logme {
        print "hello\n";
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of jjharr
jjharr

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The problem is how the timeout in accept is handled.  See this example:

#!/usr/bin/perl
use Time::HiRes qw(setitimer ITIMER_REAL time);
 
 
$SIG{'ALRM'} = \&logme;
setitimer(ITIMER_REAL, 3, 3);
 
print "Waiting...\n";
1 while(1);
print "Done waiting\n";
 
sub logme {
        print "hello\n";
}

Open in new window