Subject: | Mail::GPG blocks in perform_multiplexed_gpg_io at eof($stderr_fh) check |
Date: | 25 May 2009 17:35:33 -0000 |
To: | bug-Mail-GPG [...] rt.cpan.org |
From: | hcmav6c02 [...] sneakemail.com |
Perl version is 5.10.0 and this is on NetBSD 4.0. Module version is latest:
# $Id: GPG.pm,v 1.23 2006/11/18 08:49:05 joern Exp $
$VERSION = "1.0.6";
Mail::GPG is blocking in the above function and I have included a debugged version of the function below (which includes the output I experience when the stall happens).
Note that also in another run of the code, I get a stall in the very first outer iteration. The results don't seem to be consistent. Is it possible that the tests in the return statement are overkill? Is there a logic possible that would cause a stall? What would cause eof() itself to block? It seems that eof() isn't called twice on the same filehandle.
inner iteration 811
inner iteration 812
exited inner
alpha
beta
charlie
delta
binary 0, 1
[stalls here -- before printing "binary 1"]
[also note the debugged code in another run stalls at the same point but at the second master (outer) iteration]
Practically speaking, this means that Mail::GPG is at present unusable to me. I would be happy to provide further details to debug.
I hope this information will be helpful.
What I see on the host is that the "gpg" process continues to be "running" (although it's not using any CPU). When I replaced "gpg" with a script that does something like ``real-gpg "$@" > file; exec cat file'', then the cat process itself just hangs around there too.
There seems to be a logic error (perhaps overkill) in the checking of the return condition. The data is processed fine, it seems, since there are several hundred successful iterations of the loop above it. But the clues I get on the tail output suggest that gpg has done what it needs to do, and perhaps shouldn't need to go through another outer iteration.
Maybe in the earlier iteration, when $status_fh has been found to be undef, then that alone could mean that there can be no more practical processing that can take place.
sub perform_multiplexed_gpg_io {
my $self = shift;
my %par = @_;
my ($data_fh, $data_canonify, $stdin_fh, $stderr_fh) =
@par{'data_fh','data_canonify','stdin_fh','stderr_fh'};
my ($stdout_fh, $status_fh, $stderr_sref, $stdout_sref) =
@par{'stdout_fh','status_fh','stderr_sref','stdout_sref'};
my ($status_sref) =
$par{'status_sref'};
print STDERR "one\n";
#-- perl < 5.6 compatibility: seek() and read() work
#-- on native GLOB filehandle only, so dertmine type
#-- of filehandle here
my $data_fh_glob = ref $data_fh eq 'GLOB';
#-- rewind the data filehandle
if ($data_fh_glob) {
seek $data_fh, 0, 0;
}
else {
$data_fh->seek( 0, 0 );
}
print STDERR "two\n";
#-- create IO::Select objects for all
#-- filehandles in question
my $stdin = IO::Select->new($stdin_fh);
my $stderr = IO::Select->new($stderr_fh);
my $stdout = IO::Select->new($stdout_fh);
my $status = $status_fh ? IO::Select->new($status_fh) : undef;
my $buffer;
print STDERR "just before while loop\n";
my $myiter =0 ;
while (1) {
$myiter++;print STDERR "iteration $myiter\n";
my $myiter2=0;
#-- as long we has data try to write
#-- it into gpg
while ( $data_fh && $stdin->can_write(0.1) ) {
$myiter2++;print STDERR "inner iteration $myiter2\n";
if ( $data_fh_glob
? read $data_fh,
$buffer, 1024
: $data_fh->read( $buffer, 1024 ) ) {
#-- ok, got a block of data
if ($data_canonify) {
#-- canonify it if requested
$buffer =~ s/\x0A/\x0D\x0A/g;
$buffer =~ s/\x0D\x0D\x0A/\x0D\x0A/g;
}
#-- feed it into gpg
print $stdin_fh $buffer;
}
else {
#-- no data read, close gpg's stdin
#-- and set the data filehandle to false
close $stdin_fh;
$data_fh = 0;
}
}
print STDERR "exited inner\n";
print STDERR "alpha\n";
#-- probably we can read from gpg's stdout
while ( $stdout->can_read(0.1) ) {
last if eof($stdout_fh);
$$stdout_sref .= <$stdout_fh>;
}
print STDERR "beta\n";
#-- probably we can read from gpg's stderr
while ( $stderr->can_read(0.1) ) {
last if eof($stderr_fh);
$$stderr_sref .= <$stderr_fh>;
}
print STDERR "charlie\n";
#-- probably we can read from gpg's status
if ($status) {
while ( $status->can_read(0.1) ) {
last if eof($status_fh);
$$status_sref .= <$status_fh>;
}
}
print STDERR "delta\n";
#-- we're finished if no more data left
#-- and both gpg's stdout and stderr
#-- are at eof.
print STDERR "binary 0, ", !$data_fh, "\n";
print STDERR "binary 1, ", eof($stderr_fh), "\n";
print STDERR "binary 2, ", eof($stdout_fh), "\n";
print STDERR "binary 3, ", !$status_fh, "\n";
if ($status_fh) {
print STDERR "binary 4, ", eof($status_fh), "\n";
} else {
print STDERR "binary 4 - check skipped due to undeflike quality of status_fh.\n";
}
return
if !$data_fh
&& eof($stderr_fh)
&& eof($stdout_fh)
&& ( !$status_fh || eof($status_fh) );
print STDERR "echo\n";
}
#....
#exited inner
#alpha
#beta
#charlie
#delta
#binary 0, 1
#binary 1,
#binary 2,
#binary 3, 1
#binary 4 - check skipped due to undeflike quality of status_fh.
#echo
#iteration 2
#exited inner
#alpha
#beta
#charlie
#delta
#binary 0, 1
#[stalls here]
1;
}