# HG changeset patch # User Bram Moolenaar # Date 1637506804 -3600 # Node ID d25c0b0aad7da403a3164d89fa93384320382ec4 # Parent 285b3f4de8a9fccab7df9edee898eb77bd678f39 patch 8.2.3640: freeze when calling term_wait() in a close callback Commit: https://github.com/vim/vim/commit/eea32afdb83ae281a63152f7494f79ec7e45ff55 Author: Bram Moolenaar Date: Sun Nov 21 14:51:13 2021 +0000 patch 8.2.3640: freeze when calling term_wait() in a close callback Problem: Freeze when calling term_wait() in a close callback. Solution: Set a "closing" flag to tell term_wait() to return. (closes https://github.com/vim/vim/issues/9152) diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -3156,6 +3156,10 @@ channel_close(channel_T *channel, int in { 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, diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -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); diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -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 @@ -3459,6 +3460,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. */ @@ -6438,6 +6453,9 @@ f_term_wait(typval_T *argvars, typval_T // 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(); diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -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 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3640, +/**/ 3639, /**/ 3638,