summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-01-19 14:37:00 +0100
committerBram Moolenaar <Bram@vim.org>2019-01-19 14:37:00 +0100
commitb091f30bf38eacb31b9d8c97c82c7e0af9866301 (patch)
tree6bd242d9cad2c17b0ff2144666518faf4bae18b0
parentb2e54b009279754e420c992a5e4ec05b0728d915 (diff)
downloadvim-git-b091f30bf38eacb31b9d8c97c82c7e0af9866301.tar.gz
patch 8.1.0777: Win32: using pipes for channel does not work wellv8.1.0777
Problem: Win32: using pipes for channel does not work well. Solution: Use a larger buffer and handle overlaps. (Yasuhiro Matsumoto, closes #3782)
-rw-r--r--src/channel.c45
-rw-r--r--src/os_win32.c49
-rw-r--r--src/version.c2
3 files changed, 65 insertions, 31 deletions
diff --git a/src/channel.c b/src/channel.c
index 8f0577f9b..f6ffcd67d 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -80,11 +80,23 @@ fd_read(sock_T fd, char *buf, size_t len)
static int
fd_write(sock_T fd, char *buf, size_t len)
{
- HANDLE h = (HANDLE)fd;
- DWORD nwrite;
+ HANDLE h = (HANDLE)fd;
+ DWORD nwrite;
+ OVERLAPPED ov;
- if (!WriteFile(h, buf, (DWORD)len, &nwrite, NULL))
- return -1;
+ // If the pipe overflows while the job does not read the data, WriteFile
+ // will block forever. This abandons the write.
+ memset(&ov, 0, sizeof(ov));
+ if (!WriteFile(h, buf, (DWORD)len, &nwrite, &ov))
+ {
+ DWORD err = GetLastError();
+
+ if (err != ERROR_IO_PENDING)
+ return -1;
+ if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
+ return -1;
+ FlushFileBuffers(h);
+ }
return (int)nwrite;
}
@@ -3168,20 +3180,7 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
if (r && nread > 0)
return CW_READY;
if (r == 0)
- {
- DWORD err = GetLastError();
-
- if (err != ERROR_BAD_PIPE && err != ERROR_BROKEN_PIPE)
- return CW_ERROR;
-
- if (channel->ch_named_pipe)
- {
- DisconnectNamedPipe((HANDLE)fd);
- ConnectNamedPipe((HANDLE)fd, NULL);
- }
- else
- return CW_ERROR;
- }
+ return CW_ERROR;
/* perhaps write some buffer lines */
channel_write_any_lines();
@@ -3812,17 +3811,7 @@ channel_send(
if (part == PART_SOCK)
res = sock_write(fd, (char *)buf, len);
else
- {
res = fd_write(fd, (char *)buf, len);
-#ifdef WIN32
- if (channel->ch_named_pipe && res < 0)
- {
- DisconnectNamedPipe((HANDLE)fd);
- ConnectNamedPipe((HANDLE)fd, NULL);
- }
-#endif
-
- }
if (res < 0 && (errno == EWOULDBLOCK
#ifdef EAGAIN
|| errno == EAGAIN
diff --git a/src/os_win32.c b/src/os_win32.c
index 919e07163..e8c4916a8 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5428,6 +5428,49 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal)
# endif
}
+/*
+ * Create a pair of pipes.
+ * Return TRUE for success, FALSE for failure.
+ */
+ static BOOL
+create_pipe_pair(HANDLE handles[2])
+{
+ static LONG s;
+ char name[64];
+ SECURITY_ATTRIBUTES sa;
+
+ sprintf(name, "\\\\?\\pipe\\vim-%08lx-%08lx",
+ GetCurrentProcessId(),
+ InterlockedIncrement(&s));
+
+ // Create named pipe. Max size of named pipe is 65535.
+ handles[1] = CreateNamedPipe(
+ name,
+ PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_NOWAIT,
+ 1, 65535, 0, 0, NULL);
+
+ if (handles[1] == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ handles[0] = CreateFile(name,
+ FILE_GENERIC_READ,
+ FILE_SHARE_READ, &sa,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (handles[0] == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(handles[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
void
mch_job_start(char *cmd, job_T *job, jobopt_T *options)
{
@@ -5493,9 +5536,9 @@ mch_job_start(char *cmd, job_T *job, jobopt_T *options)
goto failed;
}
}
- else if (!use_null_for_in &&
- (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
- || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)))
+ else if (!use_null_for_in
+ && (!create_pipe_pair(ifd)
+ || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)))
goto failed;
if (use_file_for_out)
diff --git a/src/version.c b/src/version.c
index da4b2b6f3..a83bad6e1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -792,6 +792,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 777,
+/**/
776,
/**/
775,