stdin/stdout: Only set nonblock flags for non-tty fds.
authorAndre Noll <>
Sun, 30 Jul 2017 21:11:38 +0000 (23:11 +0200)
committerAndre Noll <>
Sat, 5 Aug 2017 12:46:31 +0000 (14:46 +0200)
Although the ->post_select methods of all paraslash executables perform
I/O only when select(2) reports that the file descriptor is ready,
we set the O_NONBLOCK flag for all monitored fds. This is considered
good practice because, in general, it might happen that a subsequent
read(2) call blocks even if select(2) indicates that the fd is ready
for reading. For example, an fd corresponding to a TCP socket might
be flagged as ready for reading if a network packet with incorrect
checksum has arrived, but a subsequent read(2) blocks until the packet
has been retransmitted.

However, stdin and stdout often correspond to a terminal device where
the above scenario won't happen. Moreover, for terminals it's essential
to reset the O_NONBLOCK flag to the old value on exit because the
shell refers to the same file description and thus shares the file
status flags, including O_NONBLOCK. Many terminal applications, for
example dialog(1), expect stdout to be set to blocking mode and fail
in arcane ways if O_NONBLOCK is set.

When the stdin and stdout tasks are about to exit, they reset the
file status flags back to the original values. However if "para_client
stat" is killed with SIGINT, SIGTERM or SIGKILL, or put to sleep with
SIGSTOP, the O_NONBLOCK flag remains set because para_client does not
handle signals at all. para_recv, para_filter and para_write suffer
from the same issue. Adding signal handling to these programs would
not help in the SIGSTOP case because this signal can not be caught.

This patch modifies stdin.c and stdout.c to no longer set O_NONBLOCK
for fd 0 and fd 1 if these fds are associated with a terminal
device. This is much easier and should do the job as well.


diff --git a/stdin.c b/stdin.c
index e5c40bc..7b70690 100644 (file)
--- a/stdin.c
+++ b/stdin.c
@@ -114,6 +114,7 @@ void stdin_task_register(struct stdin_task *sit, struct sched *s)
        sit->fd_flags = ret;
-       sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0;
+       sit->must_set_nonblock_flag = (sit->fd_flags & O_NONBLOCK) == 0
+               && !isatty(STDIN_FILENO);
        sit->task = task_register(&ti, s);
index 29db2b7..b266615 100644 (file)
--- a/stdout.c
+++ b/stdout.c
@@ -96,6 +96,7 @@ void stdout_task_register(struct stdout_task *sot, struct sched *s)
        sot->fd_flags = ret;
-       sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0;
+       sot->must_set_nonblock_flag = (sot->fd_flags & O_NONBLOCK) == 0
+               && !isatty(STDOUT_FILENO);
        sot->task = task_register(&ti, s);