【问题标题】:How can I run a program (with a timeout) and know how it ended (signal, exit code, etc) in Perl on a modern Linux?如何在现代 Linux 上的 Perl 中运行程序(超时)并知道它是如何结束的(信号、退出代码等)?
【发布时间】:2012-11-06 13:00:51
【问题描述】:

我需要运行一个程序,在它的标准输入上输入一些字符串,读取它的标准输出/标准错误并知道它是如何结束的。我必须知道它是否收到信号(段错误等)及其退出代码。另外,如果程序运行时间超过一定时间,我必须知道它(并杀死它)。

你会怎么做?有没有处理这种事情的模块?

【问题讨论】:

  • 似乎你需要像ForkManager 这样的东西,可能还有一些处理Perl 进程管理的类,当它结束时有回调。好好看看 CPAN 应该会让您毫无疑问地使用什么。

标签: perl


【解决方案1】:

回复。退出代码和信号,请参阅here。特别是:

129-255 范围内的退出代码表示被 Unix 终止的作业 “信号”。每种类型的信号都有一个编号,以及报告的内容 作业退出代码是信号编号加 128。可能会出现信号 从流程本身(关于 SEGV,见下文)或发送到 由一些外部代理(如批次控制系统, 或您使用“bkill”命令)。

举例来说,退出代码 64 意味着该作业故意 通过调用“exit(64)”终止其执行,退出代码 137 表示 作业收到信号 9,退出代码 140 表示信号 12.

【讨论】:

    【解决方案2】:

    好的,这就是我想出的:(最后的用法示例)

    #!/usr/bin/perl
    use strict;
    use warnings;
    use IPC::Open3;
    use Symbol 'gensym';
    use Time::HiRes 'time';
    use POSIX ':sys_wait_h';
    use IO::Select;
    
    sub run_prog {
        my ($progin, $timeout, $cmd, @args) = @_;
        my ($progres, $progout, $progerr);
        my ($fdin, $fdout, $fderr);
    
        my $outsel = IO::Select->new();
        my $errsel = IO::Select->new();
    
        $fderr = gensym;
        my $pid = open3($fdin, $fdout, $fderr, $cmd, @args);
    
    
        my $start = time;
    
        syswrite $fdin, $progin;
        close $fdin;
    
        $outsel->add($fdout);
        $errsel->add($fderr);
    
        $progout = '';
        $progerr = '';
    
        my $last_activity = $start;
        my $select_timeout = 0.1;
    
        my $ret;
        while(time - $last_activity < $timeout) {
            if($outsel->can_read($select_timeout)) {
                my $buf;
                $ret = sysread($fdout, $buf, 1000);
                if(!defined $ret) {
                    warn "out ndef";
                    last;
                }
                $progout .= $buf;
                $last_activity = time;
            }
    
            if($errsel->can_read($select_timeout)) {
                my $buf;
                $ret = sysread($fderr, $buf, 1000);
                if(!defined $ret) {
                    warn "err ndef";
                    last;
                }
                $progerr .= $buf;
                $last_activity = time;
            }
    
            $ret = waitpid($pid, WNOHANG);
            # still exists, continue
            if($ret == 0) {
                next;
            }
            # process exited/signaled
            elsif($ret > 0) {
                $progres = $?;
                last;
            }
            # process doesn't exists??
            else {
                die "wat";
            }
        }
    
        close $fdout;
        close $fderr;
    
        # timeout
        if(time - $last_activity >= $timeout) {
            kill 9, $pid;
            waitpid($pid, 0);
            $progres = $?;
        }
    
        return ($progres, $progout, $progerr);
    }
    
    my @r = run_prog("qsdjkqsodj\nqsdqsd\n", 0.9, './bbb', $ARGV[0] || 0);
    
    printf "out: <%s>\nerr: <%s>\n", $r[1], $r[2];
    my $x = $r[0];
    
    if ($x == -1) {
        print "failed to execute: $!\n";
    }
    elsif ($x & 127) {
        printf "child died with signal %d, %s coredump\n",
        ($x & 127),  ($x & 128) ? 'with' : 'without';
    }
    else {
        printf "child exited with value %d\n", $x >> 8;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 2013-01-25
      • 2012-04-11
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      相关资源
      最近更新 更多