|
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
|
Re: [PLUG] fun with perl: eval{} and exceptions
|
> > eval { $cmd_pid=open3(\*IN, \*OUT, \*ERR, @cmd); };
> > if($@ =~ /exec/){
> > print "\@ is $@\n";
> > $cmd_errstr = $@;
> > $cmd_retval = "-1";
> > die;
> > };
> > ...
>
> oh, i forgot: the duplicates happen if you take out the call to die(),
> but not if you leave it in, which is why i'm thinking this is some
> wierdness involved with a fork().
Well, I just hacked togeather some test code and it looks like open3
first creates pipes appropriately, then forks, and then attempts to
exec the command.
Since the fork has already happened, a failure of exec(), now in the
child, can only be reported to it's std{out,err}.
I don't get mixed output, I get synchronous output. The only trick is
to exit in the child (if $pid is zero/undef) _after_ the implied exec
(so if the exec fails in the child, the child still exits).
HTH
Kyle
use strict;
use warnings;
use IPC::Open3;
$|++;
#my @cmd = qw(ls -ld /tmp); # works
#my @cmd = qw(ls -l /adsftmp); # command errors after successful fork+exec
my @cmd = qw(addfadf -l /tmp); # fails exec after fork
my $pid = '';
my $sigpipe = 0;
$SIG{PIPE} = sub {
print STDERR "got SIGPIPE\n";
$sigpipe++;
};
my($in,$out,$err) = ('','','');
eval {
$pid = open3($in,$out,$err,@cmd);
unless ( $pid ) {
print "\$\$=$$ pid=$pid Whoa, the exec failed?: $!\n";
}
print "\$\$=$$ pid=$pid open3 returned\n";
};
print "\$\$=$$ pid=$pid back outside the eval...\n";
if ($@) {
die "\$\$=$$ pid=$pid whoops: $@";
}
print "\$\$=$$ pid=$pid no exception, everthing seems to have worked, proceding to read \n";
sleep 1;
readfh_nonblock("out",$out);
sleep 1;
readfh_nonblock("err",$err);
foreach my $fh ($in,$out,$err) {
close $fh if $fh;
}
print "finished, closing file handles\n";
print " pid=$pid\n";
print " sigpipe=$sigpipe\n";
# non-blocking read loop
sub readfh_nonblock {
my($name,$fh) = @_;
return unless $fh;
print "$name:\n";
print " pid=$pid\n";
print " sigpipe=$sigpipe\n";
print "$name===>\n";
while (1) {
my $buff;
my $nr = sysread($fh,$buff,1024);
unless (defined $nr) {
print "Error reading from handle $name: $!\n";
last;
}
last unless $nr;
print $buff;
}
print "<===$name\n";
}
--
------------------------------------------------------------------------------
Wisdom and Compassion are inseparable.
-- Christmas Humphreys
mortis@voicenet.com http://www.voicenet.com/~mortis
------------------------------------------------------------------------------
___________________________________________________________________________
Philadelphia Linux Users Group -- http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion -- http://lists.phillylinux.org/mailman/listinfo/plug
|
|