From 8a782f1699e2a59a3f3e91f6d7c35a3312b82b41 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 21 May 2015 09:45:46 -0400 Subject: input: set input stream to blocking on exit If stdin is non-blocking, many tools (e.g. cat(1), read(1)) which assume that stdin is blocking, will break in odd ways: read: read error: 0: Resource temporarily unavailable cat: -: Resource temporarily unavailable rm: error closing file libuv puts stdin in nonblocking mode, and leaves it that way at exit (this is apparently by design). So, before this commit, this always works (because the shell clobbers O_NONBLOCK): $ nvim --cmd q $ read ...but these forms do _not_ work: $ nvim --cmd q && read $ echo foo | nvim --cmd q && read $ nvim && read After this commit, all of the above forms work. Background: https://github.com/fish-shell/fish-shell/commit/437b4397b9cf273922ce7b414bf6626845f15ad0#diff-41f4d294430cd8c36538999d62681ae2 https://github.com/fish-shell/fish-shell/issues/176#issuecomment-15800155 - bash (and other shells: zsh, tcsh, fish), upon returning to the foreground, always sets fd 0 back to blocking mode. This practice only applies to stdin, _not_ stdout or stderr (in practice these fds may be affected anyways). - bash/zsh/tcsh/fish do _not_ restore the non-blocking status of stdin when _resuming a job_. - We do _not_ save/restore the original flags visible to fcntl(F_[SG]ETFL), because (counterintuitively) that isn't expected. Helped-by: oni-link Closes #2086 Closes #2377 --- Note: The following implementation of stream_set_blocking() was discarded, because it resulted in a failed libuv assertion[1]: int stream_set_blocking(int fd, bool blocking) { uv_pipe_t stream; uv_pipe_init(uv_default_loop(), &stream, 0); uv_pipe_open(&stream, fd); int retval = uv_stream_set_blocking((uv_stream_t *)&stream, blocking); uv_close((uv_handle_t *)&stream, NULL); return retval; } [1] .deps/build/src/libuv/src/unix/core.c:833: uv__io_stop: Assertion `loop->watchers[w->fd] == w' failed. --- src/nvim/os/input.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nvim/os/input.c') diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 486171b48a..5dcaee8304 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -8,6 +8,7 @@ #include "nvim/api/private/defs.h" #include "nvim/os/input.h" #include "nvim/os/event.h" +#include "nvim/os/os.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/rstream.h" #include "nvim/ascii.h" @@ -61,9 +62,14 @@ void input_start_stdin(int fd) void input_stop_stdin(void) { if (!read_stream) { + // In some cases (i.e. "nvim && read") where we do not explicitly play with + // std{in,out,err}, some other module/library nevertheless sets the stream + // to non-blocking; we still must "fix" the stream (#2598) in those cases. + stream_set_blocking(global_input_fd, true); // normalize stream (#2598) return; } + rstream_set_blocking(read_stream, true); // normalize stream (#2598) rstream_stop(read_stream); rstream_free(read_stream); read_stream = NULL; -- cgit