]> granicus.if.org Git - vim/commitdiff
patch 7.4.1421 v7.4.1421
authorBram Moolenaar <Bram@vim.org>
Thu, 25 Feb 2016 22:10:17 +0000 (23:10 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 25 Feb 2016 22:10:17 +0000 (23:10 +0100)
Problem:    May free a channel when a callback may need to be invoked.
Solution:   Keep the channel when refcount is zero.

src/channel.c
src/eval.c
src/proto/channel.pro
src/version.c

index 8044c4d2d371be38493b124e0cf82739efdbafd3..4a2b20c442ca334245a6c39c1643e1069bcbc695 100644 (file)
@@ -306,6 +306,31 @@ add_channel(void)
     return channel;
 }
 
+/*
+ * Return TRUE if "channel" has a callback.
+ */
+    static int
+channel_has_callback(channel_T *channel)
+{
+    return channel->ch_callback != NULL
+#ifdef CHANNEL_PIPES
+           || channel->ch_part[PART_OUT].ch_callback != NULL
+           || channel->ch_part[PART_ERR].ch_callback != NULL
+#endif
+           || channel->ch_close_cb != NULL;
+}
+
+/*
+ * Close a channel and free all its resources if there is no further action
+ * possible, there is no callback to be invoked.
+ */
+    void
+channel_may_free(channel_T *channel)
+{
+    if (!channel_has_callback(channel))
+       channel_free(channel);
+}
+
 /*
  * Close a channel and free all its resources.
  */
@@ -1463,7 +1488,7 @@ channel_status(channel_T *channel)
 
 /*
  * Close channel "channel".
- * This does not trigger the close callback.
+ * Trigger the close callback if "invoke_close_cb" is TRUE.
  */
     void
 channel_close(channel_T *channel, int invoke_close_cb)
@@ -2149,6 +2174,14 @@ channel_parse_messages(void)
 
     while (channel != NULL)
     {
+       if (channel->ch_refcount == 0 && !channel_has_callback(channel))
+       {
+           /* channel is no longer useful, free it */
+           channel_free(channel);
+           channel = first_channel;
+           part = PART_SOCK;
+           continue;
+       }
        if (channel->ch_part[part].ch_fd != INVALID_FD)
        {
            /* Increase the refcount, in case the handler causes the channel
index db9c6b7543c069c5e1a0c78c88254919df703897..0db6cfac535ebb3290782be25d8eea53789a07c5 100644 (file)
@@ -7745,8 +7745,8 @@ failret:
 
 #if defined(FEAT_CHANNEL) || defined(PROTO)
 /*
- * Decrement the reference count on "channel" and free it when it goes down to
- * zero.
+ * Decrement the reference count on "channel" and maybe free it when it goes
+ * down to zero.  Don't free it if there is a pending action.
  * Returns TRUE when the channel was freed.
  */
     int
@@ -7754,7 +7754,7 @@ channel_unref(channel_T *channel)
 {
     if (channel != NULL && --channel->ch_refcount <= 0)
     {
-       channel_free(channel);
+       channel_may_free(channel);
        return TRUE;
     }
     return FALSE;
index 96b51b9773ce988179f2af175f358c3d69418f2f..8dc4ad44d1ad81da32b80096c185d50c794ae694 100644 (file)
@@ -4,6 +4,7 @@ int ch_log_active(void);
 void ch_log(channel_T *ch, char *msg);
 void ch_logs(channel_T *ch, char *msg, char *name);
 channel_T *add_channel(void);
+void channel_may_free(channel_T *channel);
 void channel_free(channel_T *channel);
 void channel_gui_register(channel_T *channel);
 void channel_gui_register_all(void);
index de20c3e1b69391c448df5e5f872cac506b83dfc3..42200012a4420633eba2dc3a35b05b2c4c12e3c0 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1421,
 /**/
     1420,
 /**/