Two part question:
I'm using IPC::Open3 on Win32 to avoid the shell. Notice how double quotes are handled below. I'm assuming this is
a Windows issue and not a Perl issue, correct? Extra points if you can explain the logic of this. ;)
#!/usr/bin/perl -w
use strict;
use IPC::Open2;
my @command = (
'perl',
'my test.pl',
'first arg1',
'"second arg2"',
'word "quoted" and \"backslashed\" word',
'"2word "quoted" and \"backslashed\" word"',
);
my $pid = IPC::Open2::open2( \*r, \*w, @command );
print "Pid = $pid\n";
print "output:\n";
print while $_ = <r>;
print "done\n";
With output on Win32 as:
Pid = 316925
output:
316925 [first arg1]
316925 [second arg2]
316925 [word]
316925 [quoted]
316925 [and]
316925 ["backslashed"]
316925 [word]
316925 [2word quoted and "backslashed" word]
316925 done
done
Part two of my IPC::Open3 question:
The docs say to call waitpid($pid,0) to reap the child process -- and indeed the windows process table fills up (64 processes?) if waitpid isn't called.
See, I've got a function that returns a file handle. Under Windows it uses IPC::Open3, otherwise it does a open($fh,'-|') call. So the code that calls this function isn't suppose to know or care about how that file handle is generated.
The question is about when to call waitpid() on Windows. I assume it must be called after calling close() (or after the returned file handle goes out of scope). Is that a correct assumption?
If waitpid() has to be called after the close() that means the function that returns the file handle must store the PID some place. So, seems like I need to tie the handle.
Here's my code. I have a few follow-up questions at the end:
#!/usr/bin/perl -w
use strict;
my %self;
my @command = (
'perl',
'my test.pl',
'one arg',
'"two arg"'
);
{
my $fh = windows_fork( \%self, @command );
print while <$fh>;
}
print "out of scope\n";
exit;
sub windows_fork {
my ( $self, @args ) = @_;
require IPC::Open2;
my ( $rdrfh, $wtrfh );
# Deal with windows quotes
my @command = map { s/"/\\"/g; qq["$_"] } @args;
my $pid = IPC::Open2::open2($rdrfh, $wtrfh, @command );
binmode $rdrfh, ':crlf';
tie *handle, 'call_waitpid', $rdrfh, $pid;
return \*handle
}
package call_waitpid;
use strict;
sub TIEHANDLE {
my ( $class, $fh, $pid ) = @_;
bless {
handle => $fh,
pid => $pid,
}, $class;
}
sub READLINE {
my ( $self ) = @_;
my $fh = $self->{handle};
return <$fh>;
}
sub DESTROY {
my ( $self ) = @_;
close $self->{handle};
waitpid $self->{pid}, 0;
}
Questions:
-
Is this how you would deal with this issue. Use a tied handle to track the PID?
-
In READLINE I cannot do: return <$self->{handle}>; why?
syntax error at fork.pl line 81, near "<$self->{handle"
-
In the "windows_fork() sub I'm blessing a typeglob. The problem is it's the same typeglob for every call to windows_fork(). So if windows_fork() is called twice the handles are mixed. I tried using gensym() but couldn't get that to work. I need a way to have more than one file handle active at a time.
my $fh = windows_fork( \%self, 'perl', 'my test.pl', 'first stuff');
my $fg = windows_fork( \%self, 'perl', 'my test.pl', 'other stuff');
print while <$fh>;
Results in "other stuff" from $fh.