diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-05-09 17:58:04 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-05-09 17:58:04 +0200 |
commit | fb6ffc732e65dbc459c89247ff78134402f1a18b (patch) | |
tree | 4c29f995f7ea77f4426e057fa2bf9e5b6eea0cb8 | |
parent | cf7ff70ca73218d618e7c00ab785bcf5f9120a94 (diff) | |
download | vim-fb6ffc732e65dbc459c89247ff78134402f1a18b.zip |
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.
-rw-r--r-- | src/channel.c | 34 | ||||
-rw-r--r-- | src/structs.h | 2 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 36 insertions, 2 deletions
diff --git a/src/channel.c b/src/channel.c index 159a3a036..a7f4c4b8c 100644 --- a/src/channel.c +++ b/src/channel.c @@ -59,6 +59,9 @@ static void channel_read(channel_T *channel, int part, char *func); /* 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 mask) 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, int mask) channel_free_contents(ch); did_free = TRUE; } + + --safe_to_invoke_callback; return did_free; } @@ -1450,6 +1466,9 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial, 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; } diff --git a/src/structs.h b/src/structs.h index a2b38bffd..24d819bf5 100644 --- 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 diff --git a/src/version.c b/src/version.c index 373aff2dd..266e59148 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1827, +/**/ 1826, /**/ 1825, |