Mercurial > vim
changeset 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 | 8d3354777bf1 |
children | 75f46a491f61 |
files | src/channel.c src/structs.h src/version.c |
diffstat | 3 files changed, 36 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/channel.c +++ b/src/channel.c @@ -59,6 +59,9 @@ static void channel_read(channel_T *chan /* Whether a redraw is needed for appending a line to a buffer. */ static int channel_need_redraw = FALSE; +/* Whether we are inside channel_parse_messages() or another situation where it + * is safe to invoke callbacks. */ +static int safe_to_invoke_callback = 0; #ifdef WIN32 static int @@ -403,8 +406,15 @@ channel_free(channel_T *channel) { if (!in_free_unref_items) { - channel_free_contents(channel); - channel_free_channel(channel); + if (safe_to_invoke_callback == 0) + { + channel->ch_to_be_freed = TRUE; + } + else + { + channel_free_contents(channel); + channel_free_channel(channel); + } } } @@ -444,6 +454,10 @@ free_unused_channels_contents(int copyID int did_free = FALSE; channel_T *ch; + /* This is invoked from the garbage collector, which only runs at a safe + * point. */ + ++safe_to_invoke_callback; + for (ch = first_channel; ch != NULL; ch = ch->ch_next) if (!channel_still_useful(ch) && (ch->ch_copyID & mask) != (copyID & mask)) @@ -453,6 +467,8 @@ free_unused_channels_contents(int copyID channel_free_contents(ch); did_free = TRUE; } + + --safe_to_invoke_callback; return did_free; } @@ -1450,6 +1466,9 @@ invoke_callback(channel_T *channel, char typval_T rettv; int dummy; + if (safe_to_invoke_callback == 0) + EMSG("INTERNAL: Invoking callback when it is not safe"); + argv[0].v_type = VAR_CHANNEL; argv[0].vval.v_channel = channel; @@ -3515,6 +3534,8 @@ channel_parse_messages(void) int r; int part = PART_SOCK; + ++safe_to_invoke_callback; + /* Only do this message when another message was given, otherwise we get * lots of them. */ if (did_log_msg) @@ -3532,6 +3553,13 @@ channel_parse_messages(void) channel = first_channel; continue; } + if (channel->ch_to_be_freed) + { + channel_free(channel); + /* channel has been freed, start over */ + channel = first_channel; + continue; + } if (channel->ch_refcount == 0 && !channel_still_useful(channel)) { /* channel is no longer useful, free it */ @@ -3572,6 +3600,8 @@ channel_parse_messages(void) redraw_after_callback(); } + --safe_to_invoke_callback; + return ret; }
--- a/src/structs.h +++ b/src/structs.h @@ -1419,6 +1419,8 @@ struct channel_S { int ch_to_be_closed; /* When TRUE reading or writing failed and * the channel must be closed when it's safe * to invoke callbacks. */ + int ch_to_be_freed; /* When TRUE channel must be freed when it's + * safe to invoke callbacks. */ int ch_error; /* When TRUE an error was reported. Avoids * giving pages full of error messages when * the other side has exited, only mention the