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:
parent
1f6898d051
commit
58a622d473
4 changed files with 56 additions and 10 deletions
|
@ -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
|
||||
|
|
6
etc/NEWS
6
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.
|
||||
|
|
39
src/w32.c
39
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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue