2011-12-09 21 views
6

Ho uno script perl che esegue una serie di script batch per i test di regressione. Voglio implementare un timeout sugli script batch. Al momento ho il seguente codice.allarme perl con sottoprocesso

my $pid = open CMD, "$cmd 2>&1 |"; 
    eval { 
       # setup the alarm 
       local $SIG{ALRM} = sub { die "alarm\n" }; 
       # alarm on the timeout 
       alarm $MAX_TIMEOUT; 
       log_output("setting alarm to $MAX_TIMEOUT\n"); 

       # run our exe 
       while(<CMD>) { 
         $$out_ref .= $_; 
       } 
       $timeRemaining = alarm 0; 
      }; 
      if ([email protected]) { 
        #catch the alarm, kill the executable 
      } 

Il problema è che indipendentemente dall'impostazione del timeout massimo, l'allarme non viene mai attivato. Ho provato a usare Perl :: Unsafe :: Signals ma questo non ha aiutato.

È questo il modo migliore per eseguire gli script batch se voglio essere in grado di acquisire il loro output? C'è un altro modo in cui farei la stessa cosa che mi permetterebbe di usare gli allarmi, o c'è un altro metodo oltre agli allarmi per interrompere il programma?

Ho creato uno script di test per confermare che l'allarme funziona con la mia versione perl e windows, ma non funziona quando eseguo un comando come questo.

Sto eseguendo questo con activeperl 5.10.1 su Windows 7 x64.

risposta

4

E 'difficile dire quando funzionerà alarm, quando una chiamata di sistema e non sarà possibile ottenere interrotto da un SIGALRM, come lo stesso codice potrebbe comportarsi in modo diverso su diversi sistemi operativi, ecc

Se i tempi di lavoro fuori, vuoi uccidere il sottoprocesso che hai avviato. Si tratta di un caso d'uso buono per l'allarme del povero:

my $pid = open CMD, "$cmd 2>&1 |"; 
my $time = $MAX_TIMEOUT; 

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid"; 
if (fork() == 0) { 
    exec($^X, "-e", $poor_mans_alarm); 
    die "Poor man's alarm failed to start"; # shouldn't get here 
} 
# on Windows, instead of fork+exec, you can say 
# system 1, qq[$^X -e "$poor_mans_alarm"] 


... 

del poveretto corse di allarme in un processo separato. Ogni secondo, controlla se il processo con identificativo $pid è ancora attivo. Se il processo non è attivo, il processo di allarme termina. Se il processo è ancora attivo dopo $time secondi, invia un segnale di eliminazione al processo (io ho usato 9 per renderlo inaccessibile e -9 per rimuovere l'intero albero di sottoprocesso, le tue esigenze potrebbero variare).

(Il numero exec potrebbe non essere necessario. Io lo uso perché anch'io uso questo idioma per monitorare i processi che potrebbero sopravvivere allo script Perl che li ha lanciati. Poiché non sarebbe il caso con questo problema, si potrebbe saltare il exec chiamata e dicono

if (fork() == 0) { 
    for (1..$time) { sleep 1; kill(0,$pid) || exit } 
    kill -9, $pid; 
    exit; 
} 

invece.)