To: vim_dev@googlegroups.com Subject: Patch 8.0.1761 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1761 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) Files: src/channel.c, src/os_unix.c, src/testdir/test_channel.vim *** ../vim-8.0.1760/src/channel.c 2018-04-21 23:34:38.522654097 +0200 --- src/channel.c 2018-04-24 20:47:41.251850354 +0200 *************** *** 345,350 **** --- 345,359 ---- } /* + * 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. */ static void *************** *** 892,898 **** channel->ch_nb_close_cb = nb_close_cb; channel->ch_hostname = (char *)vim_strsave((char_u *)hostname); channel->ch_port = port_in; ! channel->ch_to_be_closed |= (1 << PART_SOCK); #ifdef FEAT_GUI channel_gui_register_one(channel, PART_SOCK); --- 901,907 ---- channel->ch_nb_close_cb = nb_close_cb; channel->ch_hostname = (char *)vim_strsave((char_u *)hostname); channel->ch_port = port_in; ! channel->ch_to_be_closed |= (1U << PART_SOCK); #ifdef FEAT_GUI channel_gui_register_one(channel, PART_SOCK); *************** *** 988,994 **** } *fd = INVALID_FD; ! channel->ch_to_be_closed &= ~(1 << part); } } --- 997,1004 ---- } *fd = INVALID_FD; ! /* channel is closed, may want to end the job if it was the last */ ! channel->ch_to_be_closed &= ~(1U << part); } } *************** *** 999,1004 **** --- 1009,1020 ---- { ch_close_part(channel, PART_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) { *************** *** 1007,1013 **** # endif ch_close_part(channel, PART_OUT); channel->CH_OUT_FD = out; ! channel->ch_to_be_closed |= (1 << PART_OUT); # if defined(FEAT_GUI) channel_gui_register_one(channel, PART_OUT); # endif --- 1023,1029 ---- # endif ch_close_part(channel, PART_OUT); channel->CH_OUT_FD = out; ! channel->ch_to_be_closed |= (1U << PART_OUT); # if defined(FEAT_GUI) channel_gui_register_one(channel, PART_OUT); # endif *************** *** 1019,1025 **** # endif ch_close_part(channel, PART_ERR); channel->CH_ERR_FD = err; ! channel->ch_to_be_closed |= (1 << PART_ERR); # if defined(FEAT_GUI) channel_gui_register_one(channel, PART_ERR); # endif --- 1035,1041 ---- # endif ch_close_part(channel, PART_ERR); channel->CH_ERR_FD = err; ! channel->ch_to_be_closed |= (1U << PART_ERR); # if defined(FEAT_GUI) channel_gui_register_one(channel, PART_ERR); # endif *************** *** 4200,4208 **** } while (channel != NULL) { ! if (channel->ch_to_be_closed == 0) { ! channel->ch_to_be_closed = (1 << PART_COUNT); channel_close_now(channel); /* channel may have been freed, start over */ channel = first_channel; --- 4216,4224 ---- } while (channel != NULL) { ! if (channel_can_close(channel)) { ! channel->ch_to_be_closed = (1U << PART_COUNT); channel_close_now(channel); /* channel may have been freed, start over */ channel = first_channel; *************** *** 5080,5085 **** --- 5096,5110 ---- } /* + * 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 * it has not ended yet and there is a "stoponexit" flag, an exit callback * or when the associated channel will do something with the job output. *************** *** 5209,5214 **** --- 5234,5243 ---- /* Ready to cleanup the job. */ 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) { typval_T argv[3]; *************** *** 5413,5420 **** for (job = first_job; job != NULL; job = job->jv_next) /* Only should check if the channel has been closed, if the channel is * open the job won't exit. */ ! if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL ! && !job_channel_still_useful(job)) return TRUE; return FALSE; } --- 5442,5450 ---- for (job = first_job; job != NULL; job = job->jv_next) /* Only should check if the channel has been closed, if the channel is * open the job won't exit. */ ! if ((job->jv_status == JOB_STARTED && !job_channel_still_useful(job)) ! || (job->jv_status == JOB_FINISHED ! && job_channel_can_close(job))) return TRUE; return FALSE; } *** ../vim-8.0.1760/src/os_unix.c 2018-04-24 15:19:00.507068755 +0200 --- src/os_unix.c 2018-04-24 20:42:04.561485179 +0200 *************** *** 5638,5650 **** close(fd_err[1]); if (channel != NULL) { ! channel_set_pipes(channel, ! use_file_for_in || use_null_for_in ! ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1], ! use_file_for_out || use_null_for_out ! ? INVALID_FD : fd_out[0] < 0 ? pty_master_fd : fd_out[0], ! use_out_for_err || use_file_for_err || use_null_for_err ! ? INVALID_FD : fd_err[0] < 0 ? pty_master_fd : fd_err[0]); channel_set_job(channel, job, options); } else --- 5638,5651 ---- close(fd_err[1]); if (channel != NULL) { ! int in_fd = use_file_for_in || use_null_for_in ! ? INVALID_FD : fd_in[1] < 0 ? pty_master_fd : fd_in[1]; ! int out_fd = use_file_for_out || use_null_for_out ! ? 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 ! ? 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); } else *** ../vim-8.0.1760/src/testdir/test_channel.vim 2018-04-21 19:49:02.528104537 +0200 --- src/testdir/test_channel.vim 2018-04-24 20:42:04.565485223 +0200 *************** *** 1848,1850 **** --- 1848,1861 ---- call assert_match("%s%s", text[2]) call delete('Xlog') 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 *** ../vim-8.0.1760/src/version.c 2018-04-24 20:27:22.912114599 +0200 --- src/version.c 2018-04-24 20:49:27.656178358 +0200 *************** *** 763,764 **** --- 763,766 ---- { /* Add new patch number below this line */ + /**/ + 1761, /**/ -- We're knights of the Round Table Our shows are formidable But many times We're given rhymes That are quite unsingable We're opera mad in Camelot We sing from the diaphragm a lot. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///