Skip to content

Commit 2405838

Browse files
committed
patch 8.1.0818: MS-Windows: cannot send large data with ch_sendraw()
Problem: MS-Windows: cannot send large data with ch_sendraw(). Solution: Split write into several WriteFile() calls. (Yasuhiro Matsumoto, closes #3823)
1 parent 99531a7 commit 2405838

6 files changed

Lines changed: 51 additions & 13 deletions

File tree

src/channel.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,24 +80,34 @@ fd_read(sock_T fd, char *buf, size_t len)
8080
static int
8181
fd_write(sock_T fd, char *buf, size_t len)
8282
{
83+
size_t todo = len;
8384
HANDLE h = (HANDLE)fd;
84-
DWORD nwrite;
85+
DWORD nwrite, size, done = 0;
8586
OVERLAPPED ov;
8687

87-
// If the pipe overflows while the job does not read the data, WriteFile
88-
// will block forever. This abandons the write.
89-
memset(&ov, 0, sizeof(ov));
90-
if (!WriteFile(h, buf, (DWORD)len, &nwrite, &ov))
88+
while (todo > 0)
9189
{
92-
DWORD err = GetLastError();
90+
if (todo > MAX_NAMED_PIPE_SIZE)
91+
size = MAX_NAMED_PIPE_SIZE;
92+
else
93+
size = todo;
94+
// If the pipe overflows while the job does not read the data, WriteFile
95+
// will block forever. This abandons the write.
96+
memset(&ov, 0, sizeof(ov));
97+
if (!WriteFile(h, buf + done, size, &nwrite, &ov))
98+
{
99+
DWORD err = GetLastError();
93100

94-
if (err != ERROR_IO_PENDING)
95-
return -1;
96-
if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
97-
return -1;
98-
FlushFileBuffers(h);
101+
if (err != ERROR_IO_PENDING)
102+
return -1;
103+
if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
104+
return -1;
105+
FlushFileBuffers(h);
106+
}
107+
todo -= nwrite;
108+
done += nwrite;
99109
}
100-
return (int)nwrite;
110+
return (int)done;
101111
}
102112

103113
static void

src/os_win32.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5369,7 +5369,7 @@ create_pipe_pair(HANDLE handles[2])
53695369
name,
53705370
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
53715371
PIPE_TYPE_BYTE | PIPE_NOWAIT,
5372-
1, 65535, 0, 0, NULL);
5372+
1, MAX_NAMED_PIPE_SIZE, 0, 0, NULL);
53735373

53745374
if (handles[1] == INVALID_HANDLE_VALUE)
53755375
return FALSE;

src/testdir/test_channel.vim

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,3 +1980,21 @@ func Test_job_start_in_timer()
19801980
unlet! g:val
19811981
unlet! g:job
19821982
endfunc
1983+
1984+
func Test_raw_large_data()
1985+
try
1986+
let g:out = ''
1987+
let job = job_start(s:python . " test_channel_pipe.py",
1988+
\ {'mode': 'raw', 'drop': 'never', 'noblock': 1,
1989+
\ 'callback': {ch, msg -> execute('let g:out .= msg')}})
1990+
1991+
let want = repeat('X', 79999) . "\n"
1992+
call ch_sendraw(job, want)
1993+
let g:Ch_job = job
1994+
call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
1995+
call assert_equal(want, substitute(g:out, '\r', '', 'g'))
1996+
finally
1997+
call job_stop(job)
1998+
unlet g:out
1999+
endtry
2000+
endfunc

src/testdir/test_channel_pipe.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,8 @@
5656
if typed.startswith("doubleerr "):
5757
print(typed[10:-1] + "\nAND " + typed[10:-1], file=sys.stderr)
5858
sys.stderr.flush()
59+
if typed.startswith("XXX"):
60+
print(typed, end='')
61+
sys.stderr.flush()
62+
break
5963

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,8 @@ static char *(features[]) =
787787

788788
static int included_patches[] =
789789
{ /* Add new patch number below this line */
790+
/**/
791+
818,
790792
/**/
791793
817,
792794
/**/

src/vim.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,10 @@ typedef enum {
24672467
# define MAX_OPEN_CHANNELS 0
24682468
#endif
24692469

2470+
#if defined(WIN32)
2471+
# define MAX_NAMED_PIPE_SIZE 65535
2472+
#endif
2473+
24702474
/* Options for json_encode() and json_decode. */
24712475
#define JSON_JS 1 /* use JS instead of JSON */
24722476
#define JSON_NO_NONE 2 /* v:none item not allowed */

0 commit comments

Comments
 (0)