Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending a signal to a perl script while it is closing a filehandle [duplicate]

I have the following problem, that I have reconstructed in those two mini perl scripts. This is the main script:

#!/usr/bin/perl
$SIG{INT} = \&signal_handler_one;
open(my $pipe, "|-", "/home/pa/Desktop/POC2");
close $pipe;
sub signal_handler_one{
    print "This is expected to print\n";
}

On the third line it opens a pipe to this script:

#!/usr/bin/perl
$SIG{INT} = \&signal_handler_two;
sleep(10);
sub signal_handler_two{
    print "This isn't expected to print\n";
}

The problem is that when I start the first script and then send SIGINT to it while it is closing the pipe on line 4, the signal_handler_two is fired instead of signal_handler_one. Why does it behave like this? Is there any way around this (my goal is to get signal_handler_one to execute).

Edit: I originally sent the signal on the terminal using Ctrl+C, which causes "This isn't expected to print" to print. But when I send the signal using kill to the parent process from another terminal, it just ignores it.

Edit 2: I eventually solved it by not using open to get the pipe, but by manually forking, execing and then waiting on the child instead of just calling close. Now everything seems to work fine. It seems that that behaviour was specific to my environment, but if anyone could reproduce that same error, please let me know.

like image 205
Void Avatar asked Apr 30 '16 20:04

Void


1 Answers

I cannot reproduce the behavior that you are observing. When I press CTRL-C in the terminal, both the child and the parent immediately receives SIGINT:

use diagnostics;
use feature qw(say);
use strict;
use warnings;

$SIG{INT} = sub {  say "This is expected to print"; die };
my $pid = open ( my $pipe, "|-", "script.pl" );
say "PID = $pid";
eval {
    say "Closing..";
    my $close_ok = close $pipe; # Note "close" here waits for child to exit
    if ( ! $close_ok ) {
        say "Error closing: $!";
    }
    else {
        say "Close done.";
    }
};
if ( $@ ) {
    say "Parent caught SIGINT.";
}

where script.pl is:

#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

$SIG{INT} = sub { die };
eval {
    say "Sleeping..";
    for (1..5) {
        sleep 1;
        say $_;
    }
};
if ( $@ ) {
    say "Child caught SIGINT.";
    exit;
}

the output of running the first program in the terminal (gnome-terminal on Ubuntu 16.04) is:

PID = 1746
Closing..
Sleeping..
1
2
^CThis is expected to print
Child caught SIGINT.
Parent caught SIGINT.
Uncaught exception from user code:
    refcnt: fd -1 < 0

Note that there is an uncaught exception refcnt: fd -1 < 0. I have no idea what that is. Maybe because close did not succeed?

like image 148
Håkon Hægland Avatar answered Oct 01 '22 22:10

Håkon Hægland