summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-05-09 17:20:14 +0200
committerBram Moolenaar <Bram@vim.org>2016-05-09 17:20:14 +0200
commitcf7ff70ca73218d618e7c00ab785bcf5f9120a94 (patch)
treebec7eebb977f3b4df90ef0b6a89ccb178cfa1626
parent5d96e3ae534ade8ed09a5de9ff8fd7519537ec28 (diff)
downloadvim-git-cf7ff70ca73218d618e7c00ab785bcf5f9120a94.tar.gz
patch 7.4.1826v7.4.1826
Problem: Callbacks are invoked when it's not safe. (Andrew Stewart) Solution: When a channel is to be closed don't invoke callbacks right away, wait for a safe moment.
-rw-r--r--src/channel.c21
-rw-r--r--src/structs.h3
-rw-r--r--src/version.c2
3 files changed, 24 insertions, 2 deletions
diff --git a/src/channel.c b/src/channel.c
index 843323622..159a3a036 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -2782,7 +2782,8 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
channel_close_on_error(channel_T *channel, char *func)
{
/* Do not call emsg(), most likely the other end just exited. */
- ch_errors(channel, "%s(): Cannot read from channel", func);
+ ch_errors(channel, "%s(): Cannot read from channel, will close it soon",
+ func);
/* Queue a "DETACH" netbeans message in the command queue in order to
* terminate the netbeans session later. Do not end the session here
@@ -2800,7 +2801,15 @@ channel_close_on_error(channel_T *channel, char *func)
(int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
/* When reading from stdout is not possible, assume the other side has
- * died. */
+ * died. Don't close the channel right away, it may be the wrong moment
+ * to invoke callbacks. */
+ channel->ch_to_be_closed = TRUE;
+}
+
+ static void
+channel_close_now(channel_T *channel)
+{
+ ch_log(channel, "Closing channel because of previous read error");
channel_close(channel, TRUE);
if (channel->ch_nb_close_cb != NULL)
(*channel->ch_nb_close_cb)();
@@ -3515,6 +3524,14 @@ channel_parse_messages(void)
}
while (channel != NULL)
{
+ if (channel->ch_to_be_closed)
+ {
+ channel->ch_to_be_closed = FALSE;
+ channel_close_now(channel);
+ /* channel may have been freed, start over */
+ channel = first_channel;
+ continue;
+ }
if (channel->ch_refcount == 0 && !channel_still_useful(channel))
{
/* channel is no longer useful, free it */
diff --git a/src/structs.h b/src/structs.h
index 50901acd5..a2b38bffd 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1416,6 +1416,9 @@ struct channel_S {
char *ch_hostname; /* only for socket, allocated */
int ch_port; /* only for socket */
+ 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_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 a6f85c3e3..373aff2dd 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 */
/**/
+ 1826,
+/**/
1825,
/**/
1824,