Mercurial > vim
comparison src/channel.c @ 9085:d362e6df1deb v7.4.1827
commit https://github.com/vim/vim/commit/fb6ffc732e65dbc459c89247ff78134402f1a18b
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon May 9 17:58:04 2016 +0200
patch 7.4.1827
Problem: No error when invoking a callback when it's not safe.
Solution: Add an error message. Avoid the error when freeing a channel.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 09 May 2016 18:00:06 +0200 |
parents | 69bb7b230094 |
children | d4606ae170aa |
comparison
equal
deleted
inserted
replaced
9084:8d3354777bf1 | 9085:d362e6df1deb |
---|---|
57 static void channel_read(channel_T *channel, int part, char *func); | 57 static void channel_read(channel_T *channel, int part, char *func); |
58 | 58 |
59 /* Whether a redraw is needed for appending a line to a buffer. */ | 59 /* Whether a redraw is needed for appending a line to a buffer. */ |
60 static int channel_need_redraw = FALSE; | 60 static int channel_need_redraw = FALSE; |
61 | 61 |
62 /* Whether we are inside channel_parse_messages() or another situation where it | |
63 * is safe to invoke callbacks. */ | |
64 static int safe_to_invoke_callback = 0; | |
62 | 65 |
63 #ifdef WIN32 | 66 #ifdef WIN32 |
64 static int | 67 static int |
65 fd_read(sock_T fd, char *buf, size_t len) | 68 fd_read(sock_T fd, char *buf, size_t len) |
66 { | 69 { |
401 static void | 404 static void |
402 channel_free(channel_T *channel) | 405 channel_free(channel_T *channel) |
403 { | 406 { |
404 if (!in_free_unref_items) | 407 if (!in_free_unref_items) |
405 { | 408 { |
406 channel_free_contents(channel); | 409 if (safe_to_invoke_callback == 0) |
407 channel_free_channel(channel); | 410 { |
411 channel->ch_to_be_freed = TRUE; | |
412 } | |
413 else | |
414 { | |
415 channel_free_contents(channel); | |
416 channel_free_channel(channel); | |
417 } | |
408 } | 418 } |
409 } | 419 } |
410 | 420 |
411 /* | 421 /* |
412 * Close a channel and free all its resources if there is no further action | 422 * Close a channel and free all its resources if there is no further action |
442 free_unused_channels_contents(int copyID, int mask) | 452 free_unused_channels_contents(int copyID, int mask) |
443 { | 453 { |
444 int did_free = FALSE; | 454 int did_free = FALSE; |
445 channel_T *ch; | 455 channel_T *ch; |
446 | 456 |
457 /* This is invoked from the garbage collector, which only runs at a safe | |
458 * point. */ | |
459 ++safe_to_invoke_callback; | |
460 | |
447 for (ch = first_channel; ch != NULL; ch = ch->ch_next) | 461 for (ch = first_channel; ch != NULL; ch = ch->ch_next) |
448 if (!channel_still_useful(ch) | 462 if (!channel_still_useful(ch) |
449 && (ch->ch_copyID & mask) != (copyID & mask)) | 463 && (ch->ch_copyID & mask) != (copyID & mask)) |
450 { | 464 { |
451 /* Free the channel and ordinary items it contains, but don't | 465 /* Free the channel and ordinary items it contains, but don't |
452 * recurse into Lists, Dictionaries etc. */ | 466 * recurse into Lists, Dictionaries etc. */ |
453 channel_free_contents(ch); | 467 channel_free_contents(ch); |
454 did_free = TRUE; | 468 did_free = TRUE; |
455 } | 469 } |
470 | |
471 --safe_to_invoke_callback; | |
456 return did_free; | 472 return did_free; |
457 } | 473 } |
458 | 474 |
459 void | 475 void |
460 free_unused_channels(int copyID, int mask) | 476 free_unused_channels(int copyID, int mask) |
1447 invoke_callback(channel_T *channel, char_u *callback, partial_T *partial, | 1463 invoke_callback(channel_T *channel, char_u *callback, partial_T *partial, |
1448 typval_T *argv) | 1464 typval_T *argv) |
1449 { | 1465 { |
1450 typval_T rettv; | 1466 typval_T rettv; |
1451 int dummy; | 1467 int dummy; |
1468 | |
1469 if (safe_to_invoke_callback == 0) | |
1470 EMSG("INTERNAL: Invoking callback when it is not safe"); | |
1452 | 1471 |
1453 argv[0].v_type = VAR_CHANNEL; | 1472 argv[0].v_type = VAR_CHANNEL; |
1454 argv[0].vval.v_channel = channel; | 1473 argv[0].vval.v_channel = channel; |
1455 | 1474 |
1456 call_func(callback, (int)STRLEN(callback), | 1475 call_func(callback, (int)STRLEN(callback), |
3513 channel_T *channel = first_channel; | 3532 channel_T *channel = first_channel; |
3514 int ret = FALSE; | 3533 int ret = FALSE; |
3515 int r; | 3534 int r; |
3516 int part = PART_SOCK; | 3535 int part = PART_SOCK; |
3517 | 3536 |
3537 ++safe_to_invoke_callback; | |
3538 | |
3518 /* Only do this message when another message was given, otherwise we get | 3539 /* Only do this message when another message was given, otherwise we get |
3519 * lots of them. */ | 3540 * lots of them. */ |
3520 if (did_log_msg) | 3541 if (did_log_msg) |
3521 { | 3542 { |
3522 ch_log(NULL, "looking for messages on channels"); | 3543 ch_log(NULL, "looking for messages on channels"); |
3527 if (channel->ch_to_be_closed) | 3548 if (channel->ch_to_be_closed) |
3528 { | 3549 { |
3529 channel->ch_to_be_closed = FALSE; | 3550 channel->ch_to_be_closed = FALSE; |
3530 channel_close_now(channel); | 3551 channel_close_now(channel); |
3531 /* channel may have been freed, start over */ | 3552 /* channel may have been freed, start over */ |
3553 channel = first_channel; | |
3554 continue; | |
3555 } | |
3556 if (channel->ch_to_be_freed) | |
3557 { | |
3558 channel_free(channel); | |
3559 /* channel has been freed, start over */ | |
3532 channel = first_channel; | 3560 channel = first_channel; |
3533 continue; | 3561 continue; |
3534 } | 3562 } |
3535 if (channel->ch_refcount == 0 && !channel_still_useful(channel)) | 3563 if (channel->ch_refcount == 0 && !channel_still_useful(channel)) |
3536 { | 3564 { |
3569 if (channel_need_redraw) | 3597 if (channel_need_redraw) |
3570 { | 3598 { |
3571 channel_need_redraw = FALSE; | 3599 channel_need_redraw = FALSE; |
3572 redraw_after_callback(); | 3600 redraw_after_callback(); |
3573 } | 3601 } |
3602 | |
3603 --safe_to_invoke_callback; | |
3574 | 3604 |
3575 return ret; | 3605 return ret; |
3576 } | 3606 } |
3577 | 3607 |
3578 /* | 3608 /* |