changeset 8257:c4ffdda8cdfd v7.4.1421

commit https://github.com/vim/vim/commit/c8dcbb12c5d7f3eb0c334daebb4475bb015b91e7 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Feb 25 23:10:17 2016 +0100 patch 7.4.1421 Problem: May free a channel when a callback may need to be invoked. Solution: Keep the channel when refcount is zero.
author Christian Brabandt <cb@256bit.org>
date Thu, 25 Feb 2016 23:15:05 +0100
parents 1a895d499690
children c753d5773e64
files src/channel.c src/eval.c src/proto/channel.pro src/version.c
diffstat 4 files changed, 40 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -307,6 +307,31 @@ add_channel(void)
 }
 
 /*
+ * 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.
  */
     void
@@ -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
--- a/src/eval.c
+++ b/src/eval.c
@@ -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;
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -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);
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1421,
+/**/
     1420,
 /**/
     1419,