aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoroni-link <knil.ino@gmail.com>2016-05-14 02:36:04 +0200
committeroni-link <knil.ino@gmail.com>2016-05-15 02:54:09 +0200
commit14ea366f249ab5966019bfd399f8be5547c45569 (patch)
treee41f6db916599bf48a7d758ece9f6261ff904d02
parent1c83e9eb82ec150a3a3c201e8566ea383589b775 (diff)
downloadrneovim-14ea366f249ab5966019bfd399f8be5547c45569.tar.gz
rneovim-14ea366f249ab5966019bfd399f8be5547c45569.tar.bz2
rneovim-14ea366f249ab5966019bfd399f8be5547c45569.zip
fixup: process.c: Prevent data loss for process output streams
* Get system buffer size for upper data limit. Otherwise data loss if this buffer is too big. * Test whether teardown needs special handling.
-rw-r--r--src/nvim/event/process.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 2e6511a167..23a60c3052 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -344,21 +344,36 @@ static void flush_stream(Process *proc, Stream *stream)
return;
}
- // Limit amount of data we accept after process terminated.
- size_t max_bytes = stream->num_bytes + rbuffer_capacity(stream->buffer);
+ // Maximal remaining data size of terminated process is system
+ // buffer size.
+ // Also helps with a child process that keeps the output streams open. If it
+ // keeps sending data, we only accept as much data as the system buffer size.
+ // Otherwise this would block cleanup/teardown.
+ int system_buffer_size = 0;
+ int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe,
+ &system_buffer_size);
+ if (err) {
+ system_buffer_size = (int)rbuffer_capacity(stream->buffer);
+ }
+
+ size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size;
+ // Read remaining data.
while (!stream->closed && stream->num_bytes < max_bytes) {
// Remember number of bytes before polling
size_t num_bytes = stream->num_bytes;
// Poll for data and process the generated events.
loop_poll_events(&loop, 0);
- if (proc->events && !queue_empty(proc->events)) {
- queue_process_events(proc->events);
- }
+ queue_process_events(proc->events);
// Stream can be closed if it is empty.
if (num_bytes == stream->num_bytes) {
+ if (stream->read_cb) {
+ // Stream callback could miss EOF handling if a child keeps the stream
+ // open.
+ stream->read_cb(stream, stream->buffer, 0, stream->data, true);
+ }
break;
}
}
@@ -368,11 +383,8 @@ static void process_close_handles(void **argv)
{
Process *proc = argv[0];
- // Did our process forked a child that keeps the output streams open?
- if (!process_is_tearing_down) {
- flush_stream(proc, proc->out);
- flush_stream(proc, proc->err);
- }
+ flush_stream(proc, proc->out);
+ flush_stream(proc, proc->err);
process_close_streams(proc);
process_close(proc);