Perl 将 SIGINT 从`system` 命令转发到父进程 [英] Perl forward SIGINT to parent process from `system` command

查看:49
本文介绍了Perl 将 SIGINT 从`system` 命令转发到父进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个长时间运行的 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 的方法,但找不到任何方法,所以我尝试 forking 和 execing 进程并编写信号处理程序.这不起作用,因为 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 forking and execing 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