Skip to content

Commit

Permalink
patch 8.2.3640: freeze when calling term_wait() in a close callback
Browse files Browse the repository at this point in the history
Problem:    Freeze when calling term_wait() in a close callback.
Solution:   Set a "closing" flag to tell term_wait() to return. (closes vim#9152)
  • Loading branch information
brammool committed Nov 21, 2021
1 parent 7f0c4b4 commit eea32af
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -3156,6 +3156,10 @@ channel_close(channel_T *channel, int invoke_close_cb)
{
ch_part_T part;

#ifdef FEAT_TERMINAL
// let the terminal know it is closing to avoid getting stuck
term_channel_closing(channel);
#endif
// Invoke callbacks and flush buffers before the close callback.
if (channel->ch_close_cb.cb_name != NULL)
ch_log(channel,
Expand Down
1 change: 1 addition & 0 deletions src/proto/terminal.pro
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ int term_use_loop(void);
void term_win_entered(void);
int terminal_loop(int blocking);
int may_close_term_popup(void);
void term_channel_closing(channel_T *ch);
void term_channel_closed(channel_T *ch);
void term_check_channel_closed_recently(void);
int term_do_update_window(win_T *wp);
Expand Down
18 changes: 18 additions & 0 deletions src/terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ struct terminal_S {
int tl_vterm_size_changed;

int tl_normal_mode; // TRUE: Terminal-Normal mode
int tl_channel_closing;
int tl_channel_closed;
int tl_channel_recently_closed; // still need to handle tl_finish

Expand Down Expand Up @@ -3458,6 +3459,20 @@ may_close_term_popup(void)
}
#endif

/*
* Called when a channel is going to be closed, before invoking the close
* callback.
*/
void
term_channel_closing(channel_T *ch)
{
term_T *term;

for (term = first_term; term != NULL; term = term->tl_next)
if (term->tl_job == ch->ch_job && !term->tl_channel_closed)
term->tl_channel_closing = TRUE;
}

/*
* Called when a channel has been closed.
* If this was a channel for a terminal window then finish it up.
Expand Down Expand Up @@ -6438,6 +6453,9 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
// If the terminal is closed when the channel is closed the
// buffer disappears.
break;
if (buf->b_term == NULL || buf->b_term->tl_channel_closing)
// came here from a close callback, only wait one time
break;
}

term_flush_messages();
Expand Down
17 changes: 17 additions & 0 deletions src/testdir/test_terminal.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2058,5 +2058,22 @@ func Test_terminal_adds_jump()
bwipe!
endfunc

func Close_cb(ch, ctx)
call term_wait(a:ctx.bufnr)
let g:close_done = 'done'
endfunc

func Test_term_wait_in_close_cb()
let g:close_done = ''
let ctx = {}
let ctx.bufnr = term_start('echo "HELLO WORLD"',
\ {'close_cb': {ch -> Close_cb(ch, ctx)}})

call WaitForAssert({-> assert_equal("done", g:close_done)})

unlet g:close_done
bwipe!
endfunc


" vim: shiftwidth=2 sts=2 expandtab
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3640,
/**/
3639,
/**/
Expand Down

0 comments on commit eea32af

Please sign in to comment.