|No such thing as a small change|
Safe Pipe Opens and Implicit Loopsby martin (Friar)
|on Jul 08, 2010 at 20:04 UTC||Need Help??|
I have frequently used the pseudo-filenames "-|" and "|-" as suggested in perldoc perlipc to safely open pipes, i.e. in a way that I can control what should happen just after forking and on failure.
With recent perls -- I have checked 5.10.1 and 5.12.1 on Linux and MacOS X --, however, part of that control seems to have been lost. Safe pipes now seem to loop over EAGAIN error events. There is even a warning issued when such events occur:
Can't fork, trying again in 5 seconds at ... line ...
I wonder how perl code is now supposed to break out of such a loop, or how new semantics could slip undocumented into such a basic construct.
(EAGAIN is the error code by which most Unix(-like) systems tell the caller that fork() was temporarily not possible.)
Quoting perlipc, this is where I got the idea that a retry-loop in such a scenario was my own responsibility to set up:
Moreover, if sleeping and issuing warnings was not what I wanted to happen, I could always omit the loop and bail out right away, like so:
Unfortunately, this no longer seems to be the case. Code like that second example now loops and warns indefinitely on its own accord, if the process happens not to be able to fork for some time.
A workaround I have come up with is to hook onto the warning, like this:
I do not claim this to be backwards compatible with very old perls, however.
Personally, I consider the new Safe Pipe semantics a bug, seeing as '|-' and '-|' had been a conveniently low-level feature before.
The only reason I can think of why implicit retrys might seem preferable is that repeated pipe() system calls would not be wasted during the loop. But optimizations like that should not be bought at the price of changing behaviour of code that actually still seems to be backed by the documentation.
But how long ago has this change taken place? Just before posting this article I found out that perl 5.8.9 seems to have the loop but not the warning, rendering my workaround useless. A perl 5.8 program just hangs at the open statement as long as no new processes are available. Sigh.
It would be possible to emulate the one-shot Safe Pipe Open behaviour using pipe(), fork() and STDIN/STDOUT reassignment explicitly. That would of course no longer be a concise perl idiom unless provided by a module. A cursory CPAN search just now did not bring up anything of the kind. (Wink, wink, wink -- any volunteers?)
Feel free to comment or suggest other solutions.