Skip to content

Commit c8dcbb1

Browse files
committed
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.
1 parent d2227a0 commit c8dcbb1

File tree

4 files changed

+40
-4
lines changed

4 files changed

+40
-4
lines changed

src/channel.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,31 @@ add_channel(void)
306306
return channel;
307307
}
308308

309+
/*
310+
* Return TRUE if "channel" has a callback.
311+
*/
312+
static int
313+
channel_has_callback(channel_T *channel)
314+
{
315+
return channel->ch_callback != NULL
316+
#ifdef CHANNEL_PIPES
317+
|| channel->ch_part[PART_OUT].ch_callback != NULL
318+
|| channel->ch_part[PART_ERR].ch_callback != NULL
319+
#endif
320+
|| channel->ch_close_cb != NULL;
321+
}
322+
323+
/*
324+
* Close a channel and free all its resources if there is no further action
325+
* possible, there is no callback to be invoked.
326+
*/
327+
void
328+
channel_may_free(channel_T *channel)
329+
{
330+
if (!channel_has_callback(channel))
331+
channel_free(channel);
332+
}
333+
309334
/*
310335
* Close a channel and free all its resources.
311336
*/
@@ -1463,7 +1488,7 @@ channel_status(channel_T *channel)
14631488

14641489
/*
14651490
* Close channel "channel".
1466-
* This does not trigger the close callback.
1491+
* Trigger the close callback if "invoke_close_cb" is TRUE.
14671492
*/
14681493
void
14691494
channel_close(channel_T *channel, int invoke_close_cb)
@@ -2149,6 +2174,14 @@ channel_parse_messages(void)
21492174

21502175
while (channel != NULL)
21512176
{
2177+
if (channel->ch_refcount == 0 && !channel_has_callback(channel))
2178+
{
2179+
/* channel is no longer useful, free it */
2180+
channel_free(channel);
2181+
channel = first_channel;
2182+
part = PART_SOCK;
2183+
continue;
2184+
}
21522185
if (channel->ch_part[part].ch_fd != INVALID_FD)
21532186
{
21542187
/* Increase the refcount, in case the handler causes the channel

src/eval.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7745,16 +7745,16 @@ get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
77457745

77467746
#if defined(FEAT_CHANNEL) || defined(PROTO)
77477747
/*
7748-
* Decrement the reference count on "channel" and free it when it goes down to
7749-
* zero.
7748+
* Decrement the reference count on "channel" and maybe free it when it goes
7749+
* down to zero. Don't free it if there is a pending action.
77507750
* Returns TRUE when the channel was freed.
77517751
*/
77527752
int
77537753
channel_unref(channel_T *channel)
77547754
{
77557755
if (channel != NULL && --channel->ch_refcount <= 0)
77567756
{
7757-
channel_free(channel);
7757+
channel_may_free(channel);
77587758
return TRUE;
77597759
}
77607760
return FALSE;

src/proto/channel.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ int ch_log_active(void);
44
void ch_log(channel_T *ch, char *msg);
55
void ch_logs(channel_T *ch, char *msg, char *name);
66
channel_T *add_channel(void);
7+
void channel_may_free(channel_T *channel);
78
void channel_free(channel_T *channel);
89
void channel_gui_register(channel_T *channel);
910
void channel_gui_register_all(void);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ static char *(features[]) =
748748

749749
static int included_patches[] =
750750
{ /* Add new patch number below this line */
751+
/**/
752+
1421,
751753
/**/
752754
1420,
753755
/**/

0 commit comments

Comments
 (0)