Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

question on getting SIGPIPE in close

by perl-diddler (Chaplain)
on Apr 27, 2020 at 23:56 UTC ( [id://11116138]=perlquestion: print w/replies, xml ) Need Help??

perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I have some code that spawns off a child to do some work. Parent + child communicate over a pipe. I set both parts of the pipe for *unbuffered* I/O. Include snippets of code to show code for what I describe.
pipe($iopair[0], $iopair[1]) or die "Failed opening pipe in start_reader: $!"; for (qw(0 1)) { select $iopair[$_]; $|=1;} #unbuffer pipe I/O
When parent writes last message to child I setup a pipe handler to trap any pipe sigs:
local * write_child = sub ($) { my $out=$_[0]; return unless $iopair[1] and ref $iopair[1] and -w $iopair[1]; local * pipe_catch = sub ($) { Debug "Child closed"; $iopair[1] = $iopair[0] = undef; }; $SIG{PIPE}=\&pipe_catch; P $iopair[1], $out."\n"; $SIG{PIPE}='DEFAULT'; };
With the next thing happening being a close on the pipe. The close doesn't have a SIG catcher, since there should be no SIGPIPE that would come from trying i/o on a closed pipe.
sub close_child_io () { Debug "SigCHLD: close iopair[1]"; my $tmp = $PathTree::iopair[1]; $PathTree::iopair[1] = undef; close($tmp); };

This works on linux, but on windows, I get a PIPE error in the close routine:

[#2576(PathTree::__ANON__)]Child closed Warning: unable to close filehandle $iopair[...] properly: Broken pipe + at /Users/law.Bliss/bin/lib/P.pm line 509.
The child is closed in the main program @ln 2576, but I see an error, at the last line in 'P' as it is exiting, which isn't far from where I would expect it if I didn't have the SIG{PIPE} handler wrapping that call. I.e. parent tells child it is done and to go away, so it does, but that should happen in the print wrapped in the PIPE handler.

So question is this -- would you think this is a bug in the windows implementation given it works in linux -- and would you expect any PIPE errors in write (P) to be trapped by the sig handler?

FWIW, the line where this is dumped is

509: unsee_ret($res); 510: }
where unsee_ret:
local * unsee_ret; * unsee_ret = sub ($) { delete $p->{__P_seen} if exists $p->{__P_seen}; $_[0] };
could be a do block:
do { delete $p->{__P_seen} if exists $p->{__P_seen}; $res;};
but isn't because it's done in more than one place. __P_seen is an internal hash of already seen refs in a call so P doesn't try to re-expand an already expanded ref. Only showed detail to show that it really was at the point of exit of P where I might get some auto-close behaviors.

Repeating my question in a different way: since the print call is wrapped in a PIPE handler, shouldn't the error have been seen in the pipe handler, where the code tries to turn it into an ignorable error, but instead I get a 'WARNING'. I'm pretty sure I'll just chase down a work-around -- but isn't that a correct way to do things? Perl version is Cygwin-perl 5.26.3. This isn't a time-sensitive issue, I was just playing around w/a prog I thought might be nice to have working on windows and working through the kinks...
Thanks!

Replies are listed 'Best First'.
Re: question on getting SIGPIPE in close
by jcb (Parson) on Apr 29, 2020 at 01:11 UTC

    Windows does not actually have signals. There is no SIGPIPE on Windows, so Perl is emulating it somehow. My guess is that close attempts to flush buffers, which are empty at that point in your program, so flushing them is a no-op on *nix, (only an actual write triggers SIGPIPE — flushing an empty buffer does not count) but Perl emulates SIGPIPE on Windows by asking the OS if the pipe is still connected. It is not, so "SIGPIPE" is raised.

      Sounds good, but so far, not sure how to avoid the message since it isn't in my code.

      I.e. it appears perl is checking the value of close and putting out the error whether I want it or not. Trying to stop the error with a 'no warnings' just before the final close doesn't silence the message. Only by disabling STDERR and redirecting to to /dev/null (cygwin) then restoring it do I effectively silence the message.

      While I don't disagree with the idea of checking 'close' for errors (and usually do so). It would be nice to be able to tell perl not to warn me about problems there.

        Does {local $SIG{PIPE} = sub {}; close($pipe)} work? My guess is that perl is checking the status of the pipe and emulating SIGPIPE when you close it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11116138]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-19 03:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found