2017-06-26 5 views

Répondre

2

Le pump jette un die sur les erreurs ou écrit son message à STDERR si « appelé après toutes les activités attelés ont terminé. » Voir à droite avant la section ROUTINES et pump elle-même. Le deuxième cas peut survenir si l'enfant est sorti. Alors envelopper le pump appel à eval, et également convertir des avertissements die pour attraper Mais cela seul les deux cas

if ($talk_to_child) 
{ 
    eval { 
     local $SIG{__WARN__} = sub { die "pump WARNING: @_" }; 
     pump $harness; 
    }; 
    if ([email protected]) { 
     print [email protected]; 
     $talk_to_child = 0; 
    }; 
} 
# ... and eval {} for finish() 

ne sera pas coupé: lorsqu'un parent tente d'écrire à un enfant qui est sorti il ​​obtient un SIGPIPE, ce qui met fin au processus. Il en va de même lorsqu'un enfant ferme les flux et que le parent tente d'écrire.Donc, installez également un gestionnaire de signal pour qu'il

$SIG{PIPE} = sub { 
    say "$_[0]: $!"; 
    $talk_to_child = 0; # global 
}; 

afin que le parent survit à la SIGPIPE. Le eval est toujours nécessaire car pump jette, aussi.

Ensemble, ils prennent en charge tous les tests que j'ai imaginés, pratiquement en l'état. Encore, un certain traitement dans le gestionnaire et dans eval est nécessaire pour distinguer les cas d'intérêt si cela est souhaité.

Si cela équivaut à trop d'une autre manière est de vérifier avant chaque appel. Voir this post pour les vérifications d'une ligne (enveloppées dans des sous-marins) de: (1) si un enfant est en cours d'exécution, result et (2) si "existe des canaux d'E/S ouverts ou des processus actifs", en utilisant pumpable.

Je pense que vous voulez les deux, et aussi jeter dans le gestionnaire SIGPIPE. Cela devrait le couvrir.

Je ne peux pas être plus précis ici puisque la question ne fournit pas de détails.

+0

Belle prise de 'SIGPIPE'. Je pense que c'était ce qui me manquait :) –

+0

@ HåkonHægland A droite, le 'SIGPIPE' est le bouchon du spectacle. Mais c'est encore compliqué. Il peut être plus simple de vérifier avant chaque appel en utilisant une combinaison de 'result' et' pumpable' (plus le gestionnaire 'SIGPIPE'). – zdim

+0

@ AndrzejA.Filip J'ai mis à jour la réponse avec un commentaire sur la vérification directe en utilisant 'result' +' pumpable' (+ 'SIGPIPE' handler). J'ai également édité quelques commentaires pour l'exactitude. J'ai confirmé dans mes tests que l'approche principale dans la réponse traite tous les cas, pratiquement comme elle est. Faites-nous savoir comment cela fonctionne pour vous. La réponse de @ Håkon a également été mise à jour. – zdim

1

Mise à jour: Merci à @zdim pour me rappeler de vérifier le signal SIGPIPE. Voici une mise à jour de ma réponse qui vérifie également SIGPIPE:

J'ai fait un test simple en utilisant start, pump et finish. Voici le script principal p.pl que je:

use feature qw(say); 
use strict; 
use warnings; 
use IPC::Run; 

my $child_in; 
my $child_out; 
my $child_err; 
my $child_name = shift; 

