emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] emacs-25 58a622d: Make piping to subprocesses more robust


From: Eli Zaretskii
Subject: [Emacs-diffs] emacs-25 58a622d: Make piping to subprocesses more robust on MS-Windows
Date: Tue, 12 Jan 2016 16:42:51 +0000

branch: emacs-25
commit 58a622d473112f8ff5b4bdb3e49bc6573dfd3404
Author: Eli Zaretskii <address@hidden>
Commit: Eli Zaretskii <address@hidden>

    Make piping to subprocesses more robust on MS-Windows
    
    * src/w32.c (sys_write): Don't write to a pipe more stuff than its
    buffer can hold.  Don't return -1 if something has been written to
    the pipe.  Zero out 'errno' before calling '_write', to avoid
    returning a stale value.  (Bug#22344)
    * src/w32proc.c (syms_of_ntproc) <w32-pipe-buffer-size>: New variable.
    * src/w32.c (pipe2): Use it to request a user-defined size for the
    pipe being created.
    
    * etc/NEWS: Mention 'w32-pipe-buffer-size'.
    
    * doc/emacs/msdos.texi (Windows Processes): Document
    'w32-pipe-buffer-size'.
---
 doc/emacs/msdos.texi |   14 ++++++++++++--
 etc/NEWS             |    6 ++++++
 src/w32.c            |   39 +++++++++++++++++++++++++++++++--------
 src/w32proc.c        |    7 +++++++
 4 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/doc/emacs/msdos.texi b/doc/emacs/msdos.texi
index ea8a24d..6ad12d6 100644
--- a/doc/emacs/msdos.texi
+++ b/doc/emacs/msdos.texi
@@ -655,7 +655,7 @@ and the right button generates @kbd{mouse-3} events.  If 
this variable
 is address@hidden, the roles of these two buttons are reversed.
 
 @node Windows Processes
address@hidden Subprocesses on Windows 9X/ME and Windows NT/2K/XP
address@hidden Subprocesses on Windows 9X/ME and Windows NT/2K/XP/Vista/7/8/10
 @cindex subprocesses on MS-Windows
 
 @cindex DOS applications, running from Emacs
@@ -663,7 +663,8 @@ is address@hidden, the roles of these two buttons are 
reversed.
 version) includes full support for asynchronous subprocesses.
 In the Windows version, synchronous and asynchronous subprocesses work
 fine on both
-Windows 9X/ME and Windows NT/2K/XP as long as you run only 32-bit Windows
+Windows 9X/ME and Windows NT/2K/XP/Vista/7/8/10 as long as you run
+only 32-bit or 64-bit Windows
 applications.  However, when you run a DOS application in a subprocess,
 you may encounter problems or be unable to run the application at all;
 and if you run two DOS applications at the same time in two
@@ -713,6 +714,15 @@ character.  If the value is a character, Emacs uses that 
character to escape
 any quote characters that appear; otherwise it chooses a suitable escape
 character based on the type of the program.
 
address@hidden w32-pipe-buffer-size
+  The variable @code{w32-pipe-buffer-size} controls the size of the
+buffer Emacs requests from the system when it creates pipes for
+communications with subprocesses.  The default value is zero, which
+lets the OS choose the size.  Any valid positive value will request a
+buffer of that size in bytes.  This can be used to tailor
+communications with subprocesses to programs that exhibit unusual
+behavior with respect to buffering pipe I/O.
+
 @ifnottex
 @findex w32-shell-execute
   The function @code{w32-shell-execute} can be useful for writing
diff --git a/etc/NEWS b/etc/NEWS
index 85ec30a..10fcb7e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1762,6 +1762,12 @@ this has no effect.
 ** The new function 'w32-application-type' returns the type of an
 MS-Windows application given the name of its executable program file.
 
+** New variable `w32-pipe-buffer-size'.
+It can be used to tune the size of the buffer of pipes created for
+communicating with subprocesses, when the program run by a subprocess
+exhibits unusual buffering behavior.  Default is zero, which lets the
+OS use its default size.
+
 
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/src/w32.c b/src/w32.c
index 4770718..ea3a9da 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -8043,14 +8043,19 @@ pipe2 (int * phandles, int pipe2_flags)
 {
   int rc;
   unsigned flags;
+  unsigned pipe_size = 0;
 
   eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
 
+  /* Allow Lisp to override the default buffer size of the pipe.  */
+  if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
+    pipe_size = w32_pipe_buffer_size;
+
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
      pipes into binary mode; we will do text mode translation ourselves
      if required.  */
-  rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
+  rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
 
   if (rc == 0)
     {
@@ -8632,15 +8637,35 @@ sys_write (int fd, const void * buffer, unsigned int 
count)
         http://thread.gmane.org/gmane.comp.version-control.git/145294
         in the git mailing list.  */
       const unsigned char *p = buffer;
-      const unsigned chunk = 30 * 1024 * 1024;
+      const bool is_pipe = (fd < MAXDESC
+                           && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
+                               == (FILE_PIPE | FILE_NDELAY)));
+      /* Some programs, notably Node.js's node.exe, seem to never
+        completely empty the pipe, so writing more than the size of
+        the pipe's buffer always returns ENOSPC, and we loop forever
+        between send_process and here.  As a workaround, write no
+        more than the pipe's buffer can hold.  */
+      DWORD pipe_buffer_size;
+      if (is_pipe)
+       {
+         if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
+                               NULL, &pipe_buffer_size, NULL, NULL))
+           {
+             DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
+             pipe_buffer_size = 4096;
+           }
+       }
+      const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
 
       nchars = 0;
+      errno = 0;
       while (count > 0)
        {
          unsigned this_chunk = count < chunk ? count : chunk;
          int n = _write (fd, p, this_chunk);
 
-         nchars += n;
+         if (n > 0)
+           nchars += n;
          if (n < 0)
            {
              /* When there's no buffer space in a pipe that is in the
@@ -8654,12 +8679,10 @@ sys_write (int fd, const void * buffer, unsigned int 
count)
                 avoiding deadlock whereby each side of the pipe is
                 blocked on write, waiting for the other party to read
                 its end of the pipe.  */
-             if (errno == ENOSPC
-                 && fd < MAXDESC
-                 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
-                     == (FILE_PIPE | FILE_NDELAY)))
+             if (errno == ENOSPC && is_pipe)
                errno = EAGAIN;
-             nchars = n;
+             if (nchars == 0)
+               nchars = -1;
              break;
            }
          else if (n < this_chunk)
diff --git a/src/w32proc.c b/src/w32proc.c
index a65f085..a89a985 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -3702,6 +3702,13 @@ of time slices to wait (effectively boosting the 
priority of the child
 process temporarily).  A value of zero disables waiting entirely.  */);
   w32_pipe_read_delay = 50;
 
+  DEFVAR_INT ("w32-pipe-buffer-size", w32_pipe_buffer_size,
+             doc: /* Size of buffer for pipes created to communicate with 
subprocesses.
+The size is in bytes, and must be non-negative.  The default is zero,
+which lets the OS use its default size, usually 4KB (4096 bytes).
+Any negative value means to use the default value of zero.  */);
+  w32_pipe_buffer_size = 0;
+
   DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names,
               doc: /* Non-nil means convert all-upper case file names to lower 
case.
 This applies when performing completions and file name expansion.



reply via email to

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