Perl 将 SIGINT 从`system` 命令转发到父进程 [英] Perl forward SIGINT to parent process from `system` command
问题描述
如果我有一个长时间运行的 system
命令,比如 apt-cache search
,有没有办法转发 SIGINT
在命令行上通过 ^C
发送到父 Perl 进程,这样所有子进程都会被收割.
If I have a long-running system
command like apt-cache search <some query>
, is there a way to forward a SIGINT
sent via ^C
on the command line to the parent Perl process in such a way that all child processes are reaped.
此示例没有所需的行为.信号被发送到子进程.
This example does not have the desired behavior. The signal is sent to the child process.
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
system("apt-cache search hi");
print("Perl did not catch SIGINT even with autodie\n");
我尝试四处寻找捕获由 system("apt-cache search hi &")
创建的孩子的 pid 的方法,但找不到任何方法,所以我尝试 fork
ing 和 exec
ing 进程并编写信号处理程序.这不起作用,因为 apt-cache
本身通过 clone
系统调用启动了一些进程.手动滚动一些逻辑以遍历流程树的一部分并清理
I tried searching around for ways of capturing the pid of the child that would be created by system("apt-cache search hi &")
, but couldn't find any, so I tried fork
ing and exec
ing the process and writing a signal handler. This doesn't work because apt-cache
itself launches a few processes via the clone
system call. Hand-rolling some logic to walk part of the process tree and clean up the
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie;
my $cpid;
$SIG{INT} = sub {
kill 'KILL', $cpid;
exit;
};
# long running command on ubuntu, produces a ton of output.
# replace with your favorite long running command
$cpid = fork;
if ($cpid == 0) {
exec 'apt-cache', 'search', 'hi';
}
print "Perl did not catch SIGINT even with autodie\n";
我想基本上我想要的是一种确定由 system
启动的子进程是否由于 SIGINT
之类的信号而退出的方法,这样我就可以拥有 Perl 脚本自行清理或以一种方式遍历子进程并收获它们,以便干净且可移植地处理进程管理的奇怪边缘情况.
I guess essentially what I want is either a way of determining whether a child process launched by system
exited due to a signal like SIGINT
so I can have the Perl script clean up after itself or a way of walking the child processes and reaping them in such a way that strange edge cases of process management are handled cleanly and portably.
推荐答案
让子进程成为进程组的头,然后向整个进程组发送信号.
Make the child the head of a process group, then send the signal to the whole process group.
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use POSIX qw( setpgid );
my $child_pid;
$SIG{INT} = sub {
kill INT => -$child_pid if $child_pid;
exit(0x80 | 2); # 2 = SIGINT
};
my $child_pid = fork();
if (!$child_pid) {
setpgid($$);
exec 'apt-cache', 'search', 'hi';
}
WAIT: {
no autodie;
waitpid($child_pid, 0);
redo WAIT if $? == -1 and $!{EINTR};
die $! if $? == -1;
}
exit( ( $? >> 8 ) | ( 0x80 | ( $? & 0x7F ) ) );
这篇关于Perl 将 SIGINT 从`system` 命令转发到父进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!