emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 4ba3285: Fix wait_reading_process_output wait_proc


From: Eli Zaretskii
Subject: [Emacs-diffs] master 4ba3285: Fix wait_reading_process_output wait_proc hang
Date: Fri, 16 Feb 2018 10:59:58 -0500 (EST)

branch: master
commit 4ba32858d61eee16f17b51aca01c15211a0912f8
Author: Matthias Dahl <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    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.
---
 src/process.c | 19 ++++++++++++++++++-
 src/process.h |  2 ++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/process.c b/src/process.c
index 2ec10b1..496b1f2 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,
   struct timespec got_output_end_time = invalid_timespec ();
   enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
   int got_some_output = -1;
+  uintmax_t prev_wait_proc_nbytes_read = wait_proc ? wait_proc->nbytes_read : 
0;
 #if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
   bool retry_for_async;
 #endif
@@ -5460,6 +5461,8 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
       if (nfds == 0)
        {
           /* Exit the main loop if we've passed the requested timeout,
+             or have read some bytes from our wait_proc (either directly
+             in this call or indirectly through timers / process filters),
              or aren't skipping processes and got some output and
              haven't lowered our timeout due to timers or SIGIO and
              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,
          struct timespec huge_timespec
            = make_timespec (TYPE_MAXIMUM (time_t), 2 * TIMESPEC_RESOLUTION);
          struct timespec cmp_time = huge_timespec;
-         if (wait < TIMEOUT)
+         if (wait < TIMEOUT
+              || (wait_proc
+                  && wait_proc->nbytes_read != prev_wait_proc_nbytes_read))
            break;
          if (wait == TIMEOUT)
            cmp_time = end_time;
@@ -5772,6 +5777,15 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
       maybe_quit ();
     }
 
+  /* Timers and/or process filters that we have run could have themselves 
called
+     `accept-process-output' (and by that indirectly this function), thus
+     possibly reading some (or all) output of wait_proc without us noticing it.
+     This could potentially lead to an endless wait (dealt with earlier in the
+     function) and/or a wrong return value (dealt with here).  */
+  if (wait_proc && wait_proc->nbytes_read != prev_wait_proc_nbytes_read)
+    got_some_output = min (INT_MAX, (wait_proc->nbytes_read
+                                     - prev_wait_proc_nbytes_read));
+
   return got_some_output;
 }
 
@@ -5890,6 +5904,9 @@ read_process_output (Lisp_Object proc, int channel)
       coding->mode |= CODING_MODE_LAST_BLOCK;
     }
 
+  /* Ignore carryover, it's been added by a previous iteration already.  */
+  p->nbytes_read += nbytes;
+
   /* Now set NBYTES how many bytes we must decode.  */
   nbytes += carryover;
 
diff --git a/src/process.h b/src/process.h
index ab468b1..6464a8c 100644
--- a/src/process.h
+++ b/src/process.h
@@ -129,6 +129,8 @@ struct Lisp_Process
     pid_t pid;
     /* Descriptor by which we read from this process.  */
     int infd;
+    /* Byte-count modulo (UINTMAX_MAX + 1) for process output read from 
`infd'.  */
+    uintmax_t nbytes_read;
     /* Descriptor by which we write to this process.  */
     int outfd;
     /* Descriptors that were created for this process and that need



reply via email to

[Prev in Thread] Current Thread [Next in Thread]