2016-01-23 16 views
4

当子进程从终端接收到SIGINT时,我遇到一些来自system()的奇怪返回值。从Perl脚本parent.pl解释我使用system()作为子进程运行另一个Perl脚本,但我也需要通过shell运行子,所以我使用了system 'sh', '-c', ...形式..因此,子的父母变成了sh进程和sh进程的父级变为parent.pl。另外,为了避免sh进程收到信号,我将其捕获。当使用SIGINT默认处理程序时从系统()返回值

例如,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); 
} 

其中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; 

child3.pl是:

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

如果我运行parent.pl(命令行),然后按CTRL-C中止每个子进程,输出结果是:

^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 

现在,我想知道为什么我得到一个返回值情况1为130,并且情况2的返回值为4.

此外,在这种情况下,确切知道"DEFAULT"信号处理程序的功能是很好的。

注:如果我更换shbash(和陷阱SIGINT代替INTbash)相同的值返回。

参见:

回答

6

这个问题是非常相似的Propagation of signal to parent when using system,你刚才问。

从我的bash文档:

当一个命令上的致命的信号N终止时,bash使用作为退出状态128 + N的值。

SIGINT通常是2,所以128 + 2会给你130。

Perl的die数字出其退出代码通过检查$!$?未被捕捉异常的(所以,不是你使用eval的情况下):

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

请注意,在这种情况下,Perl,以价值退出因为没有向上移动8位。

错误值恰好是4(请参阅errno.h)。变量$!是具有不同字符串和数字值的双变量。使用数字(如添加零),以获得数端:

use v5.10; 

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

此打印:

$ bash -c "perl errno.pl" 
^Cnumeric errno is 4 
Died at errno.pl line 6. 
$ echo $? 
4 
+0

'errno' 4是'EINTR',“中断的系统调用”。当信号进入时,“睡眠”设置了此项。 – ikegami

1

以你的问题出的顺序:

而且,这将是很好在这种情况下确切知道“DEFAULT”信号处理程序的功能。

将给定信号的处理程序设置为"DEFAULT"确认或恢复给定信号的默认信号处理程序,其操作取决于信号。详情请见the signal(7) manual pageSIGINT的默认处理程序终止该过程。

现在,我想知道为什么我得到的130返回值的情况下,1和4的情况下返回值2

你child1明确设置了SIGINT的默认处理,这样信号会导致它异常终止。 这样的过程在传统意义上没有退出代码。外壳也收到SIGINT,但它陷阱并忽略它。它为子进程报告的退出状态(以及因此自身)反映了杀死孩子的信号(编号2)。

另一方面,您的其他两个子进程捕获SIGINT并正常终止响应。这些确实会产生退出代码,shell将这些代码传递给您(在陷印并忽略了SIGINT之后)。 The documentation for die()描述了在这种情况下如何确定退出代码,但底线是如果您想退出特定代码,则应使用exit而不是die