Hi,

I found another problem with channel on Win32 GUI.
When executing the following line in test_channel.vim, Vim sometimes hangs up:

  call assert_equal('ok', ch_sendexpr(handle, 'make change'))

When test_channnel.vim receives 'make change', it send two responses
'["ex","call append(\\"$\\",\\"added1\\")"]["ex","call 
append(\\"$\\",\\"added2\\")"]'
and [id, "ok"].  And when Vim receives these responses as two separated
responses, the problem occurs.


1291     int
1292 channel_read_json_block(int ch_idx, int id, typval_T **rettv)
1293 {
1294     int  more;
1295
1296     for (;;)
1297     {
1298         more = channel_parse_json(ch_idx);
1299
1300         /* search for messsage "id" */
1301         if (channel_get_json(ch_idx, id, rettv) == OK)
1302             return OK;
1303
1304         if (!more)
1305         {
1306             /* Handle any other messages in the queue.  If done some more
1307              * messages may have arrived. */
1308             if (channel_parse_messages())
1309                 continue;
1310
1311             /* Wait for up to the channel timeout. */
1312             if (channels[ch_idx].ch_fd < 0
1313                         || channel_wait(channels[ch_idx].ch_fd,
1314                                          channels[ch_idx].ch_timeout) == 
FAIL)
1315                 break;
1316             channel_read(ch_idx);
1317         }
1318     }
1319     return FAIL;
1320 }

In L1301, channel_get_json() waits [id, "ok"] but it's not found when the
responses are separated because the only two ["ex", *] responses are available.
In L1308, channel_parse_messages() calls channel_get_json(), and then it
receives [id, "ok"] but the response will be thrown away(?).
Next time in L1301, channel_get_json() cannot find [id, "ok"], so the function
channel_read_json_block() will not return.

Attached patch seems to fix this, but I'm not sure this is a right solution.


Regards,
Ken Takata

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
# HG changeset patch
# Parent  6ccf095d722ecad18c7e616d2888cd32a2d8c3da

diff --git a/src/channel.c b/src/channel.c
--- a/src/channel.c
+++ b/src/channel.c
@@ -765,7 +765,8 @@ remove_json_node(jsonq_T *node)
 /*
  * Get a message from the JSON queue for channel "ch_idx".
  * When "id" is positive it must match the first number in the list.
- * When "id" is zero or negative jut get the first message.
+ * When "id" is zero just get the first message.
+ * When "id" is negative get the first message which doesn't match "-id".
  * Return OK when found and return the value in "rettv".
  * Return FAIL otherwise.
  */
@@ -781,7 +782,9 @@ channel_get_json(int ch_idx, int id, typ
 	typval_T    *tv = &l->lv_first->li_tv;
 
 	if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id)
-	      || id <= 0)
+	      || (id < 0 && tv->v_type == VAR_NUMBER
+						&& tv->vval.v_number != -id)
+	      || id == 0)
 	{
 	    *rettv = item->value;
 	    remove_json_node(item);
@@ -894,10 +897,12 @@ channel_exe_cmd(int idx, char_u *cmd, ty
 
 /*
  * Invoke a callback for channel "idx" if needed.
+ * If "id" is zero all messages are processed.
+ * If "id" is not zero all messages except "id" are processed.
  * Return OK when a message was handled, there might be another one.
  */
     static int
-may_invoke_callback(int idx)
+may_invoke_callback(int idx, int id)
 {
     char_u	*msg = NULL;
     typval_T	*listtv = NULL;
@@ -915,11 +920,11 @@ may_invoke_callback(int idx)
     if (ch_mode != MODE_RAW)
     {
 	/* Get any json message in the queue. */
-	if (channel_get_json(idx, -1, &listtv) == FAIL)
+	if (channel_get_json(idx, -id, &listtv) == FAIL)
 	{
 	    /* Parse readahead, return when there is still no message. */
 	    channel_parse_json(idx);
-	    if (channel_get_json(idx, -1, &listtv) == FAIL)
+	    if (channel_get_json(idx, -id, &listtv) == FAIL)
 		return FALSE;
 	}
 
@@ -1303,9 +1308,9 @@ channel_read_json_block(int ch_idx, int 
 
 	if (!more)
 	{
-	    /* Handle any other messages in the queue.  If done some more
-	     * messages may have arrived. */
-	    if (channel_parse_messages())
+	    /* Handle any other messages except "id" in the queue.  If done
+	     * some more messages may have arrived. */
+	    if (channel_parse_messages(id))
 		continue;
 
 	    /* Wait for up to the channel timeout. */
@@ -1470,16 +1475,18 @@ channel_select_check(int ret_in, void *r
 /*
  * Execute queued up commands.
  * Invoked from the main loop when it's safe to execute received commands.
+ * If "id" is zero all messages are processed.
+ * If "id" is not zero all messages except "id" are processed.
  * Return TRUE when something was done.
  */
     int
-channel_parse_messages(void)
+channel_parse_messages(int id)
 {
     int	    i;
     int	    ret = FALSE;
 
     for (i = 0; i < channel_count; ++i)
-	while (may_invoke_callback(i) == OK)
+	while (may_invoke_callback(i, id) == OK)
 	{
 	    i = 0;  /* start over */
 	    ret = TRUE;
diff --git a/src/misc2.c b/src/misc2.c
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -6242,7 +6242,7 @@ parse_queued_messages(void)
 # endif
 # ifdef FEAT_CHANNEL
     /* Process the messages queued on channels. */
-    channel_parse_messages();
+    channel_parse_messages(0);
 # endif
 # if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
     /* Process the queued clientserver messages. */
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -22,7 +22,7 @@ int channel_poll_setup(int nfd_in, void 
 int channel_poll_check(int ret_in, void *fds_in);
 int channel_select_setup(int maxfd_in, void *rfds_in);
 int channel_select_check(int ret_in, void *rfds_in);
-int channel_parse_messages(void);
+int channel_parse_messages(int id);
 int set_ref_in_channel(int copyID);
 ch_mode_T channel_get_mode(int idx);
 /* vim: set ft=c : */

Raspunde prin e-mail lui