J
J. Romano
Dear Perl Community,
I am interested in using the IPC::Open2 and IPC::Open3 modules. From
reading the documentation I know that a potential problem is that a
program I am talking to may not flush its output, possibly causing a
deadlock. Therefore, I would like to check to see if input is waiting
before reading from the process, by following the advice mentioned in
IPC::Open3's perldoc:
If you try to read from the child's stdout writer and their stderr
writer, you'll have problems with blocking, which means you'll want
to
use select() or the IO::Select, which means you'd best use
sysread()
instead of readline() for normal stuff.
So I wrote a program which uses IO::Select to check for input waiting
to be read, and used sysread() to read its input, one character at a
time. Here is a short program that does just that:
#!/usr/bin/perl -w
use strict;
use IPC::Open3;
use IO::Select;
$| = 1; # autoflush STDOUT
# Declare filehandles and command to use:
my ($w, $r, $e);
my $cmd = 'perl -ne "$| = 1; print uc($_)"';
# Open the process and set the selector:
my $pid = open3($w, $r, $e, $cmd);
my $selector = IO::Select->new($r);
while (<>)
{
print $w $_; # send line to process
sleep 1; # allow some time for request to process
# print out output from process, if any exists:
while ($selector->can_read(0))
{
my $char;
sysread($r, $char, 1);
print $char;
}
}
__END__
A quick note: The program that is spawned which I communicate with is
specified near the top of the script in the line:
my $cmd = 'perl -ne "$| = 1; print uc($_)"';
This is basically a program that does nothing but print out a copy of
its input in capital letters. Also note that $| (the autoflush
variable) is set to non-zero (ensuring that the output is flushed
frequently).
Back to the problem: This short script works perfect on the two UNIX
machines I tested it on, but it doesn't work on the two versions of
ActiveState ActivePerl I tried it on. When I ran this script using
ActivePerl, it behaved as though the inner while loop did not exist.
For anyone who is interested, "perl -v" on one of the machines printed
the following information:
This is perl, v5.8.0 built for MSWin32-x86-multi-thread
(with 1 registered patch, see perl -V for more detail)
Binary build 805 provided by ActiveState Corp.
http://www.ActiveState.com
Built 18:08:02 Feb 4 2003
What's more is, when I replaced the inner while loop with the line:
print scalar <$r>;
the program worked just fine. This doesn't help, however, because I
want to be able to check to see if there is any data waiting to be
read (using IO::Select) before I try reading, otherwise I might cause
a deadlock.
I also tried the same thing with IPC::Open2, and I got the same
situation: it worked perfectly on UNIX, but not on ActivePerl.
I seached the newsgroups for any mention of this problem with
ActivePerl, but nothing turned up.
So am I doing anything wrong? Am I missing something? Do other
ActivePerl users have the same problem? And if so, is it a bug in
ActivePerl?
Thanks in advance for any responses,
Jean-Luc
I am interested in using the IPC::Open2 and IPC::Open3 modules. From
reading the documentation I know that a potential problem is that a
program I am talking to may not flush its output, possibly causing a
deadlock. Therefore, I would like to check to see if input is waiting
before reading from the process, by following the advice mentioned in
IPC::Open3's perldoc:
If you try to read from the child's stdout writer and their stderr
writer, you'll have problems with blocking, which means you'll want
to
use select() or the IO::Select, which means you'd best use
sysread()
instead of readline() for normal stuff.
So I wrote a program which uses IO::Select to check for input waiting
to be read, and used sysread() to read its input, one character at a
time. Here is a short program that does just that:
#!/usr/bin/perl -w
use strict;
use IPC::Open3;
use IO::Select;
$| = 1; # autoflush STDOUT
# Declare filehandles and command to use:
my ($w, $r, $e);
my $cmd = 'perl -ne "$| = 1; print uc($_)"';
# Open the process and set the selector:
my $pid = open3($w, $r, $e, $cmd);
my $selector = IO::Select->new($r);
while (<>)
{
print $w $_; # send line to process
sleep 1; # allow some time for request to process
# print out output from process, if any exists:
while ($selector->can_read(0))
{
my $char;
sysread($r, $char, 1);
print $char;
}
}
__END__
A quick note: The program that is spawned which I communicate with is
specified near the top of the script in the line:
my $cmd = 'perl -ne "$| = 1; print uc($_)"';
This is basically a program that does nothing but print out a copy of
its input in capital letters. Also note that $| (the autoflush
variable) is set to non-zero (ensuring that the output is flushed
frequently).
Back to the problem: This short script works perfect on the two UNIX
machines I tested it on, but it doesn't work on the two versions of
ActiveState ActivePerl I tried it on. When I ran this script using
ActivePerl, it behaved as though the inner while loop did not exist.
For anyone who is interested, "perl -v" on one of the machines printed
the following information:
This is perl, v5.8.0 built for MSWin32-x86-multi-thread
(with 1 registered patch, see perl -V for more detail)
Binary build 805 provided by ActiveState Corp.
http://www.ActiveState.com
Built 18:08:02 Feb 4 2003
What's more is, when I replaced the inner while loop with the line:
print scalar <$r>;
the program worked just fine. This doesn't help, however, because I
want to be able to check to see if there is any data waiting to be
read (using IO::Select) before I try reading, otherwise I might cause
a deadlock.
I also tried the same thing with IPC::Open2, and I got the same
situation: it worked perfectly on UNIX, but not on ActivePerl.
I seached the newsgroups for any mention of this problem with
ActivePerl, but nothing turned up.
So am I doing anything wrong? Am I missing something? Do other
ActivePerl users have the same problem? And if so, is it a bug in
ActivePerl?
Thanks in advance for any responses,
Jean-Luc