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.
This commit is contained in:
oni-link
2016-05-14 02:36:04 +02:00
parent 1c83e9eb82
commit 14ea366f24

View File

@@ -344,21 +344,36 @@ static void flush_stream(Process *proc, Stream *stream)
return; return;
} }
// Limit amount of data we accept after process terminated. // Maximal remaining data size of terminated process is system
size_t max_bytes = stream->num_bytes + rbuffer_capacity(stream->buffer); // 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) { while (!stream->closed && stream->num_bytes < max_bytes) {
// Remember number of bytes before polling // Remember number of bytes before polling
size_t num_bytes = stream->num_bytes; size_t num_bytes = stream->num_bytes;
// Poll for data and process the generated events. // Poll for data and process the generated events.
loop_poll_events(&loop, 0); 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. // Stream can be closed if it is empty.
if (num_bytes == stream->num_bytes) { 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; break;
} }
} }
@@ -368,11 +383,8 @@ static void process_close_handles(void **argv)
{ {
Process *proc = argv[0]; Process *proc = argv[0];
// Did our process forked a child that keeps the output streams open? flush_stream(proc, proc->out);
if (!process_is_tearing_down) { flush_stream(proc, proc->err);
flush_stream(proc, proc->out);
flush_stream(proc, proc->err);
}
process_close_streams(proc); process_close_streams(proc);
process_close(proc); process_close(proc);