Mercurial > vim
comparison src/channel.c @ 9007:d5c6f1c5cd28 v7.4.1789
commit https://github.com/vim/vim/commit/437905c25d4cedfa16d0f87392e4a000d22362b7
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Apr 26 19:01:05 2016 +0200
patch 7.4.1789
Problem: Cannot use ch_read() in the close callback.
Solution: Do not discard the channel if there is readahead. Do not discard
readahead if there is a close callback.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 26 Apr 2016 19:15:06 +0200 |
parents | 072556995a8e |
children | 72a597e9e36d |
comparison
equal
deleted
inserted
replaced
9006:ef8e23332fa8 | 9007:d5c6f1c5cd28 |
---|---|
2101 in_part->ch_buf_bot = buffer->b_ml.ml_line_count; | 2101 in_part->ch_buf_bot = buffer->b_ml.ml_line_count; |
2102 } | 2102 } |
2103 } | 2103 } |
2104 } | 2104 } |
2105 | 2105 |
2106 static void | |
2107 drop_messages(channel_T *channel, int part) | |
2108 { | |
2109 char_u *msg; | |
2110 | |
2111 while ((msg = channel_get(channel, part)) != NULL) | |
2112 { | |
2113 ch_logs(channel, "Dropping message '%s'", (char *)msg); | |
2114 vim_free(msg); | |
2115 } | |
2116 } | |
2117 | |
2106 /* | 2118 /* |
2107 * Invoke a callback for "channel"/"part" if needed. | 2119 * Invoke a callback for "channel"/"part" if needed. |
2108 * This does not redraw but sets channel_need_redraw when redraw is needed. | 2120 * This does not redraw but sets channel_need_redraw when redraw is needed. |
2109 * Return TRUE when a message was handled, there might be another one. | 2121 * Return TRUE when a message was handled, there might be another one. |
2110 */ | 2122 */ |
2200 else | 2212 else |
2201 { | 2213 { |
2202 /* If there is no callback or buffer drop the message. */ | 2214 /* If there is no callback or buffer drop the message. */ |
2203 if (callback == NULL && buffer == NULL) | 2215 if (callback == NULL && buffer == NULL) |
2204 { | 2216 { |
2205 while ((msg = channel_get(channel, part)) != NULL) | 2217 /* If there is a close callback it may use ch_read() to get the |
2206 { | 2218 * messages. */ |
2207 ch_logs(channel, "Dropping message '%s'", (char *)msg); | 2219 if (channel->ch_close_cb == NULL) |
2208 vim_free(msg); | 2220 drop_messages(channel, part); |
2209 } | |
2210 return FALSE; | 2221 return FALSE; |
2211 } | 2222 } |
2212 | 2223 |
2213 if (ch_mode == MODE_NL) | 2224 if (ch_mode == MODE_NL) |
2214 { | 2225 { |
2324 || channel->CH_OUT_FD != INVALID_FD | 2335 || channel->CH_OUT_FD != INVALID_FD |
2325 || channel->CH_ERR_FD != INVALID_FD); | 2336 || channel->CH_ERR_FD != INVALID_FD); |
2326 } | 2337 } |
2327 | 2338 |
2328 /* | 2339 /* |
2340 * Return TRUE if "channel" has JSON or other typeahead. | |
2341 */ | |
2342 static int | |
2343 channel_has_readahead(channel_T *channel, int part) | |
2344 { | |
2345 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; | |
2346 | |
2347 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) | |
2348 { | |
2349 jsonq_T *head = &channel->ch_part[part].ch_json_head; | |
2350 jsonq_T *item = head->jq_next; | |
2351 | |
2352 return item != NULL; | |
2353 } | |
2354 return channel_peek(channel, part) != NULL; | |
2355 } | |
2356 | |
2357 /* | |
2329 * Return a string indicating the status of the channel. | 2358 * Return a string indicating the status of the channel. |
2330 */ | 2359 */ |
2331 char * | 2360 char * |
2332 channel_status(channel_T *channel) | 2361 channel_status(channel_T *channel) |
2333 { | 2362 { |
2363 int part; | |
2364 int has_readahead = FALSE; | |
2365 | |
2334 if (channel == NULL) | 2366 if (channel == NULL) |
2335 return "fail"; | 2367 return "fail"; |
2336 if (channel_is_open(channel)) | 2368 if (channel_is_open(channel)) |
2337 return "open"; | 2369 return "open"; |
2370 for (part = PART_SOCK; part <= PART_ERR; ++part) | |
2371 if (channel_has_readahead(channel, part)) | |
2372 { | |
2373 has_readahead = TRUE; | |
2374 break; | |
2375 } | |
2376 | |
2377 if (has_readahead) | |
2378 return "buffered"; | |
2338 return "closed"; | 2379 return "closed"; |
2339 } | 2380 } |
2340 | 2381 |
2341 static void | 2382 static void |
2342 channel_part_info(channel_T *channel, dict_T *dict, char *name, int part) | 2383 channel_part_info(channel_T *channel, dict_T *dict, char *name, int part) |
2456 /* the callback is only called once */ | 2497 /* the callback is only called once */ |
2457 vim_free(channel->ch_close_cb); | 2498 vim_free(channel->ch_close_cb); |
2458 channel->ch_close_cb = NULL; | 2499 channel->ch_close_cb = NULL; |
2459 partial_unref(channel->ch_close_partial); | 2500 partial_unref(channel->ch_close_partial); |
2460 channel->ch_close_partial = NULL; | 2501 channel->ch_close_partial = NULL; |
2502 | |
2503 /* any remaining messages are useless now */ | |
2504 for (part = PART_SOCK; part <= PART_ERR; ++part) | |
2505 drop_messages(channel, part); | |
2461 } | 2506 } |
2462 | 2507 |
2463 channel->ch_nb_close_cb = NULL; | 2508 channel->ch_nb_close_cb = NULL; |
2464 } | 2509 } |
2465 | 2510 |
2965 */ | 3010 */ |
2966 void | 3011 void |
2967 common_channel_read(typval_T *argvars, typval_T *rettv, int raw) | 3012 common_channel_read(typval_T *argvars, typval_T *rettv, int raw) |
2968 { | 3013 { |
2969 channel_T *channel; | 3014 channel_T *channel; |
2970 int part; | 3015 int part = -1; |
2971 jobopt_T opt; | 3016 jobopt_T opt; |
2972 int mode; | 3017 int mode; |
2973 int timeout; | 3018 int timeout; |
2974 int id = -1; | 3019 int id = -1; |
2975 typval_T *listtv = NULL; | 3020 typval_T *listtv = NULL; |
2981 clear_job_options(&opt); | 3026 clear_job_options(&opt); |
2982 if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID) | 3027 if (get_job_options(&argvars[1], &opt, JO_TIMEOUT + JO_PART + JO_ID) |
2983 == FAIL) | 3028 == FAIL) |
2984 goto theend; | 3029 goto theend; |
2985 | 3030 |
2986 channel = get_channel_arg(&argvars[0], TRUE); | 3031 if (opt.jo_set & JO_PART) |
3032 part = opt.jo_part; | |
3033 channel = get_channel_arg(&argvars[0], TRUE, TRUE, part); | |
2987 if (channel != NULL) | 3034 if (channel != NULL) |
2988 { | 3035 { |
2989 if (opt.jo_set & JO_PART) | 3036 if (part < 0) |
2990 part = opt.jo_part; | |
2991 else | |
2992 part = channel_part_read(channel); | 3037 part = channel_part_read(channel); |
2993 mode = channel_get_mode(channel, part); | 3038 mode = channel_get_mode(channel, part); |
2994 timeout = channel_get_timeout(channel, part); | 3039 timeout = channel_get_timeout(channel, part); |
2995 if (opt.jo_set & JO_TIMEOUT) | 3040 if (opt.jo_set & JO_TIMEOUT) |
2996 timeout = opt.jo_timeout; | 3041 timeout = opt.jo_timeout; |
3150 { | 3195 { |
3151 channel_T *channel; | 3196 channel_T *channel; |
3152 int part_send; | 3197 int part_send; |
3153 | 3198 |
3154 clear_job_options(opt); | 3199 clear_job_options(opt); |
3155 channel = get_channel_arg(&argvars[0], TRUE); | 3200 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); |
3156 if (channel == NULL) | 3201 if (channel == NULL) |
3157 return NULL; | 3202 return NULL; |
3158 part_send = channel_part_send(channel); | 3203 part_send = channel_part_send(channel); |
3159 *part_read = channel_part_read(channel); | 3204 *part_read = channel_part_read(channel); |
3160 | 3205 |
3199 | 3244 |
3200 /* return an empty string by default */ | 3245 /* return an empty string by default */ |
3201 rettv->v_type = VAR_STRING; | 3246 rettv->v_type = VAR_STRING; |
3202 rettv->vval.v_string = NULL; | 3247 rettv->vval.v_string = NULL; |
3203 | 3248 |
3204 channel = get_channel_arg(&argvars[0], TRUE); | 3249 channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); |
3205 if (channel == NULL) | 3250 if (channel == NULL) |
3206 return; | 3251 return; |
3207 part_send = channel_part_send(channel); | 3252 part_send = channel_part_send(channel); |
3208 | 3253 |
3209 ch_mode = channel_get_mode(channel, part_send); | 3254 ch_mode = channel_get_mode(channel, part_send); |
3431 } | 3476 } |
3432 | 3477 |
3433 return ret; | 3478 return ret; |
3434 } | 3479 } |
3435 # endif /* !WIN32 && HAVE_SELECT */ | 3480 # endif /* !WIN32 && HAVE_SELECT */ |
3436 | |
3437 /* | |
3438 * Return TRUE if "channel" has JSON or other typeahead. | |
3439 */ | |
3440 static int | |
3441 channel_has_readahead(channel_T *channel, int part) | |
3442 { | |
3443 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; | |
3444 | |
3445 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) | |
3446 { | |
3447 jsonq_T *head = &channel->ch_part[part].ch_json_head; | |
3448 jsonq_T *item = head->jq_next; | |
3449 | |
3450 return item != NULL; | |
3451 } | |
3452 return channel_peek(channel, part) != NULL; | |
3453 } | |
3454 | 3481 |
3455 /* | 3482 /* |
3456 * Execute queued up commands. | 3483 * Execute queued up commands. |
3457 * Invoked from the main loop when it's safe to execute received commands. | 3484 * Invoked from the main loop when it's safe to execute received commands. |
3458 * Return TRUE when something was done. | 3485 * Return TRUE when something was done. |
3966 } | 3993 } |
3967 | 3994 |
3968 /* | 3995 /* |
3969 * Get the channel from the argument. | 3996 * Get the channel from the argument. |
3970 * Returns NULL if the handle is invalid. | 3997 * Returns NULL if the handle is invalid. |
3998 * When "check_open" is TRUE check that the channel can be used. | |
3999 * When "reading" is TRUE "check_open" considers typeahead useful. | |
4000 * "part" is used to check typeahead, when -1 use the default part. | |
3971 */ | 4001 */ |
3972 channel_T * | 4002 channel_T * |
3973 get_channel_arg(typval_T *tv, int check_open) | 4003 get_channel_arg(typval_T *tv, int check_open, int reading, int part) |
3974 { | 4004 { |
3975 channel_T *channel = NULL; | 4005 channel_T *channel = NULL; |
4006 int has_readahead = FALSE; | |
3976 | 4007 |
3977 if (tv->v_type == VAR_JOB) | 4008 if (tv->v_type == VAR_JOB) |
3978 { | 4009 { |
3979 if (tv->vval.v_job != NULL) | 4010 if (tv->vval.v_job != NULL) |
3980 channel = tv->vval.v_job->jv_channel; | 4011 channel = tv->vval.v_job->jv_channel; |
3986 else | 4017 else |
3987 { | 4018 { |
3988 EMSG2(_(e_invarg2), get_tv_string(tv)); | 4019 EMSG2(_(e_invarg2), get_tv_string(tv)); |
3989 return NULL; | 4020 return NULL; |
3990 } | 4021 } |
3991 | 4022 if (channel != NULL && reading) |
3992 if (check_open && (channel == NULL || !channel_is_open(channel))) | 4023 has_readahead = channel_has_readahead(channel, |
4024 part >= 0 ? part : channel_part_read(channel)); | |
4025 | |
4026 if (check_open && (channel == NULL || (!channel_is_open(channel) | |
4027 && !(reading && has_readahead)))) | |
3993 { | 4028 { |
3994 EMSG(_("E906: not an open channel")); | 4029 EMSG(_("E906: not an open channel")); |
3995 return NULL; | 4030 return NULL; |
3996 } | 4031 } |
3997 return channel; | 4032 return channel; |