プログラムを実行し、その stdin にいくつかの文字列をフィードし、その stdout/stderr を読み取り、それがどのように終了したかを知る必要があります。シグナル (segfault など) とその終了コードを受信したかどうかを知る必要があります。また、プログラムが一定時間以上実行されている場合は、それを知る (そして強制終了する) 必要があります。
どうやってそれをしますか?この種のものを処理するモジュールはありますか?
プログラムを実行し、その stdin にいくつかの文字列をフィードし、その stdout/stderr を読み取り、それがどのように終了したかを知る必要があります。シグナル (segfault など) とその終了コードを受信したかどうかを知る必要があります。また、プログラムが一定時間以上実行されている場合は、それを知る (そして強制終了する) 必要があります。
どうやってそれをしますか?この種のものを処理するモジュールはありますか?
再。終了コードとシグナルについては、こちらを参照してください。特に:
129 ~ 255 の範囲の終了コードは、Unix の「シグナル」によって終了したジョブを表します。シグナルの各タイプには番号があり、ジョブ終了コードとして報告されるのは、シグナル番号に 128 を加えたものです。シグナルは、プロセス自体 (SEGV については以下を参照) 内から発生するか、外部エージェントによってプロセスに送信されます (バッチ制御システム、または「bkill」コマンドの使用など)。
例として、終了コード 64 はジョブが「exit(64)」を呼び出して意図的に実行を終了したことを意味し、終了コード 137 はジョブがシグナル 9 を受信したことを意味し、終了コード 140 はシグナル 12 を表します。
これが私が思いついたものです:(最後に使用例)
#!/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;
}