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'.
This commit is contained in:
Eli Zaretskii 2016-01-12 18:41:58 +02:00
parent 1f6898d051
commit 58a622d473
4 changed files with 56 additions and 10 deletions

View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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.