From: Eli Zaretskii Date: Tue, 12 Jan 2016 16:41:58 +0000 (+0200) Subject: Make piping to subprocesses more robust on MS-Windows X-Git-Tag: emacs-25.0.90~197 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=58a622d473112f8ff5b4bdb3e49bc6573dfd3404;p=emacs.git 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) : 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'. --- diff --git a/doc/emacs/msdos.texi b/doc/emacs/msdos.texi index ea8a24d1cf7..6ad12d646a1 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 non-@code{nil}, the roles of these two buttons are reversed. @node Windows Processes -@section Subprocesses on Windows 9X/ME and Windows NT/2K/XP +@section 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 non-@code{nil}, 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. +@vindex 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 85ec30ac033..10fcb7e3fd4 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 4770718f5e3..ea3a9dafad5 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 a65f085fb3d..a89a9850466 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.