diff options
author | Matt Widmann <mw@mattwidmann.net> | 2017-11-25 13:59:07 -0800 |
---|---|---|
committer | Matt Widmann <mw@mattwidmann.net> | 2017-11-25 13:59:07 -0800 |
commit | 0f9c90e0edd27d2db04d48e7bd98bb46d2c4a918 (patch) | |
tree | c4c750d6464fa203f5cee03155a51f2d4f406cad /src/nvim/if_cscope.c | |
parent | d9b3ebfede6439aab4148c4bbf117b8950ed6aa0 (diff) | |
download | rneovim-0f9c90e0edd27d2db04d48e7bd98bb46d2c4a918.tar.gz rneovim-0f9c90e0edd27d2db04d48e7bd98bb46d2c4a918.tar.bz2 rneovim-0f9c90e0edd27d2db04d48e7bd98bb46d2c4a918.zip |
io: retry fgets on EINTR (#7632)
The calls to `fgets` in `src/nvim/if_cscope.c` (and elsewhere) can show
communication errors to the user if a signal is delivered during its
system calls. For plugins that proxy subprocess output into cscope
requests, a `SIGCHLD` might *always* interfere with calls into `fgets`.
To see this in a debugger, put a breakpoint on `cs_reading_emsg` and
watch signals come in (with lldb, using `process handle --notify true
--pass true`). Next, run a subcommand from neovim that calls through
cscope when it returns. A tag picker plugin, like vim-picker and fzy,
with `cscopetag` and `cscopetagorder=0` set, reproduced this reliably.
The breakpoint will hit after a `SIGCHLD` is delivered, and `errno` will
be set to 4, `EINTR`.
The caller of `fgets` should retry when `NULL` is returned with `errno`
set to `EINTR`.
Diffstat (limited to 'src/nvim/if_cscope.c')
-rw-r--r-- | src/nvim/if_cscope.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 0f9ecdf2d7..21e4b84074 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -553,9 +553,15 @@ static int cs_cnt_matches(size_t idx) char *buf = xmalloc(CSREAD_BUFSIZE); for (;; ) { + errno = 0; if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) { - if (feof(csinfo[idx].fr_fp)) + if (errno == EINTR) { + continue; + } + + if (feof(csinfo[idx].fr_fp)) { errno = EIO; + } cs_reading_emsg(idx); @@ -1381,9 +1387,16 @@ static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, char *p; char *name; +retry: + errno = 0; if (fgets(buf, bufsize, csinfo[cnumber].fr_fp) == NULL) { - if (feof(csinfo[cnumber].fr_fp)) + if (errno == EINTR) { + goto retry; + } + + if (feof(csinfo[cnumber].fr_fp)) { errno = EIO; + } cs_reading_emsg(cnumber); |