my $harness = eval { 
    IPC::Run::start [ $child_name ], \$child_in, \$child_out, \$child_err; 
}; 
if ([email protected]) { 
    chomp [email protected]; 
    die "Caught exception: '[email protected]'"; 
} 
for (1..2) { 
    $child_in = "Joe$_\n"; 
    say "Parent sleeping for 1 second.."; 
    sleep 1; 
    eval { 
     local $SIG{PIPE} = sub { 
      die "Parent received SIGPIPE. " 
       . "Child is either dead or has closed its input pipe\n"; 
     }; 
     say "Sending data to child.."; 
     my $result = $harness->pump; 
     say "IPC::Run::pump() returned: ", $result ? "TRUE" : "FALSE"; 
    }; 
    if ([email protected]) { 
     chomp [email protected]; 
     say "IPC::Run::pump() failed: '[email protected]'"; 
     last; 
    } 
    say "\$child_in = '$child_in'"; 
    say "\$child_out = '$child_out'"; 
} 
say "Finishing harness.."; 
my $res = eval { 
    local $SIG{PIPE} = sub { 
     die "Parent received SIGPIPE. " 
      . "Child is either dead or has closed its input pipe\n"; 
    }; 
    $harness->finish; 
}; 
if ([email protected]) { 
    chomp [email protected]; 
    die "IPC::Run::finish() failed: '[email protected]'\n"; 
} 
printf "IPC::Run::finish() returned: '%s'\n", $res ? "TRUE" : "FALSE"; 
chomp $child_out; 
say "STDOUT from child: '$child_out'"; 
chomp $child_err; 
say "STDERR from child: '$child_err'"; 
say "Child returned exit code: ", $harness->result; 
say "Parent exited normally.." 

je trois scripts enfants différents:

child.pl:

#! /usr/bin/env perl  
use feature qw(say); 
use strict; 
use warnings; 

my $reply = <STDIN>; 
chomp $reply; 
say "Hello $reply"; 
my $reply2 = <STDIN>; 
chomp $reply2; 
say "Got second reply: $reply2"; 
exit 0; 

et sortie:

$ p.pl child.pl 
Parent sleeping for 1 second.. 
Sending data to child.. 
IPC::Run::pump() returned: TRUE 
$child_in = '' 
$child_out = '' 
Parent sleeping for 1 second.. 
Sending data to child.. 
IPC::Run::pump() returned: TRUE 
$child_in = '' 
$child_out = '' 
Finishing harness.. 
IPC::Run::finish() returned: 'TRUE' 
STDOUT from child: 'Hello Joe1 
Got second reply: Joe2' 
STDERR from child: '' 
Child returned exit code: 
Parent exited normally.. 

enfant2.pl:

#! /usr/bin/env perl 
use feature qw(say); 
use strict; 
use warnings; 

my $reply = <STDIN>; 
chomp $reply; 
say "Hello $reply"; 
die "Child exception\n"; 

et sortie:

$ p.pl child2.pl 
Parent sleeping for 1 second.. 
Sending data to child.. 
IPC::Run::pump() returned: TRUE 
$child_in = '' 
$child_out = '' 
Parent sleeping for 1 second.. 
Sending data to child.. 
IPC::Run::pump() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe' 
Finishing harness.. 
IPC::Run::finish() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe' 

child3.pl:

#! /usr/bin/env perl 
use strict; 
use warnings; 

close \*STDIN; 
close \*STDOUT; 
close \*STDERR; 
sleep 5; 
exit 2; 

et sortie:

$ p.pl child3.pl 
Parent sleeping for 1 second.. 
Sending data to child.. 
IPC::Run::pump() failed: 'ack Parent received SIGPIPE. Child is either dead or has closed its input pipe' 
Finishing harness.. 
IPC::Run::finish() failed: 'Parent received SIGPIPE. Child is either dead or has closed its input pipe' 

Donc, pour ces tes ts, il semble que le signal SIGPIPE peut être utilisé pour vérifier si un enfant est vivant ou a fermé son tube d'entrée. Notez que si vous essayez d'appeler pump() après la fermeture d'un enfant, la sortie précédente de l'enfant est perdue, voir l'exemple child2.pl.

+0

Je suis intéressé par le cas de ** long ** enfant en cours d'exécution avec un grand nombre de "commandes-réponses" des séquences. Je voudrais éviter de pousser les commandes à l'enfant avec STDIN fermé ou des réponses de pompage de l'enfant avec STDOUT fermé. – AnFi