@@ -59,6 +59,9 @@ static void channel_read(channel_T *channel, int part, char *func);
5959/* Whether a redraw is needed for appending a line to a buffer. */
6060static int channel_need_redraw = FALSE;
6161
62+ /* Whether we are inside channel_parse_messages() or another situation where it
63+ * is safe to invoke callbacks. */
64+ static int safe_to_invoke_callback = 0 ;
6265
6366#ifdef WIN32
6467 static int
@@ -403,8 +406,15 @@ channel_free(channel_T *channel)
403406{
404407 if (!in_free_unref_items )
405408 {
406- channel_free_contents (channel );
407- channel_free_channel (channel );
409+ if (safe_to_invoke_callback == 0 )
410+ {
411+ channel -> ch_to_be_freed = TRUE;
412+ }
413+ else
414+ {
415+ channel_free_contents (channel );
416+ channel_free_channel (channel );
417+ }
408418 }
409419}
410420
@@ -444,6 +454,10 @@ free_unused_channels_contents(int copyID, int mask)
444454 int did_free = FALSE;
445455 channel_T * ch ;
446456
457+ /* This is invoked from the garbage collector, which only runs at a safe
458+ * point. */
459+ ++ safe_to_invoke_callback ;
460+
447461 for (ch = first_channel ; ch != NULL ; ch = ch -> ch_next )
448462 if (!channel_still_useful (ch )
449463 && (ch -> ch_copyID & mask ) != (copyID & mask ))
@@ -453,6 +467,8 @@ free_unused_channels_contents(int copyID, int mask)
453467 channel_free_contents (ch );
454468 did_free = TRUE;
455469 }
470+
471+ -- safe_to_invoke_callback ;
456472 return did_free ;
457473}
458474
@@ -1450,6 +1466,9 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
14501466 typval_T rettv ;
14511467 int dummy ;
14521468
1469+ if (safe_to_invoke_callback == 0 )
1470+ EMSG ("INTERNAL: Invoking callback when it is not safe" );
1471+
14531472 argv [0 ].v_type = VAR_CHANNEL ;
14541473 argv [0 ].vval .v_channel = channel ;
14551474
@@ -3515,6 +3534,8 @@ channel_parse_messages(void)
35153534 int r ;
35163535 int part = PART_SOCK ;
35173536
3537+ ++ safe_to_invoke_callback ;
3538+
35183539 /* Only do this message when another message was given, otherwise we get
35193540 * lots of them. */
35203541 if (did_log_msg )
@@ -3532,6 +3553,13 @@ channel_parse_messages(void)
35323553 channel = first_channel ;
35333554 continue ;
35343555 }
3556+ if (channel -> ch_to_be_freed )
3557+ {
3558+ channel_free (channel );
3559+ /* channel has been freed, start over */
3560+ channel = first_channel ;
3561+ continue ;
3562+ }
35353563 if (channel -> ch_refcount == 0 && !channel_still_useful (channel ))
35363564 {
35373565 /* channel is no longer useful, free it */
@@ -3572,6 +3600,8 @@ channel_parse_messages(void)
35723600 redraw_after_callback ();
35733601 }
35743602
3603+ -- safe_to_invoke_callback ;
3604+
35753605 return ret ;
35763606}
35773607
0 commit comments