Skip to content

Commit

Permalink
patch 8.1.0818: MS-Windows: cannot send large data with ch_sendraw()
Browse files Browse the repository at this point in the history
Problem:    MS-Windows: cannot send large data with ch_sendraw().
Solution:   Split write into several WriteFile() calls. (Yasuhiro Matsumoto,
            closes #3823)
  • Loading branch information
brammool committed Jan 24, 2019
1 parent 99531a7 commit 2405838
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 13 deletions.
34 changes: 22 additions & 12 deletions src/channel.c
Expand Up @@ -80,24 +80,34 @@ fd_read(sock_T fd, char *buf, size_t len)
static int
fd_write(sock_T fd, char *buf, size_t len)
{
size_t todo = len;
HANDLE h = (HANDLE)fd;
DWORD nwrite;
DWORD nwrite, size, done = 0;
OVERLAPPED ov;

// 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))
while (todo > 0)
{
DWORD err = GetLastError();
if (todo > MAX_NAMED_PIPE_SIZE)
size = MAX_NAMED_PIPE_SIZE;
else
size = todo;
// 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 + done, size, &nwrite, &ov))
{
DWORD err = GetLastError();

if (err != ERROR_IO_PENDING)
return -1;
if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
return -1;
FlushFileBuffers(h);
if (err != ERROR_IO_PENDING)
return -1;
if (!GetOverlappedResult(h, &ov, &nwrite, FALSE))
return -1;
FlushFileBuffers(h);
}
todo -= nwrite;
done += nwrite;
}
return (int)nwrite;
return (int)done;
}

static void
Expand Down
2 changes: 1 addition & 1 deletion src/os_win32.c
Expand Up @@ -5369,7 +5369,7 @@ create_pipe_pair(HANDLE handles[2])
name,
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_NOWAIT,
1, 65535, 0, 0, NULL);
1, MAX_NAMED_PIPE_SIZE, 0, 0, NULL);

if (handles[1] == INVALID_HANDLE_VALUE)
return FALSE;
Expand Down
18 changes: 18 additions & 0 deletions src/testdir/test_channel.vim
Expand Up @@ -1980,3 +1980,21 @@ func Test_job_start_in_timer()
unlet! g:val
unlet! g:job
endfunc

func Test_raw_large_data()
try
let g:out = ''
let job = job_start(s:python . " test_channel_pipe.py",
\ {'mode': 'raw', 'drop': 'never', 'noblock': 1,
\ 'callback': {ch, msg -> execute('let g:out .= msg')}})

let want = repeat('X', 79999) . "\n"
call ch_sendraw(job, want)
let g:Ch_job = job
call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
call assert_equal(want, substitute(g:out, '\r', '', 'g'))
finally
call job_stop(job)
unlet g:out
endtry
endfunc
4 changes: 4 additions & 0 deletions src/testdir/test_channel_pipe.py
Expand Up @@ -56,4 +56,8 @@
if typed.startswith("doubleerr "):
print(typed[10:-1] + "\nAND " + typed[10:-1], file=sys.stderr)
sys.stderr.flush()
if typed.startswith("XXX"):
print(typed, end='')
sys.stderr.flush()
break

2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -787,6 +787,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
818,
/**/
817,
/**/
Expand Down
4 changes: 4 additions & 0 deletions src/vim.h
Expand Up @@ -2467,6 +2467,10 @@ typedef enum {
# define MAX_OPEN_CHANNELS 0
#endif

#if defined(WIN32)
# define MAX_NAMED_PIPE_SIZE 65535
#endif

/* Options for json_encode() and json_decode. */
#define JSON_JS 1 /* use JS instead of JSON */
#define JSON_NO_NONE 2 /* v:none item not allowed */
Expand Down

0 comments on commit 2405838

Please sign in to comment.