From bc00321f36d67bd172ead740be6cc5b5ba04a6ec Mon Sep 17 00:00:00 2001 From: Xiaoqiang Wang Date: Mon, 17 Aug 2020 13:10:43 +0200 Subject: [PATCH] use select to read child process's stdout and stderr --- App/tools/getVersion.pl | 57 +++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/App/tools/getVersion.pl b/App/tools/getVersion.pl index ffe34f0..1c54c69 100755 --- a/App/tools/getVersion.pl +++ b/App/tools/getVersion.pl @@ -5,7 +5,8 @@ use strict; use 5.010; use File::Glob qw/bsd_glob/; -use IPC::Open3; +use IPC::Open3 qw/open3/; +use Symbol qw/gensym/; # cvs status parsing state use constant { @@ -35,27 +36,49 @@ while (@ARGV) { my $files = join(' ', @files); sub check_output { - my ($child_stdin, $child_stdout, $child_stderr); + my ($child_stdout, $child_stderr); + $child_stderr = gensym(); + chomp(my $command = $_[0]); - # start the child process and wait for it to finish - my $child_pid = open3($child_stdin, $child_stdout, $child_stderr, $command); - waitpid($child_pid, 0); - if ($? != 0) { - my $error; - foreach (<$child_stdout>) { - $error .= $_; + # start the child process capturing stdout and stderr + my $child_pid = open3(undef, $child_stdout, $child_stderr, $command); + + # filehandles' bitmask for read + my $out_set = ''; + vec($out_set, fileno($child_stdout), 1) = 1; + vec($out_set, fileno($child_stderr), 1) = 1; + my $num_bits = 2; + + # output and error from the child process + my $output = ''; + my $error = ''; + + while ($num_bits and select(my $rout=$out_set, undef, undef, 5)) { + for my $fh ($child_stdout, $child_stderr) { + next unless vec($rout, fileno($fh), 1); + + my $bytes_read = sysread($fh, my $line, 4096); + if ($bytes_read) { + if ($fh == $child_stdout) { + $output .= $line; + } + elsif ($fh == $child_stdout) { + $error .= $line; + } + } + else { + + vec($out_set, fileno($fh), 1) = 0; + $num_bits -= 1; + } } - die $error; } - # read child process output - my @output = (); - foreach my $line (<$child_stdout>) { - push @output, $line; - } + waitpid($child_pid, 0); + die $error if $?; - return @output; + return split(/\n/, $output); } sub parse_cvs_output { @@ -126,7 +149,7 @@ sub parse_cvs_output { return; } elsif ($line =~ /no such directory `(.*)'/) { - say STDERR "checking directory $1: so such directory"; + say STDERR "checking directory $1: no so such directory"; return; } elsif ($line =~ /cvs \[status aborted\]: there is no version here/) {