1

如果我有一个脚本是另一个程序的包装器(例如,守护程序包装器mathematica 的包装器),有时在包装器程序中捕获信号并将它们传递给子程序很有用。例如,这里有一些处理 INT(中断)信号的 Perl 代码,因此如果您在启动包装器后执行 ctrl-C,子程序也会被中断:

my $subprogram = "foo args";
my $pid = open(F, "$subprogram |") or die "Can't open pipe from $subprogram: $!";
$SIG{INT} = sub { kill('INT', $pid); 
                  close(F); 
                  die "Passed along INT signal and now aborting.\n"; };
print while(<F>);
close(F);

在程序可能处理的[所有可能的信号]( http://en.wikipedia.org/wiki/Signal_(computing)中,包装器脚本应该传递哪些信号?
还有什么好的包装器应该做的吗?

编辑:最初这个问题是询问如何传递所有可能的信号。感谢最初的答案,我了解到这不是正确的问题。

编辑:我想出了是什么让我在这里循环。Mathematica 显然脱离了它的父进程。所以我必须明确地传递各种终止信号:

$SIG{INT} =  sub { kill('INT', $pid); };  # pass along SIGINT (eg, ctrl-C)
$SIG{TERM} = sub { kill('TERM', $pid); }; # pass along SIGTERM (kill's default)
$SIG{QUIT} = sub { kill('QUIT', $pid); }; # pass along SIGQUIT
$SIG{ABRT} = sub { kill('ABRT', $pid); }; # pass along SIGABRT
$SIG{HUP} =  sub { kill('HUP', $pid); };  # pass along SIGHUP

通常这不是必需的,因为子进程会自动传递这些信号(感谢让我直截了当的答案!)。所以现在我想知道为什么(以及如何)mathematica 脱离自身......

4

4 回答 4

2

有许多信号以这种方式“通过”会很危险。“man 7 signal”并查看 SIGPIPE、SIGILL、SIGCHILD 等内容。您很可能只是不想碰这些人。

所以,真正的问题变成了:你在寻找什么行为?我敢打赌,您真正想要的只是将 SIGINT 和 SIGCONT 传递给孩子。子程序是否对其他信号(如 HUP、USR1 或 USR2)做任何花哨的事情?

我想你真的只是对 SIGINT 和 SIGCONT 感兴趣,其余的(即 SIGSEGV、SIGKILL 等)会自行处理,因为父进程终止也会清理子进程。

哦,顺便说一下,你的例子:

print while(<F>);

很好,如果父 perl 进程被挂起,它将不会继续从 F 读取,一旦该管道填满,您的子程序将阻止写入 stdout,这可能也是您想要的行为。

对于一些更有趣的想法,看看“man bash”和内置的“trap”,看看 shell 开发人员做了什么来解决这个问题。

于 2009-02-13T23:31:13.133 回答
2

我真的不明白你为什么要这样做。就此而言,我不明白您为什么要向包装脚本发送信号。

ETA:停止和重启信号被发送到整个进程组。如果这就是您所追求的:只需确保您的子进程是该进程组的一部分(默认情况下是 AFAIK)。

ETA2:如果mathematica 真的分离自己(可以使用setsid()and完成setpgid()),这意味着它明确不想接收此类信号,因此您不应该发送它们:它可能无论如何都不会处理它们。

于 2009-02-13T23:44:22.337 回答
2

没有任何。

无论如何,您可能在键盘上生成的信号都会发送到子进程,除非子进程采取措施避免这种情况(在这种情况下,您要干预谁)。

其他可能杀死父进程的信号通常会导致子进程在下一次写入父进程时关闭的管道时消失。

因此,除非您有理由认为子进程对信号管理不善,否则我不会担心将任何信号传递给子进程。如果孩子对信号管理不善,也许你应该修复孩子而不是破解父母。

于 2009-02-14T01:06:25.107 回答
1

您可以使用 获取所有信号的列表keys %SIG。因此,为了让它们全部通过,您设置处理程序以向子进程 ID 发送信号:

for my $signal (keys %SIG) {
    $SIG{$signal} = sub { kill($signal, $child_pid); };
}

您可能想要本地化%SIG.

并不是说我说这是个好主意,而是这样做的。

于 2009-02-14T00:00:04.670 回答