From 9730f74a0b2acb490943393a203a24ab8fab923a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 19:50:51 +0100 Subject: [PATCH 1/6] patch 7.4.1454 Problem: The exit callback test is flaky. Solution: Loop to wait for a short time up to a second. --- src/testdir/test_channel.vim | 17 +++++++++++++---- src/version.c | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index b214fa9885..0fded018a3 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -535,14 +535,21 @@ endfunc func Test_exit_callback() if has('job') + call ch_log('Test_exit_callback()') call s:run_server('s:test_exit_callback') - " the job may take a little while to exit - sleep 50m + " wait up to a second for the job to exit + for i in range(100) + if s:job_exit_ret == 'done' + break + endif + sleep 10m + " calling job_status() triggers the callback + call job_status(s:exit_job) + endfor - " calling job_status() triggers the callback - call job_status(s:exit_job) call assert_equal('done', s:job_exit_ret) + unlet s:exit_job endif endfunc @@ -571,3 +578,5 @@ func Test_close_callback() call s:run_server('s:test_close_callback') endfunc +" Uncomment this to see what happens, output is in src/testdir/channellog. +" call ch_logfile('channellog', 'w') diff --git a/src/version.c b/src/version.c index 991af8dbfb..2c21470811 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1454, /**/ 1453, /**/ From fc2457e21d136cb366076edd448e67c9732dc40a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 20:04:09 +0100 Subject: [PATCH 2/6] patch 7.4.1455 Problem: JSON decoding test for surrogate pairs is in the wrong place. Solution: Move the test lines. (Ken Takata) --- src/testdir/test_json.vim | 10 ++++++---- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim index 4955cadda3..589fcb9edc 100644 --- a/src/testdir/test_json.vim +++ b/src/testdir/test_json.vim @@ -82,8 +82,7 @@ func Test_json_encode() if has('multi_byte') call assert_equal(s:jsonmb, json_encode(s:varmb)) - call assert_equal(s:varsp1, json_decode(s:jsonsp1)) - call assert_equal(s:varsp2, json_decode(s:jsonsp2)) + " no test for surrogate pair, json_encode() doesn't create them. endif call assert_equal(s:jsonnr, json_encode(s:varnr)) @@ -120,8 +119,8 @@ func Test_json_decode() if has('multi_byte') call assert_equal(s:varmb, json_decode(s:jsonmb)) - call assert_equal(s:varsp1, js_decode(s:jsonsp1)) - call assert_equal(s:varsp2, js_decode(s:jsonsp2)) + call assert_equal(s:varsp1, json_decode(s:jsonsp1)) + call assert_equal(s:varsp2, json_decode(s:jsonsp2)) endif call assert_equal(s:varnr, json_decode(s:jsonnr)) @@ -185,6 +184,7 @@ func Test_js_encode() if has('multi_byte') call assert_equal(s:jsonmb, js_encode(s:varmb)) + " no test for surrogate pair, js_encode() doesn't create them. endif call assert_equal(s:jsonnr, js_encode(s:varnr)) @@ -223,6 +223,8 @@ func Test_js_decode() if has('multi_byte') call assert_equal(s:varmb, js_decode(s:jsonmb)) + call assert_equal(s:varsp1, js_decode(s:jsonsp1)) + call assert_equal(s:varsp2, js_decode(s:jsonsp2)) endif call assert_equal(s:varnr, js_decode(s:jsonnr)) diff --git a/src/version.c b/src/version.c index 2c21470811..17d42ce564 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1455, /**/ 1454, /**/ From 29e1951e14907b62797554ad0cc85cbbe75a1be4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 20:13:18 +0100 Subject: [PATCH 3/6] patch 7.4.1456 Problem: Test 87 fails with Python 3.5. Solution: Work around difference. (Taro Muraoka) --- src/testdir/test87.in | 8 +++++++- src/version.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/testdir/test87.in b/src/testdir/test87.in index 154e823827..535a143782 100644 --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -228,6 +228,8 @@ def ee(expr, g=globals(), l=locals()): cb.append(expr + ':' + repr((e.__class__, TypeError(msg)))) else: cb.append(expr + ':' + repr((e.__class__, e))) + elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': + msg = cb.append(expr + ':' + repr((TypeError, TypeError('expected bytes with no null')))) else: cb.append(expr + ':' + repr((e.__class__, e))) else: @@ -264,13 +266,17 @@ EOF :let messages=[] :delfunction DictNew py3 <= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte': + m.extend([TypeError.__name__]) + else: + m.extend([e.__class__.__name__]) em('d["abc1"]') em('d["abc1"]="\\0"') diff --git a/src/version.c b/src/version.c index 17d42ce564..923256b399 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1456, /**/ 1455, /**/ From d42119fff228434fe57e88d501c744de0a9fb1b1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 20:51:49 +0100 Subject: [PATCH 4/6] patch 7.4.1457 Problem: Opening a channel with select() is not done properly. Solution: Also used read-fds. Use getsockopt() to check for errors. (Ozaki Kiichi) --- src/channel.c | 69 ++++++++++++++++++++++++++------------------------- src/version.c | 2 ++ 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/channel.c b/src/channel.c index 9e406abdb2..61156be385 100644 --- a/src/channel.c +++ b/src/channel.c @@ -28,6 +28,8 @@ # define ECONNREFUSED WSAECONNREFUSED # undef EWOULDBLOCK # define EWOULDBLOCK WSAEWOULDBLOCK +# undef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS # ifdef EINTR # undef EINTR # endif @@ -550,8 +552,6 @@ channel_open( #else int port = port_in; struct timeval start_tv; - int so_error; - socklen_t so_error_len = sizeof(so_error); #endif channel_T *channel; int ret; @@ -633,7 +633,6 @@ channel_open( { if (errno != EWOULDBLOCK && errno != ECONNREFUSED - #ifdef EINPROGRESS && errno != EINPROGRESS #endif @@ -653,14 +652,13 @@ channel_open( if (waittime >= 0 && ret < 0) { struct timeval tv; + fd_set rfds; fd_set wfds; -#if defined(__APPLE__) && __APPLE__ == 1 -# define PASS_RFDS - fd_set rfds; + int so_error = 0; + socklen_t so_error_len = sizeof(so_error); FD_ZERO(&rfds); FD_SET(sd, &rfds); -#endif FD_ZERO(&wfds); FD_SET(sd, &wfds); @@ -671,13 +669,7 @@ channel_open( #endif ch_logn(channel, "Waiting for connection (waittime %d msec)...", waittime); - ret = select((int)sd + 1, -#ifdef PASS_RFDS - &rfds, -#else - NULL, -#endif - &wfds, NULL, &tv); + ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv); if (ret < 0) { @@ -689,30 +681,39 @@ channel_open( channel_free(channel); return NULL; } -#ifdef PASS_RFDS - if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) - { - /* For OS X, this implies error. See tcp(4). */ - ch_error(channel, "channel_open: Connect failed"); - EMSG(_(e_cannot_connect)); - sock_close(sd); - channel_free(channel); - return NULL; - } -#endif -#ifdef WIN32 - /* On Win32 select() is expected to work and wait for up to the - * waittime for the socket to be open. */ - if (!FD_ISSET(sd, &wfds) || ret == 0) -#else - /* See socket(7) for the behavior on Linux-like systems: + + /* On Win32: select() is expected to work and wait for up to the + * waittime for the socket to be open. + * On Linux-like systems: See socket(7) for the behavior * After putting the socket in non-blocking mode, connect() will * return EINPROGRESS, select() will not wait (as if writing is * possible), need to use getsockopt() to check if the socket is - * actually open. */ - getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); - if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0) + * actually connect. + * We detect an failure to connect when both read and write fds + * are set. Use getsockopt() to find out what kind of failure. */ + if (FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) + { + ret = getsockopt(sd, + SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); + if (ret < 0 || (so_error != 0 + && so_error != EWOULDBLOCK + && so_error != ECONNREFUSED +#ifdef EINPROGRESS + && so_error != EINPROGRESS #endif + )) + { + ch_errorn(channel, + "channel_open: Connect failed with errno %d", + so_error); + PERROR(_(e_cannot_connect)); + sock_close(sd); + channel_free(channel); + return NULL; + } + } + + if (!FD_ISSET(sd, &wfds) || so_error != 0) { #ifndef WIN32 struct timeval end_tv; diff --git a/src/version.c b/src/version.c index 923256b399..33640ce1b4 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1457, /**/ 1456, /**/ From fdd6ce4a2f922afac7bd719a00228dbd8539b9c4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 22:21:38 +0100 Subject: [PATCH 5/6] patch 7.4.1458 Problem: When a JSON channel has a callback it may never be cleared. Solution: Do not write "DETACH" into a JS or JSON channel. --- src/channel.c | 54 ++++++++++++++++++++++++++++++++++++++------------- src/version.c | 2 ++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/channel.c b/src/channel.c index 61156be385..745d226a27 100644 --- a/src/channel.c +++ b/src/channel.c @@ -316,20 +316,47 @@ add_channel(void) * Called when the refcount of a channel is zero. * Return TRUE if "channel" has a callback and the associated job wasn't * killed. - * If the job was killed the channel is not expected to work anymore. - * If there is no callback then nobody can get readahead. */ static int channel_still_useful(channel_T *channel) { + int has_sock_msg; +#ifdef CHANNEL_PIPES + int has_out_msg; + int has_err_msg; +#endif + + /* If the job was killed the channel is not expected to work anymore. */ if (channel->ch_job_killed && channel->ch_job == NULL) return FALSE; - return channel->ch_callback != NULL + + /* If there is a close callback it may still need to be invoked. */ + if (channel->ch_close_cb != NULL) + return TRUE; + + /* If there is no callback then nobody can get readahead. If the fd is + * closed and there is no readahead then the callback won't be called. */ + has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD + || channel->ch_part[PART_SOCK].ch_head.rq_next != NULL + || channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL; #ifdef CHANNEL_PIPES - || channel->ch_part[PART_OUT].ch_callback != NULL - || channel->ch_part[PART_ERR].ch_callback != NULL + has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD + || channel->ch_part[PART_OUT].ch_head.rq_next != NULL + || channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL; + has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD + || channel->ch_part[PART_ERR].ch_head.rq_next != NULL + || channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL; #endif - || channel->ch_close_cb != NULL; + return (channel->ch_callback != NULL && (has_sock_msg +#ifdef CHANNEL_PIPES + || has_out_msg || has_err_msg +#endif + )) +#ifdef CHANNEL_PIPES + || (channel->ch_part[PART_OUT].ch_callback != NULL && has_out_msg) + || (channel->ch_part[PART_ERR].ch_callback != NULL && has_err_msg) +#endif + ; } /* @@ -1497,7 +1524,7 @@ may_invoke_callback(channel_T *channel, int part) { if (item->cq_seq_nr == seq_nr) { - ch_logs(channel, "Invoking one-time callback '%s'", + ch_logs(channel, "Invoking one-time callback %s", (char *)item->cq_callback); /* Remove the item from the list first, if the callback * invokes ch_close() the list will be cleared. */ @@ -1558,7 +1585,7 @@ may_invoke_callback(channel_T *channel, int part) if (callback != NULL) { /* invoke the channel callback */ - ch_log(channel, "Invoking channel callback"); + ch_logs(channel, "Invoking channel callback %s", (char *)callback); invoke_callback(channel, callback, argv); } } @@ -1758,7 +1785,6 @@ channel_free_all(void) /* Sent when the channel is found closed when reading. */ #define DETACH_MSG_RAW "DETACH\n" -#define DETACH_MSG_JSON "\"DETACH\"\n" /* Buffer size for reading incoming messages. */ #define MAXMSGSIZE 4096 @@ -1854,7 +1880,6 @@ channel_read(channel_T *channel, int part, char *func) int readlen = 0; sock_T fd; int use_socket = FALSE; - char *msg; fd = channel->ch_part[part].ch_fd; if (fd == INVALID_FD) @@ -1909,11 +1934,12 @@ channel_read(channel_T *channel, int part, char *func) * -> ui_breakcheck * -> gui event loop or select loop * -> channel_read() + * Don't send "DETACH" for a JS or JSON channel. */ - msg = channel->ch_part[part].ch_mode == MODE_RAW - || channel->ch_part[part].ch_mode == MODE_NL - ? DETACH_MSG_RAW : DETACH_MSG_JSON; - channel_save(channel, part, (char_u *)msg, (int)STRLEN(msg)); + if (channel->ch_part[part].ch_mode == MODE_RAW + || channel->ch_part[part].ch_mode == MODE_NL) + channel_save(channel, part, (char_u *)DETACH_MSG_RAW, + (int)STRLEN(DETACH_MSG_RAW)); /* TODO: When reading from stdout is not possible, should we try to * keep stdin and stderr open? Probably not, assume the other side diff --git a/src/version.c b/src/version.c index 33640ce1b4..0fb7b8a56a 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1458, /**/ 1457, /**/ From e081e21f760bffc24ca98d5f9bbdb5f02e6aea79 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 28 Feb 2016 22:33:46 +0100 Subject: [PATCH 6/6] patch 7.4.1459 Problem: MS-Windows doesn't know socklen_t. Solution: Use previous method for WIN32. --- src/channel.c | 14 ++++++++++---- src/version.c | 2 ++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/channel.c b/src/channel.c index 745d226a27..a1ea6b843a 100644 --- a/src/channel.c +++ b/src/channel.c @@ -681,8 +681,10 @@ channel_open( struct timeval tv; fd_set rfds; fd_set wfds; +#ifndef WIN32 int so_error = 0; socklen_t so_error_len = sizeof(so_error); +#endif FD_ZERO(&rfds); FD_SET(sd, &rfds); @@ -709,9 +711,12 @@ channel_open( return NULL; } +#ifdef WIN32 /* On Win32: select() is expected to work and wait for up to the - * waittime for the socket to be open. - * On Linux-like systems: See socket(7) for the behavior + * waittime for the socket to be open. */ + if (!FD_ISSET(sd, &wfds) || ret == 0) +#else + /* On Linux-like systems: See socket(7) for the behavior * After putting the socket in non-blocking mode, connect() will * return EINPROGRESS, select() will not wait (as if writing is * possible), need to use getsockopt() to check if the socket is @@ -725,9 +730,9 @@ channel_open( if (ret < 0 || (so_error != 0 && so_error != EWOULDBLOCK && so_error != ECONNREFUSED -#ifdef EINPROGRESS +# ifdef EINPROGRESS && so_error != EINPROGRESS -#endif +# endif )) { ch_errorn(channel, @@ -741,6 +746,7 @@ channel_open( } if (!FD_ISSET(sd, &wfds) || so_error != 0) +#endif { #ifndef WIN32 struct timeval end_tv; diff --git a/src/version.c b/src/version.c index 0fb7b8a56a..f9f412801a 100644 --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1459, /**/ 1458, /**/