Commit 58a622d4 authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

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'.
parent 1f6898d0
...@@ -655,7 +655,7 @@ and the right button generates @kbd{mouse-3} events. If this variable ...@@ -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. is non-@code{nil}, the roles of these two buttons are reversed.
@node Windows Processes @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 subprocesses on MS-Windows
@cindex DOS applications, running from Emacs @cindex DOS applications, running from Emacs
...@@ -663,7 +663,8 @@ is non-@code{nil}, the roles of these two buttons are reversed. ...@@ -663,7 +663,8 @@ is non-@code{nil}, the roles of these two buttons are reversed.
version) includes full support for asynchronous subprocesses. version) includes full support for asynchronous subprocesses.
In the Windows version, synchronous and asynchronous subprocesses work In the Windows version, synchronous and asynchronous subprocesses work
fine on both 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, applications. However, when you run a DOS application in a subprocess,
you may encounter problems or be unable to run the application at all; 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 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 ...@@ -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 any quote characters that appear; otherwise it chooses a suitable escape
character based on the type of the program. 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 @ifnottex
@findex w32-shell-execute @findex w32-shell-execute
The function @code{w32-shell-execute} can be useful for writing The function @code{w32-shell-execute} can be useful for writing
......
...@@ -1762,6 +1762,12 @@ this has no effect. ...@@ -1762,6 +1762,12 @@ this has no effect.
** The new function 'w32-application-type' returns the type of an ** The new function 'w32-application-type' returns the type of an
MS-Windows application given the name of its executable program file. 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. This file is part of GNU Emacs.
......
...@@ -8043,14 +8043,19 @@ pipe2 (int * phandles, int pipe2_flags) ...@@ -8043,14 +8043,19 @@ pipe2 (int * phandles, int pipe2_flags)
{ {
int rc; int rc;
unsigned flags; unsigned flags;
unsigned pipe_size = 0;
eassert (pipe2_flags == (O_BINARY | O_CLOEXEC)); 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 /* make pipe handles non-inheritable; when we spawn a child, we
replace the relevant handle with an inheritable one. Also put replace the relevant handle with an inheritable one. Also put
pipes into binary mode; we will do text mode translation ourselves pipes into binary mode; we will do text mode translation ourselves
if required. */ if required. */
rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY); rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
if (rc == 0) if (rc == 0)
{ {
...@@ -8632,15 +8637,35 @@ sys_write (int fd, const void * buffer, unsigned int count) ...@@ -8632,15 +8637,35 @@ sys_write (int fd, const void * buffer, unsigned int count)
http://thread.gmane.org/gmane.comp.version-control.git/145294 http://thread.gmane.org/gmane.comp.version-control.git/145294
in the git mailing list. */ in the git mailing list. */
const unsigned char *p = buffer; 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; nchars = 0;
errno = 0;
while (count > 0) while (count > 0)
{ {
unsigned this_chunk = count < chunk ? count : chunk; unsigned this_chunk = count < chunk ? count : chunk;
int n = _write (fd, p, this_chunk); int n = _write (fd, p, this_chunk);
nchars += n; if (n > 0)
nchars += n;
if (n < 0) if (n < 0)
{ {
/* When there's no buffer space in a pipe that is in the /* 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) ...@@ -8654,12 +8679,10 @@ sys_write (int fd, const void * buffer, unsigned int count)
avoiding deadlock whereby each side of the pipe is avoiding deadlock whereby each side of the pipe is
blocked on write, waiting for the other party to read blocked on write, waiting for the other party to read
its end of the pipe. */ its end of the pipe. */
if (errno == ENOSPC if (errno == ENOSPC && is_pipe)
&& fd < MAXDESC
&& ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
== (FILE_PIPE | FILE_NDELAY)))
errno = EAGAIN; errno = EAGAIN;
nchars = n; if (nchars == 0)
nchars = -1;
break; break;
} }
else if (n < this_chunk) else if (n < this_chunk)
......
...@@ -3702,6 +3702,13 @@ of time slices to wait (effectively boosting the priority of the child ...@@ -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. */); process temporarily). A value of zero disables waiting entirely. */);
w32_pipe_read_delay = 50; 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, DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names,
doc: /* Non-nil means convert all-upper case file names to lower case. doc: /* Non-nil means convert all-upper case file names to lower case.
This applies when performing completions and file name expansion. This applies when performing completions and file name expansion.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment