mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.0.1761: job in terminal window with no output channel is killed
Problem: Job in terminal window with no output channel is killed. Solution: Keep the job running when the input is a tty. (Ozaki Kiichi, closes #2734)
This commit is contained in:
@@ -344,6 +344,15 @@ channel_still_useful(channel_T *channel)
|
|||||||
&& has_err_msg);
|
&& has_err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return TRUE if "channel" is closeable (i.e. all readable fds are closed).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
channel_can_close(channel_T *channel)
|
||||||
|
{
|
||||||
|
return channel->ch_to_be_closed == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a channel and free all its resources.
|
* Close a channel and free all its resources.
|
||||||
*/
|
*/
|
||||||
@@ -892,7 +901,7 @@ channel_open(
|
|||||||
channel->ch_nb_close_cb = nb_close_cb;
|
channel->ch_nb_close_cb = nb_close_cb;
|
||||||
channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
|
channel->ch_hostname = (char *)vim_strsave((char_u *)hostname);
|
||||||
channel->ch_port = port_in;
|
channel->ch_port = port_in;
|
||||||
channel->ch_to_be_closed |= (1 << PART_SOCK);
|
channel->ch_to_be_closed |= (1U << PART_SOCK);
|
||||||
|
|
||||||
#ifdef FEAT_GUI
|
#ifdef FEAT_GUI
|
||||||
channel_gui_register_one(channel, PART_SOCK);
|
channel_gui_register_one(channel, PART_SOCK);
|
||||||
@@ -988,7 +997,8 @@ ch_close_part(channel_T *channel, ch_part_T part)
|
|||||||
}
|
}
|
||||||
*fd = INVALID_FD;
|
*fd = INVALID_FD;
|
||||||
|
|
||||||
channel->ch_to_be_closed &= ~(1 << part);
|
/* channel is closed, may want to end the job if it was the last */
|
||||||
|
channel->ch_to_be_closed &= ~(1U << part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -999,6 +1009,12 @@ channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
|
|||||||
{
|
{
|
||||||
ch_close_part(channel, PART_IN);
|
ch_close_part(channel, PART_IN);
|
||||||
channel->CH_IN_FD = in;
|
channel->CH_IN_FD = in;
|
||||||
|
# if defined(UNIX)
|
||||||
|
/* Do not end the job when all output channels are closed, wait until
|
||||||
|
* the job ended. */
|
||||||
|
if (isatty(in))
|
||||||
|
channel->ch_to_be_closed |= (1U << PART_IN);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
if (out != INVALID_FD)
|
if (out != INVALID_FD)
|
||||||
{
|
{
|
||||||
@@ -1007,7 +1023,7 @@ channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
|
|||||||
# endif
|
# endif
|
||||||
ch_close_part(channel, PART_OUT);
|
ch_close_part(channel, PART_OUT);
|
||||||
channel->CH_OUT_FD = out;
|
channel->CH_OUT_FD = out;
|
||||||
channel->ch_to_be_closed |= (1 << PART_OUT);
|
channel->ch_to_be_closed |= (1U << PART_OUT);
|
||||||
# if defined(FEAT_GUI)
|
# if defined(FEAT_GUI)
|
||||||
channel_gui_register_one(channel, PART_OUT);
|
channel_gui_register_one(channel, PART_OUT);
|
||||||
# endif
|
# endif
|
||||||
@@ -1019,7 +1035,7 @@ channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
|
|||||||
# endif
|
# endif
|
||||||
ch_close_part(channel, PART_ERR);
|
ch_close_part(channel, PART_ERR);
|
||||||
channel->CH_ERR_FD = err;
|
channel->CH_ERR_FD = err;
|
||||||
channel->ch_to_be_closed |= (1 << PART_ERR);
|
channel->ch_to_be_closed |= (1U << PART_ERR);
|
||||||
# if defined(FEAT_GUI)
|
# if defined(FEAT_GUI)
|
||||||
channel_gui_register_one(channel, PART_ERR);
|
channel_gui_register_one(channel, PART_ERR);
|
||||||
# endif
|
# endif
|
||||||
@@ -4200,9 +4216,9 @@ channel_parse_messages(void)
|
|||||||
}
|
}
|
||||||
while (channel != NULL)
|
while (channel != NULL)
|
||||||
{
|
{
|
||||||
if (channel->ch_to_be_closed == 0)
|
if (channel_can_close(channel))
|
||||||
{
|
{
|
||||||
channel->ch_to_be_closed = (1 << PART_COUNT);
|
channel->ch_to_be_closed = (1U << PART_COUNT);
|
||||||
channel_close_now(channel);
|
channel_close_now(channel);
|
||||||
/* channel may have been freed, start over */
|
/* channel may have been freed, start over */
|
||||||
channel = first_channel;
|
channel = first_channel;
|
||||||
@@ -5079,6 +5095,15 @@ job_channel_still_useful(job_T *job)
|
|||||||
return job->jv_channel != NULL && channel_still_useful(job->jv_channel);
|
return job->jv_channel != NULL && channel_still_useful(job->jv_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return TRUE if the channel of "job" is closeable.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
job_channel_can_close(job_T *job)
|
||||||
|
{
|
||||||
|
return job->jv_channel != NULL && channel_can_close(job->jv_channel);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE if the job should not be freed yet. Do not free the job when
|
* Return TRUE if the job should not be freed yet. Do not free the job when
|
||||||
* it has not ended yet and there is a "stoponexit" flag, an exit callback
|
* it has not ended yet and there is a "stoponexit" flag, an exit callback
|
||||||
@@ -5209,6 +5234,10 @@ job_cleanup(job_T *job)
|
|||||||
/* Ready to cleanup the job. */
|
/* Ready to cleanup the job. */
|
||||||
job->jv_status = JOB_FINISHED;
|
job->jv_status = JOB_FINISHED;
|
||||||
|
|
||||||
|
/* When only channel-in is kept open, close explicitly. */
|
||||||
|
if (job->jv_channel != NULL)
|
||||||
|
ch_close_part(job->jv_channel, PART_IN);
|
||||||
|
|
||||||
if (job->jv_exit_cb != NULL)
|
if (job->jv_exit_cb != NULL)
|
||||||
{
|
{
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
@@ -5413,8 +5442,9 @@ has_pending_job(void)
|
|||||||
for (job = first_job; job != NULL; job = job->jv_next)
|
for (job = first_job; job != NULL; job = job->jv_next)
|
||||||
/* Only should check if the channel has been closed, if the channel is
|
/* Only should check if the channel has been closed, if the channel is
|
||||||
* open the job won't exit. */
|
* open the job won't exit. */
|
||||||
if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL
|
if ((job->jv_status == JOB_STARTED && !job_channel_still_useful(job))
|
||||||
&& !job_channel_still_useful(job))
|
|| (job->jv_status == JOB_FINISHED
|
||||||
|
&& job_channel_can_close(job)))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@@ -5638,13 +5638,14 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
|
|||||||
close(fd_err[1]);
|
close(fd_err[1]);
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
channel_set_pipes(channel,
|
int in_fd = use_file_for_in || use_null_for_in
|
||||||
use_file_for_in || use_null_for_in
|
? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1];
|
||||||
? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1],
|
int out_fd = use_file_for_out || use_null_for_out
|
||||||
use_file_for_out || use_null_for_out
|
? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0];
|
||||||
? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0],
|
int err_fd = use_out_for_err || use_file_for_err || use_null_for_err
|
||||||
use_out_for_err || use_file_for_err || use_null_for_err
|
? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0];
|
||||||
? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0]);
|
|
||||||
|
channel_set_pipes(channel, in_fd, out_fd, err_fd);
|
||||||
channel_set_job(channel, job, options);
|
channel_set_job(channel, job, options);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -1848,3 +1848,14 @@ func Test_zz_ch_log()
|
|||||||
call assert_match("%s%s", text[2])
|
call assert_match("%s%s", text[2])
|
||||||
call delete('Xlog')
|
call delete('Xlog')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_keep_pty_open()
|
||||||
|
if !has('unix')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"', {'out_io': 'null', 'err_io': 'null', 'pty': 1})
|
||||||
|
let elapsed = WaitFor({-> job_status(job) ==# 'dead'})
|
||||||
|
call assert_inrange(200, 1000, elapsed)
|
||||||
|
call job_stop(job)
|
||||||
|
endfunc
|
||||||
|
@@ -761,6 +761,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1761,
|
||||||
/**/
|
/**/
|
||||||
1760,
|
1760,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user