waitpid interruped by "Alarm clock"

M

M Weaver

I open a system call in a pipe, do stuff, then call waitpid($pid,0) on
the process opened in the pipe. It dies before the system call exits
with an "Alarm clock" message. Why?

Thanks.

-Matthew



#Here's some code:


my $slowCommandPID = undef;
eval {
local $SIG{ALRM} = sub { die "MY-TIMEOUT"; };
alarm (int (60 * $timeoutMins));
print "DEBUG: Alarm set; opening pipe for '$cmd'...$/" if $debug;
($pid = open(CMD_IN, "$cmd |")) or
warn("Unable to execute $cmd: $!$/");
print "DEBUG: Pipe is opened (pid $pid), reading...$/" if $debug;
while (<CMD_IN>) {
print $line unless ($noLogging);
}
print "DEBUG: Closing pipe for '$cmd'...$/" if $debug;
close CMD_IN or warn "Couldn't close pipe: $!$/";
print "DEBUG: Just checking, \$? = $? $/$/" if $debug;
alarm 0;
};
if ($@) { # caught a signal
print "DEBUG: We got a signal while executing '$cmd'...$/$/" if
$debug;
unless ($@ =~ /MY-TIMEOUT/) {
fail($@);
} # it's not our signal
alarm 0;
my $timeoutMsg = "[ERROR] System call timed out after $timeoutMins
minutes!";
print $timeoutMsg;
if ($killOnTimeout) {
print "Killing pid $pid...";
kill ('TERM', $pid) or warn "Could not send SIGTERM to pid
$pid: $!$/";
} else {
$slowCommandPID = $pid;
}
}


.. . .


if ($slowCommandPID) {
pstatus "Waiting for slow command to complete, pid
$slowCommandPID...";
my $childPid = waitpid ($slowCommandPID,0); #blocking
pstatus "Slow command has completed: \$childPid = $childPid,
status = $?";
}
 
M

M Weaver

Purl said:
Don't localize your signal. Leave it global.

Ah, thanks for catching that 'local'. I was following the Camel book,
perhaps too slavishly -- how does Larry get away with using 'local' in
"Timing out slow operations"? But I'll take that up with him.

Sorry the rest of my question was so unclear. Most of the code was
just for context, which I thought might be relevant. The last few
lines are the puzzle. I should have said so in the first place.

Here's the code again, with a little less extraneous junk (more
remarks after code):

####################################
my $slowCommandPID = undef;
eval {
local $SIG{ALRM} = sub { die "MY-TIMEOUT"; };
alarm (int (60 * $timeoutMins));
($pid = open(CMD_IN, "$cmd |")) or
warn("Unable to execute $cmd: $!$/");
while (<CMD_IN>) {
print $line unless ($noLogging);
}
close CMD_IN or warn "Couldn't close pipe: $!$/";
alarm 0;
};
if ($@) { # caught a signal
unless ($@ =~ /MY-TIMEOUT/) {
fail($@);
} # it's not our signal
alarm 0;
print = "[ERROR] System call timed out!$/";
$slowCommandPID = $pid;
}

# . . .

if ($slowCommandPID) {
pstatus "Waiting for slow command to complete, pid
$slowCommandPID...";
my $childPid =
waitpid ($slowCommandPID,0); #blocking
pstatus "Slow command has completed: \$childPid = $childPid,status =
$?";
}
###########################################


"MY-TIMEOUT" has already been thrown and handled, and $slowCommandPID
has been initialized. The mystery is what happens when I call
waitpid($slowCommandPID,0);
It waits as expected, but only for about 10 minutes; then -- before
the child process completes -- my process receives the "Alarm clock"
signal from I-do-not-know-where. The last pstatus line is never
reached.

When it's run the command line I get a message:
run-script.sh: line 168: 12309 Alarm clock
! ( myPerlScript.pl >$LOG 2>&1 )

Thanks for comments.

-Matthew
 
D

Dale Henderson

MW> I open a system call in a pipe, do stuff, then call
MW> waitpid($pid,0) on the process opened in the pipe. It dies
MW> before the system call exits with an "Alarm clock" message.
MW> Why?

MW> Thanks.

MW> -Matthew

I have no idea why your code is failing. My guess it that in a
part you're not showing you have an alarm system call that never
gets turned off. I'm guessing that ... ... represents snipped
code. Since your snippets are not runnable I couldn't very well
try to run it and debug it.

By the way your use of local in the eval is fine and does just
what you would expect. The signal is caught while the "local"
value of SIG is still in effect so the die is executed which is
what sets $@. Using my here would be a bad idea though. This all
assumes that you do not want the handler installed during the
eval to last for the rest of the program.

I would take Purl Gurls "advice" with a very large grain of
salt. Sometimes she gives good advice but this is the exception
not the rule. And for some reason she seems to abhor local
variables (or even dynamically scoped variables).

If you don't believe what I said about local($SIG{ALRM}) try
this:

#!/usr/bin/perl

use strict;
use warnings;

eval {
local $SIG{ALRM} = sub { die "MY-TIMEOUT"; };
alarm(1);
sleep (5);

};

if ($@){
print $@;
}

The result is:

MY-TIMEOUT at test.pl line 7.

You might also google for Purl Gurl's posts particularly the Bokma
thread.
 
M

M Weaver

You were right, the omitted code hid another alarm which I had failed
to unset. Mystery solved.

Thanks for pointing me in the right direction.

-Matthew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top