Mercurial > vim
comparison src/channel.c @ 7997:c1c9ab17e197 v7.4.1293
commit https://github.com/vim/vim/commit/e56bf15c163a921ce9e1c09c0d5b3a03efc63324
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Feb 8 23:23:42 2016 +0100
patch 7.4.1293
Problem: Sometimes a channel may hang waiting for a message that was
already discarded. (Ken Takata)
Solution: Store the ID of the message blocking on in the channel.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 08 Feb 2016 23:30:05 +0100 |
parents | d3fed9a639db |
children | b2cfa3416ba0 |
comparison
equal
deleted
inserted
replaced
7996:996b03ef584a | 7997:c1c9ab17e197 |
---|---|
114 int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */ | 114 int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */ |
115 #endif | 115 #endif |
116 | 116 |
117 void (*ch_close_cb)(void); /* callback for when channel is closed */ | 117 void (*ch_close_cb)(void); /* callback for when channel is closed */ |
118 | 118 |
119 int ch_block_id; /* ID that channel_read_json_block() is | |
120 waiting for */ | |
119 char_u *ch_callback; /* function to call when a msg is not handled */ | 121 char_u *ch_callback; /* function to call when a msg is not handled */ |
120 cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ | 122 cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ |
121 | 123 |
122 ch_mode_T ch_mode; | 124 ch_mode_T ch_mode; |
123 jsonq_T ch_json_head; /* dummy node, header for circular queue */ | 125 jsonq_T ch_json_head; /* dummy node, header for circular queue */ |
763 } | 765 } |
764 | 766 |
765 /* | 767 /* |
766 * Get a message from the JSON queue for channel "ch_idx". | 768 * Get a message from the JSON queue for channel "ch_idx". |
767 * When "id" is positive it must match the first number in the list. | 769 * When "id" is positive it must match the first number in the list. |
768 * When "id" is zero or negative jut get the first message. | 770 * When "id" is zero or negative jut get the first message. But not the one |
771 * with id ch_block_id. | |
769 * Return OK when found and return the value in "rettv". | 772 * Return OK when found and return the value in "rettv". |
770 * Return FAIL otherwise. | 773 * Return FAIL otherwise. |
771 */ | 774 */ |
772 static int | 775 static int |
773 channel_get_json(int ch_idx, int id, typval_T **rettv) | 776 channel_get_json(int ch_idx, int id, typval_T **rettv) |
774 { | 777 { |
775 jsonq_T *head = &channels[ch_idx].ch_json_head; | 778 channel_T *channel = &channels[ch_idx]; |
776 jsonq_T *item = head->next; | 779 jsonq_T *head = &channel->ch_json_head; |
780 jsonq_T *item = head->next; | |
777 | 781 |
778 while (item != head) | 782 while (item != head) |
779 { | 783 { |
780 list_T *l = item->value->vval.v_list; | 784 list_T *l = item->value->vval.v_list; |
781 typval_T *tv = &l->lv_first->li_tv; | 785 typval_T *tv = &l->lv_first->li_tv; |
782 | 786 |
783 if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) | 787 if ((id > 0 && tv->v_type == VAR_NUMBER && tv->vval.v_number == id) |
784 || id <= 0) | 788 || (id <= 0 && (tv->v_type != VAR_NUMBER |
789 || tv->vval.v_number != channel->ch_block_id))) | |
785 { | 790 { |
786 *rettv = item->value; | 791 *rettv = item->value; |
787 remove_json_node(item); | 792 remove_json_node(item); |
788 return OK; | 793 return OK; |
789 } | 794 } |
1289 * Blocks until the message is received or the timeout is reached. | 1294 * Blocks until the message is received or the timeout is reached. |
1290 */ | 1295 */ |
1291 int | 1296 int |
1292 channel_read_json_block(int ch_idx, int id, typval_T **rettv) | 1297 channel_read_json_block(int ch_idx, int id, typval_T **rettv) |
1293 { | 1298 { |
1294 int more; | 1299 int more; |
1295 | 1300 channel_T *channel = &channels[ch_idx]; |
1301 | |
1302 channel->ch_block_id = id; | |
1296 for (;;) | 1303 for (;;) |
1297 { | 1304 { |
1298 more = channel_parse_json(ch_idx); | 1305 more = channel_parse_json(ch_idx); |
1299 | 1306 |
1300 /* search for messsage "id" */ | 1307 /* search for messsage "id" */ |
1301 if (channel_get_json(ch_idx, id, rettv) == OK) | 1308 if (channel_get_json(ch_idx, id, rettv) == OK) |
1309 { | |
1310 channel->ch_block_id = 0; | |
1302 return OK; | 1311 return OK; |
1312 } | |
1303 | 1313 |
1304 if (!more) | 1314 if (!more) |
1305 { | 1315 { |
1306 /* Handle any other messages in the queue. If done some more | 1316 /* Handle any other messages in the queue. If done some more |
1307 * messages may have arrived. */ | 1317 * messages may have arrived. */ |
1308 if (channel_parse_messages()) | 1318 if (channel_parse_messages()) |
1309 continue; | 1319 continue; |
1310 | 1320 |
1311 /* Wait for up to the channel timeout. */ | 1321 /* Wait for up to the channel timeout. */ |
1312 if (channels[ch_idx].ch_fd < 0 | 1322 if (channel->ch_fd < 0 || channel_wait(channel->ch_fd, |
1313 || channel_wait(channels[ch_idx].ch_fd, | 1323 channel->ch_timeout) == FAIL) |
1314 channels[ch_idx].ch_timeout) == FAIL) | |
1315 break; | 1324 break; |
1316 channel_read(ch_idx); | 1325 channel_read(ch_idx); |
1317 } | 1326 } |
1318 } | 1327 } |
1328 channel->ch_block_id = 0; | |
1319 return FAIL; | 1329 return FAIL; |
1320 } | 1330 } |
1321 | 1331 |
1322 # if defined(WIN32) || defined(PROTO) | 1332 # if defined(WIN32) || defined(PROTO) |
1323 /* | 1333 /* |