Hi all,
nothing mission critical, just something I don't fully understand yet :) More precisely, the can_write() method of IO::Select doesn't seem to test what I think its name would suggest.
While playing around with How and When to read STDOUT after using open3() funciton? I encountered a problem when trying to write to the filehandle that open3() connects to STDIN of the command being run. My initial code (simplified to the minimum) was as follows:
#!/usr/bin/perl use strict; use warnings; use IPC::Open3; use IO::Select; my @cmd = qw'echo bar'; # writing to 'echo' fails #my @cmd = qw'cat'; # ... while 'cat' works open3(my $wh, my $rh, undef, @cmd); # tiny delay, so the command gets enough time to close STDIN # (prevent potential race condition, in this demo script) select undef,undef,undef, 0.1; my $msg = "foo"; #----- print $wh "$msg\n"; close $wh; #----- my $data = ""; if (IO::Select->new($rh)->can_read()) { print "reading from $rh ('@cmd |')\n"; while (sysread($rh, my $buffer, 1000)) { $data .= $buffer; } } print "data: $data\n";
Problem with this code is that it simply terminates before it starts doing anything useful. Apparently, the issue is that the command being run via open3() is closing STDIN, so an attempt to write to it causes a SIGPIPE, which in turn leads to the script being killed by the default signal handler... Or some such. Ok, silly thing to do... to write to a program that doesn't take input, but anyway.
So, I changed the section between the #----- to read:
#----- # handle SIGPIPE ourselves, so we don't get killed $SIG{PIPE} = sub { warn "BROKEN PIPE\n" }; if (my ($w) = IO::Select->new($wh)->can_write()) { if (print $w "$msg\n") { print "wrote '$msg' to $w ('| @cmd')\n"; close $w; } else { warn "print to $w FAILED\n"; # we'll have gotten a SIGPIPE, too } } else { warn "$wh not ready for writing\n"; } #-----
I would've thought that carefully testing with can_write() would avoid running into the situation that's causing the SIGPIPE... However, this doesn't seem to be the case. With the command being echo I still get
BROKEN PIPE print to GLOB(0x6ff5b0) FAILED reading from GLOB(0x6ff360) ('echo bar |') data: bar
while with cat things work as expected (as it doesn't close STDIN):
wrote 'foo' to GLOB(0x63c160) ('| cat') reading from GLOB(0x6ff5a0) ('cat |') data: foo
With echo I would have expected to see
GLOB(0x6ff5b0) not ready for writing reading from GLOB(0x6ff360) ('echo bar |') data: bar
Can someone explain why this doesn't work as I first thought it should?
Hm, on second thought, I figure it has to do with the writability referring to the local side of the pipe only, rather than the entire pipe including the status of the remote side...(?) Which brings up the question: is there a 'proper' way to test if the pipe can be written to (other than waiting for the SIGPIPE to happen, and then handling it)? Thanks.
In reply to Pipes and IO::Select's method can_write() by almut
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |