Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return value from system() when using SIGINT default handler

I am experiencing some strange return values from system() when a child process receives a SIGINT from the terminal. To explain, from a Perl script parent.pl I used system() to run another Perl script as a child process, but I also needed to run the child through the shell, so I used the system 'sh', '-c', ... form.. So the parent of the child became the sh process and the parent of the sh process became parent.pl. Also, to avoid having the sh process receiving the SIGINT signal, I trapped it.

For example, parent.pl:

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

for (1..3) {
    my $res = system 'sh', '-c', "trap '' INT; child$_.pl";
    say "Parent received return value: " . ($res >> 8);
}

where child1.pl:

local $SIG{INT} = "DEFAULT";
sleep 10;
say "Child timed out..";
exit 1;

child2.pl:

local $SIG{INT} = sub { die };
sleep 10;
say "Child timed out..";
exit 1;

and child3.pl is:

eval {
    local $SIG{INT} = sub { die };
    sleep 10;
};
if ( $@ ) {
    print $@;
    exit 2;
}
say "Child timed out..";
exit 0;

If I run parent.pl (from the command line) and press CTRL-C to abort each child process, the output is:

^CParent received return value: 130
^CDied at ./child2.pl line 7.
Parent received return value: 4
^CDied at ./child3.pl line 8.
Parent received return value: 2

Now, I would like to know why I get a return value of 130 for case 1, and a return value of 4 for case 2.

Also, it would be nice to know exactly what the "DEFAULT" signal handler does in this case.

Note: the same values are returned if I replace sh with bash ( and trap SIGINT instead of INT in bash ).

See also:

  • Propagation of signal to parent when using system
  • perlipc
  • Chapter 15, in Programming Perl, 4th Edition
like image 472
Håkon Hægland Avatar asked Mar 14 '23 12:03

Håkon Hægland


1 Answers

This question is very similar to Propagation of signal to parent when using system that you asked earlier.

From my bash docs:

When a command terminates on a fatal signal N, bash uses the value of 128+N as the exit status.

SIGINT is typically 2, so 128 + 2 give you 130.

Perl's die figures out its exit code by inspecting $! or $? for an uncaught exception (so, not the case where you use eval):

exit $! if $!;              # errno
exit $? >> 8 if $? >> 8;    # child exit status
exit 255;                   # last resort

Notice that in this case, Perl exits with the value as is, not shifted up 8 bits.

The errno value happens to be 4 (see errno.h). The $! variable is a dualvar with different string and numeric values. Use it numerically (like adding zero) to get the number side:

use v5.10;

local $SIG{INT}=sub{
    say "numeric errno is ", $!+0;
    die
    };
sleep 10;
print q(timed out);
exit 1;

This prints:

$ bash -c "perl errno.pl"
^Cnumeric errno is 4
Died at errno.pl line 6.
$ echo $?
4
like image 67
brian d foy Avatar answered Apr 02 '23 15:04

brian d foy