mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.1.0845: having job_status() free the job causes problems
Problem: Having job_status() free the job causes problems. Solution: Do not actually free the job or terminal yet, put it in a list and free it a bit later. Do not use a terminal after checking the job status. (closes #3873)
This commit is contained in:
@@ -803,10 +803,17 @@ free_scrollback(term_T *term)
|
||||
ga_clear(&term->tl_scrollback);
|
||||
}
|
||||
|
||||
|
||||
// Terminals that need to be freed soon.
|
||||
term_T *terminals_to_free = NULL;
|
||||
|
||||
/*
|
||||
* Free a terminal and everything it refers to.
|
||||
* Kills the job if there is one.
|
||||
* Called when wiping out a buffer.
|
||||
* The actual terminal structure is freed later in free_unused_terminals(),
|
||||
* because callbacks may wipe out a buffer while the terminal is still
|
||||
* referenced.
|
||||
*/
|
||||
void
|
||||
free_terminal(buf_T *buf)
|
||||
@@ -816,6 +823,8 @@ free_terminal(buf_T *buf)
|
||||
|
||||
if (term == NULL)
|
||||
return;
|
||||
|
||||
// Unlink the terminal form the list of terminals.
|
||||
if (first_term == term)
|
||||
first_term = term->tl_next;
|
||||
else
|
||||
@@ -834,29 +843,43 @@ free_terminal(buf_T *buf)
|
||||
job_stop(term->tl_job, NULL, "kill");
|
||||
job_unref(term->tl_job);
|
||||
}
|
||||
term->tl_next = terminals_to_free;
|
||||
terminals_to_free = term;
|
||||
|
||||
free_scrollback(term);
|
||||
|
||||
term_free_vterm(term);
|
||||
vim_free(term->tl_title);
|
||||
#ifdef FEAT_SESSION
|
||||
vim_free(term->tl_command);
|
||||
#endif
|
||||
vim_free(term->tl_kill);
|
||||
vim_free(term->tl_status_text);
|
||||
vim_free(term->tl_opencmd);
|
||||
vim_free(term->tl_eof_chars);
|
||||
#ifdef WIN3264
|
||||
if (term->tl_out_fd != NULL)
|
||||
fclose(term->tl_out_fd);
|
||||
#endif
|
||||
vim_free(term->tl_cursor_color);
|
||||
vim_free(term);
|
||||
buf->b_term = NULL;
|
||||
if (in_terminal_loop == term)
|
||||
in_terminal_loop = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
free_unused_terminals()
|
||||
{
|
||||
while (terminals_to_free != NULL)
|
||||
{
|
||||
term_T *term = terminals_to_free;
|
||||
|
||||
terminals_to_free = term->tl_next;
|
||||
|
||||
free_scrollback(term);
|
||||
|
||||
term_free_vterm(term);
|
||||
vim_free(term->tl_title);
|
||||
#ifdef FEAT_SESSION
|
||||
vim_free(term->tl_command);
|
||||
#endif
|
||||
vim_free(term->tl_kill);
|
||||
vim_free(term->tl_status_text);
|
||||
vim_free(term->tl_opencmd);
|
||||
vim_free(term->tl_eof_chars);
|
||||
#ifdef WIN3264
|
||||
if (term->tl_out_fd != NULL)
|
||||
fclose(term->tl_out_fd);
|
||||
#endif
|
||||
vim_free(term->tl_cursor_color);
|
||||
vim_free(term);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the part that is connected to the tty. Normally this is PART_IN, but
|
||||
* when writing buffer lines to the job it can be another. This makes it
|
||||
@@ -1275,6 +1298,7 @@ term_convert_key(term_T *term, int c, char *buf)
|
||||
/*
|
||||
* Return TRUE if the job for "term" is still running.
|
||||
* If "check_job_status" is TRUE update the job status.
|
||||
* NOTE: "term" may be freed by callbacks.
|
||||
*/
|
||||
static int
|
||||
term_job_running_check(term_T *term, int check_job_status)
|
||||
@@ -1285,10 +1309,15 @@ term_job_running_check(term_T *term, int check_job_status)
|
||||
&& term->tl_job != NULL
|
||||
&& channel_is_open(term->tl_job->jv_channel))
|
||||
{
|
||||
job_T *job = term->tl_job;
|
||||
|
||||
// Careful: Checking the job status may invoked callbacks, which close
|
||||
// the buffer and terminate "term". However, "job" will not be freed
|
||||
// yet.
|
||||
if (check_job_status)
|
||||
job_status(term->tl_job);
|
||||
return (term->tl_job->jv_status == JOB_STARTED
|
||||
|| term->tl_job->jv_channel->ch_keep_open);
|
||||
job_status(job);
|
||||
return (job->jv_status == JOB_STARTED
|
||||
|| (job->jv_channel != NULL && job->jv_channel->ch_keep_open));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2151,9 +2180,8 @@ terminal_loop(int blocking)
|
||||
#ifdef FEAT_GUI
|
||||
if (!curbuf->b_term->tl_system)
|
||||
#endif
|
||||
/* TODO: skip screen update when handling a sequence of keys. */
|
||||
/* Repeat redrawing in case a message is received while redrawing.
|
||||
*/
|
||||
// TODO: skip screen update when handling a sequence of keys.
|
||||
// Repeat redrawing in case a message is received while redrawing.
|
||||
while (must_redraw != 0)
|
||||
if (update_screen(0) == FAIL)
|
||||
break;
|
||||
|
Reference in New Issue
Block a user