Проблема с fork exec kill при перенаправлении вывода в perl - PullRequest
6 голосов
/ 03 июня 2010

Я создал скрипт на Perl для запуска программ с таймаутом. Если выполнение программы занимает больше времени, чем тайм-аут, чем сценарий убивает эту программу и возвращает сообщение «ВРЕМЯ».

Сценарий работал довольно хорошо, пока я не решил перенаправить вывод выполненной программы.

Когда перенаправляются stdout и stderr, программа, выполняемая сценарием, не уничтожается, поскольку у нее pid, отличный от того, который я получил от fork.

Кажется, perl выполняет оболочку, которая выполняет мою программу в случае перенаправления.

Я хотел бы иметь перенаправление вывода, но все еще мог бы убить программу в случае тайм-аута.

Есть идеи, как мне это сделать?

Упрощенный код моего скрипта:

#!/usr/bin/perl

use strict;
use warnings;
use POSIX ":sys_wait_h";

my $timeout = 5;
my $cmd = "very_long_program 1>&2 > out.txt";

my $pid = fork();
if( $pid == 0 )
{
   exec($cmd) or print STDERR "Couldn't exec '$cmd': $!";
   exit(2);
}
my $time = 0;
my $kid = waitpid($pid, WNOHANG);
while ( $kid == 0 )
{
   sleep(1);
   $time ++;
   $kid = waitpid($pid, WNOHANG);
   print "Waited $time sec, result $kid\n";
   if ($timeout > 0 && $time > $timeout)
   {
      print "TIMEOUT!\n";
      #Kill process
      kill 9, $pid;
      exit(3);
   }
}

if ( $kid == -1)
{
   print "Process did not exist\n";
   exit(4);
}
print "Process exited with return code $?\n";
exit($?);

Спасибо за любую помощь.

Ответы [ 2 ]

11 голосов
/ 03 июня 2010

Попробуйте изменить $cmd с

my $cmd = "very_long_program 1>&2 > out.txt";

до

my $cmd = "exec very_long_program 1>&2 > out.txt";

exec скажет оболочке, которая порождается perl, заменить себя на very_long_program, а не запускать Very_long_program в качестве дочернего элемента.

(Причина, по которой perl порождает оболочку в этом случае, заключается в том, что $cmd содержит символы перенаправления - и perl не знает, как обрабатывать их самостоятельно. Альтернативный способ решения проблемы - перенаправление в самом perl. после fork(), но до вызова exec() - но это немного сложнее, поэтому сначала попробуйте обходной путь exec!)

2 голосов
/ 03 июня 2010

Альтернативой является перенаправление STDOUT и STDERR после разветвления и выполнение команды без перенаправления:

open(STDOUT, ">", "out.txt") or die "Err: $!";
open(STDERR, ">&STDOUT");
exec("very_long_command");
die "Failed to exec very_long_command: $!";
...