]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 7.4.1826 v7.4.1826
authorBram Moolenaar <Bram@vim.org>
Mon, 9 May 2016 15:20:14 +0000 (17:20 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 9 May 2016 15:20:14 +0000 (17:20 +0200)
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.

src/channel.c
src/structs.h
src/version.c

index 8433236227cf61d4a8e11eb9cfcae7df94d2040c..159a3a036802dd80bad5561709167997203812e4 100644 (file)
@@ -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 */
index 50901acd5760dfc00acf2866374804282cc16d28..a2b38bffd8cc0df384cb465e108a926dedad11a2 100644 (file)
@@ -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
index a6f85c3e327fc73f1cf0d710725de1f7cc1e172d..373aff2dd00f0f6857d66a11be9ca3a9d91bf568 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1826,
 /**/
     1825,
 /**/