2

My pipe (filehandle, socket) breaks (sometimes). I can reproduce it with the following code:

my $counter = 5;
alarm(1);

open(FH,"while(sleep 2); do date; done |") or die $!;
while (<FH>) { print; }
close(FH);

BEGIN {
    $SIG{ALRM} = sub { 
        print "alarm!\n"; 
        exit if --$counter == 0;
        alarm(1);
    };
}

Which will produce:

alarm!
alarm!
Thu Feb  7 11:46:29 EST 2013
alarm!
alarm!
alarm!

If I strace this process, I see that the spawned shell gets a SIGPIPE. However, the Perl process happily continues. How do I fix this?

Willem
  • 3,043
  • 2
  • 25
  • 37
  • What is the problem? In your handler for ALRM, you call exit, so perl exits and closes the file descriptor. When the subshell writes to the closed file handle, it gets a SIGPIPE. Do you want the subshell to ignore the SIGPIPE and just continue forever, with failed writes? – William Pursell Feb 07 '13 at 17:08
  • Your Perl process happily continues after you call `exit` ?? – mob Feb 07 '13 at 17:18

1 Answers1

3

The problem is that <FH> is returning false because of an interrupted system call. I am not sure if this is the idiomatic way to handle this in perl (and would love to see a better answer), but the following seems to work:

my $counter = 5;
alarm 1;

open my $fh, '-|', 'while(sleep 2); do date; done' or die $!;
loop:
while (<$fh>) { print; }
goto loop if $!{EINTR};
close $fh;

BEGIN {
    $SIG{ALRM} = sub { 
        print "alarm!\n"; 
        alarm 1;
        exit if --$counter <= 0;
    };
}
William Pursell
  • 204,365
  • 48
  • 270
  • 300