Hi all,
On Mon, 28 Nov 2022, Arsen Arsenović wrote:
Pádraig Brady <P@draigBrady.com> writes:
Trying to understand your use case better,
...
The bug we observed is that on occasion, for instance when running with a
tty, or with a script that (for some reason) has a pipe on stdin, the
tee-based "compiler" would hang. To replicate this, try:
tee > (gcc test.c -o a.out.1) >(gcc test.c -o a.out.2)
in a tty (here, the stdin is meant to be irrelevant).
If I may try to provide a simple example of the problem, consider the
following command line:
tee > (sleep 3) | sleep 5
Let tee's stdin be a terminal to supply the "intermittent input".
You'll see that after 5 seconds, this will hang indefinitely until you hit
Enter.
For the first 3 seconds, when hitting the Enter key, tee will successfully
write the line to each pipe. Between 3 and 5 seconds, the pipe to "sleep 3"
will be broken, which tee will notice, and then tee will continue writing the
lines to the "sleep 5" pipe.
But after 5 seconds, when "sleep 5" has terminated and that pipe becomes
broken, tee will continue to "hang" waiting for input (in this case the
intermittent input from the terminal) indefinitely, despite the fact that all
of tee's outputs are now broken pipes. tee will only "notice" that the
"sleep 5" pipe is broken when it receives input after that point, because
then the write to that pipe fails with EPIPE (and/or a SIGPIPE is delivered).
...
It seems the ideal thing to happen here is for tee to terminate once it
determines that all of its outputs are broken pipes. It comes close to this
already, but it only learns about this when write attempts fail, and it only
attempts a write when it has input to tee.
As I suppose was suggested in the patch, perhaps poll(2) could be used to
wait for POLLIN from fd 0, and POLLHUP for outputs (perhaps limited to pipes
/ sockets).
The patch subject suggests adding --pipe-check as an option, but on first
blush it seems like this would actually be a good thing to do by default...
Cheers,
Carl