summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/channel.c35
-rw-r--r--src/eval.c6
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/version.c2
4 files changed, 40 insertions, 4 deletions
diff --git a/src/channel.c b/src/channel.c
index 8044c4d2d..4a2b20c44 100644
--- 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
diff --git a/src/eval.c b/src/eval.c
index db9c6b754..0db6cfac5 100644
--- 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;
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 96b51b977..8dc4ad44d 100644
--- 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);
diff --git a/src/version.c b/src/version.c
index de20c3e1b..42200012a 100644
--- 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,