2010-06-03 11 views
6

Ho creato uno script in perl per eseguire programmi con un timeout. Se il programma in esecuzione richiede più tempo allora il timeout rispetto allo script uccide questo programma e restituisce il messaggio "TIMEOUT".Problemi con fork exec kill durante il reindirizzamento dell'output in perl

Lo script ha funzionato abbastanza bene fino a quando ho deciso di reindirizzare l'output del programma eseguito.

Quando lo stderr e lo stderr vengono reindirizzati, il programma eseguito dallo script non viene ucciso perché ha un pid diverso da quello ricevuto dalla forcella.

Sembra che perl esegua una shell che esegue il mio programma in caso di reindirizzamento.

Mi piacerebbe avere il reindirizzamento dell'output ma è comunque possibile interrompere il programma in caso di timeout.

Qualche idea su come potrei farlo?

un codice semplificato del mio script è:

#!/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($?); 

Grazie per qualsiasi aiuto.

risposta

11

Prova a cambiare $cmd da

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

a

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

Il exec dirà il guscio che viene generato da perl a sostituire se stesso con very_long_program, piuttosto che correre very_long_program come un bambino.

(Il motivo per cui spawn una shell in questo caso è perché $cmd contiene i caratteri di reindirizzamento e perl non sa come gestirli da solo. Un modo alternativo per risolvere il problema è eseguire il reindirizzamento in perl stesso dopo il fork() ma prima di chiamare exec() - ma questo è un po 'più complicato, in modo da provare la soluzione exec prima)

+0

! Intelligente, pulito e funziona. Tks. – Edu

2

un'alternativa è quella di reindirizzare STDOUT e STDERR dopo la forcella ed eseguire il comando senza il reindirizzamento:

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