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 : */