diff options
author | Pádraig Brady <P@draigBrady.com> | 2023-03-05 15:51:32 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2023-03-08 18:32:05 +0000 |
commit | 16000805eb1bcdf25360471b8bbc8ec3f025e035 (patch) | |
tree | 62f3c3de4d34462cac20967433b827bc4cf9cb1e /tests | |
parent | 176b74f0e7360d94450c5aa3cf7db2ab86ed28c8 (diff) | |
download | coreutils-16000805eb1bcdf25360471b8bbc8ec3f025e035.tar.gz |
tee: support non blocking outputs
Non blocking outputs can be seen for example
when piping telnet through tee to a terminal.
In that case telnet sets its input to nonblocking mode,
which results in tee's output being nonblocking,
in which case in may receive an EAGAIN error upon write().
The same issue was seen with mpirun.
The following can be used to reproduce this
locally at a terminal (in most invocations):
$ { dd iflag=nonblock count=0 status=none;
dd bs=10K count=10 if=/dev/zero status=none; } |
tee || echo fail >/dev/tty
* src/iopoll.c (iopoll_internal): A new function refactored from
iopoll(), to also support a mode where we check the output
descriptor is writeable.
(iopoll): Now refactored to just call iopoll_internal().
(fwait_for_nonblocking_write): A new internal function which
uses iopoll_internal() to wait for writeable output
if an EAGAIN or EWOULDBLOCK was received.
(fwrite_nonblock): An fwrite() wrapper which uses
fwait_for_nonblocking_write() to handle EAGAIN.
(fclose_nonblock): Likewise.
src/iopoll.h: Add fclose_nonblock, fwrite_nonblock.
src/tee.c: Call fclose_nonblock() and fwrite_nonblock wrappers,
instead of the standard functions.
* tests/misc/tee.sh: Add a test case.
* NEWS: Mention the improvement.
The idea was suggested by Kamil Dudka in
https://bugzilla.redhat.com/1615467
Diffstat (limited to 'tests')
-rwxr-xr-x | tests/misc/tee.sh | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/tests/misc/tee.sh b/tests/misc/tee.sh index 63e7524c0..ce0cfd41d 100755 --- a/tests/misc/tee.sh +++ b/tests/misc/tee.sh @@ -79,8 +79,23 @@ touch file.ro || framework_failure_ chmod a-w file.ro || framework_failure_ returns_ 1 tee -p </dev/null file.ro || fail=1 -# Ensure tee honors --output-error modes mkfifo_or_skip_ fifo + +# Ensure tee handles nonblocking output correctly +# Terminate any background processes +cleanup_() { kill $pid 2>/dev/null && wait $pid; } +read_fifo_delayed() { + { sleep .1; timeout 10 dd of=/dev/null status=none; } <fifo +} +read_fifo_delayed & pid=$! +dd count=20 bs=100K if=/dev/zero status=none | +{ + dd count=0 oflag=nonblock status=none + tee || { cleanup_; touch tee.fail; } +} >fifo +test -f tee.fail && fail=1 + +# Ensure tee honors --output-error modes read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & } # Determine platform sigpipe exit status |