From 57e9adc220312681588180aff2bae1eb07925ad5 Mon Sep 17 00:00:00 2001 From: Matthias Dahl Date: Tue, 24 Oct 2017 15:56:47 +0200 Subject: [PATCH 2/2] * src/process.c (wait_reading_process_output): Fix wait_proc hang. If called recursively (through timers or process filters by the means of accept-process-output), it is possible that the output of wait_proc has already been read by one of those recursive calls, leaving the original call hanging forever if no further output arrives through that fd and no timeout has been specified. Implement proper checks by taking advantage of the process output read accounting. --- src/process.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/process.c b/src/process.c index 904ca60863..a743aa973e 100644 --- a/src/process.c +++ b/src/process.c @@ -5003,6 +5003,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, struct timespec got_output_end_time = invalid_timespec (); enum { MINIMUM = -1, TIMEOUT, INFINITY } wait; int got_some_output = -1; + unsigned long initial_wait_proc_num_bytes_read = (wait_proc) ? + wait_proc->infd_num_bytes_read : 0; #if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS bool retry_for_async; #endif @@ -5161,6 +5163,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, && requeued_events_pending_p ()) break; + /* Timers could have called `accept-process-output', thus reading the output + of wait_proc while we (in the worst case) wait endlessly for it to become + available later. So we need to check if data has been read and break out + early if that is so since our job has been fulfilled. */ + if (wait_proc + && wait_proc->infd_num_bytes_read != initial_wait_proc_num_bytes_read) + { + got_some_output = 1; + break; + } + /* This is so a breakpoint can be put here. */ if (!timespec_valid_p (timer_delay)) wait_reading_process_output_1 (); @@ -5606,7 +5619,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, buffered-ahead character if we have one. */ nread = read_process_output (proc, channel); - if ((!wait_proc || wait_proc == XPROCESS (proc)) + + /* In case a filter was run that called `accept-process-output', it is + possible that the output from wait_proc was already read, leaving us + waiting for it endlessly (if no timeout was specified). Thus, we need + to check if data was already read. */ + if (wait_proc + && wait_proc->infd_num_bytes_read != initial_wait_proc_num_bytes_read) + got_some_output = 1; + else if ((!wait_proc || wait_proc == XPROCESS (proc)) && got_some_output < nread) got_some_output = nread; if (nread > 0) -- 2.14.3