aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
authorMatthias Dahl2018-02-16 17:57:40 +0200
committerEli Zaretskii2018-02-16 17:57:40 +0200
commit4ba32858d61eee16f17b51aca01c15211a0912f8 (patch)
treea775831b32002629415087e663698c2b32decbee /src/process.c
parent49fc040077b33bd1e78ee425575e76329b772a41 (diff)
downloademacs-4ba32858d61eee16f17b51aca01c15211a0912f8.tar.gz
emacs-4ba32858d61eee16f17b51aca01c15211a0912f8.zip
Fix wait_reading_process_output wait_proc hang
* src/process.c (read_process_output): Track bytes read from a process. (wait_reading_process_output): If called recursively through timers and/or process filters via 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 set. Fix that by using the process read accounting to keep track of how many bytes have been read and use that as a condition to break out of the infinite loop and return to the caller as well as to calculate the proper return value (if a wait_proc is given that is). * src/process.h (struct Lisp_Process): Add nbytes_read to track bytes read from a process.
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/process.c b/src/process.c
index 2ec10b12ecc..496b1f2b70c 100644
--- a/src/process.c
+++ b/src/process.c
@@ -5006,6 +5006,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5006 struct timespec got_output_end_time = invalid_timespec (); 5006 struct timespec got_output_end_time = invalid_timespec ();
5007 enum { MINIMUM = -1, TIMEOUT, INFINITY } wait; 5007 enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
5008 int got_some_output = -1; 5008 int got_some_output = -1;
5009 uintmax_t prev_wait_proc_nbytes_read = wait_proc ? wait_proc->nbytes_read : 0;
5009#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS 5010#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
5010 bool retry_for_async; 5011 bool retry_for_async;
5011#endif 5012#endif
@@ -5460,6 +5461,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5460 if (nfds == 0) 5461 if (nfds == 0)
5461 { 5462 {
5462 /* Exit the main loop if we've passed the requested timeout, 5463 /* Exit the main loop if we've passed the requested timeout,
5464 or have read some bytes from our wait_proc (either directly
5465 in this call or indirectly through timers / process filters),
5463 or aren't skipping processes and got some output and 5466 or aren't skipping processes and got some output and
5464 haven't lowered our timeout due to timers or SIGIO and 5467 haven't lowered our timeout due to timers or SIGIO and
5465 have waited a long amount of time due to repeated 5468 have waited a long amount of time due to repeated
@@ -5467,7 +5470,9 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5467 struct timespec huge_timespec 5470 struct timespec huge_timespec
5468 = make_timespec (TYPE_MAXIMUM (time_t), 2 * TIMESPEC_RESOLUTION); 5471 = make_timespec (TYPE_MAXIMUM (time_t), 2 * TIMESPEC_RESOLUTION);
5469 struct timespec cmp_time = huge_timespec; 5472 struct timespec cmp_time = huge_timespec;
5470 if (wait < TIMEOUT) 5473 if (wait < TIMEOUT
5474 || (wait_proc
5475 && wait_proc->nbytes_read != prev_wait_proc_nbytes_read))
5471 break; 5476 break;
5472 if (wait == TIMEOUT) 5477 if (wait == TIMEOUT)
5473 cmp_time = end_time; 5478 cmp_time = end_time;
@@ -5772,6 +5777,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5772 maybe_quit (); 5777 maybe_quit ();
5773 } 5778 }
5774 5779
5780 /* Timers and/or process filters that we have run could have themselves called
5781 `accept-process-output' (and by that indirectly this function), thus
5782 possibly reading some (or all) output of wait_proc without us noticing it.
5783 This could potentially lead to an endless wait (dealt with earlier in the
5784 function) and/or a wrong return value (dealt with here). */
5785 if (wait_proc && wait_proc->nbytes_read != prev_wait_proc_nbytes_read)
5786 got_some_output = min (INT_MAX, (wait_proc->nbytes_read
5787 - prev_wait_proc_nbytes_read));
5788
5775 return got_some_output; 5789 return got_some_output;
5776} 5790}
5777 5791
@@ -5890,6 +5904,9 @@ read_process_output (Lisp_Object proc, int channel)
5890 coding->mode |= CODING_MODE_LAST_BLOCK; 5904 coding->mode |= CODING_MODE_LAST_BLOCK;
5891 } 5905 }
5892 5906
5907 /* Ignore carryover, it's been added by a previous iteration already. */
5908 p->nbytes_read += nbytes;
5909
5893 /* Now set NBYTES how many bytes we must decode. */ 5910 /* Now set NBYTES how many bytes we must decode. */
5894 nbytes += carryover; 5911 nbytes += carryover;
5895 5912