1
0
forked from aniani/vim

patch 8.0.0050

Problem:    An exiting job is detected with a large latency.
Solution:   Check for pending job more often. (Ozaki Kiichi)  Change the
            double loop in mch_inchar() into one.
This commit is contained in:
Bram Moolenaar 2016-10-27 20:00:07 +02:00
parent 2f97912800
commit 01688ad545
5 changed files with 156 additions and 119 deletions

View File

@ -4643,8 +4643,8 @@ job_stop_on_exit(void)
}
/*
* Return TRUE when there is any job that might exit, which means
* job_check_ended() should be called once in a while.
* Return TRUE when there is any job that has an exit callback and might exit,
* which means job_check_ended() should be called more often.
*/
int
has_pending_job(void)
@ -4652,7 +4652,11 @@ has_pending_job(void)
job_T *job;
for (job = first_job; job != NULL; job = job->jv_next)
if (job_still_alive(job))
/* 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->jv_channel == NULL
|| !channel_still_useful(job->jv_channel)))
return TRUE;
return FALSE;
}

View File

@ -404,139 +404,121 @@ mch_inchar(
{
int len;
int interrupted = FALSE;
int did_start_blocking = FALSE;
long wait_time;
long elapsed_time = 0;
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
struct timeval start_tv;
gettimeofday(&start_tv, NULL);
#endif
#ifdef MESSAGE_QUEUE
parse_queued_messages();
#endif
/* Check if window changed size while we were busy, perhaps the ":set
* columns=99" command was used. */
while (do_resize)
handle_resize();
/* repeat until we got a character or waited long enough */
for (;;)
{
if (wtime >= 0)
wait_time = wtime;
else
wait_time = p_ut;
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
wait_time -= elapsed(&start_tv);
if (wait_time >= 0)
{
#endif
if (WaitForChar(wait_time, &interrupted))
break;
/* no character available */
if (do_resize)
{
handle_resize();
continue;
}
#ifdef FEAT_CLIENTSERVER
if (server_waiting())
{
parse_queued_messages();
continue;
}
#endif
#ifdef MESSAGE_QUEUE
if (interrupted)
{
parse_queued_messages();
continue;
}
#endif
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
}
#endif
if (wtime >= 0)
/* no character available within "wtime" */
return 0;
/* wtime == -1: no character available within 'updatetime' */
#ifdef FEAT_AUTOCMD
if (trigger_cursorhold() && maxlen >= 3
&& !typebuf_changed(tb_change_cnt))
{
buf[0] = K_SPECIAL;
buf[1] = KS_EXTRA;
buf[2] = (int)KE_CURSORHOLD;
return 3;
}
#endif
/*
* If there is no character available within 'updatetime' seconds
* flush all the swap files to disk.
* Also done when interrupted by SIGWINCH.
*/
before_blocking();
break;
}
/* repeat until we got a character */
for (;;)
{
long wtime_now = -1L;
while (do_resize) /* window changed size */
/* Check if window changed size while we were busy, perhaps the ":set
* columns=99" command was used. */
while (do_resize)
handle_resize();
#ifdef MESSAGE_QUEUE
parse_queued_messages();
# ifdef FEAT_JOB_CHANNEL
if (has_pending_job())
{
/* Don't wait longer than a few seconds, checking for a finished
* job requires polling. */
if (p_ut > 9000L)
wtime_now = 1000L;
else
wtime_now = 10000L - p_ut;
}
# endif
#endif
if (wtime < 0 && did_start_blocking)
/* blocking and already waited for p_ut */
wait_time = -1;
else
{
if (wtime >= 0)
wait_time = wtime;
else
/* going to block after p_ut */
wait_time = p_ut;
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
elapsed_time = elapsed(&start_tv);
#endif
wait_time -= elapsed_time;
if (wait_time < 0)
{
if (wtime >= 0)
/* no character available within "wtime" */
return 0;
if (wtime < 0)
{
/* no character available within 'updatetime' */
did_start_blocking = TRUE;
#ifdef FEAT_AUTOCMD
if (trigger_cursorhold() && maxlen >= 3
&& !typebuf_changed(tb_change_cnt))
{
buf[0] = K_SPECIAL;
buf[1] = KS_EXTRA;
buf[2] = (int)KE_CURSORHOLD;
return 3;
}
#endif
/*
* If there is no character available within 'updatetime'
* seconds flush all the swap files to disk.
* Also done when interrupted by SIGWINCH.
*/
before_blocking();
continue;
}
}
}
#ifdef FEAT_JOB_CHANNEL
/* Checking if a job ended requires polling. Do this every 100 msec. */
if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
wait_time = 100L;
#endif
/*
* We want to be interrupted by the winch signal
* or by an event on the monitored file descriptors.
*/
if (!WaitForChar(wtime_now, &interrupted))
if (WaitForChar(wait_time, &interrupted))
{
if (do_resize) /* interrupted by SIGWINCH signal */
continue;
#ifdef MESSAGE_QUEUE
if (interrupted || wtime_now > 0)
{
parse_queued_messages();
continue;
}
#endif
return 0;
/* If input was put directly in typeahead buffer bail out here. */
if (typebuf_changed(tb_change_cnt))
return 0;
/*
* For some terminals we only get one character at a time.
* We want the get all available characters, so we could keep on
* trying until none is available
* For some other terminals this is quite slow, that's why we don't
* do it.
*/
len = read_from_input_buf(buf, (long)maxlen);
if (len > 0)
return len;
continue;
}
/* If input was put directly in typeahead buffer bail out here. */
if (typebuf_changed(tb_change_cnt))
return 0;
/* no character available */
#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
/* estimate the elapsed time */
elapsed += wait_time;
#endif
/*
* For some terminals we only get one character at a time.
* We want the get all available characters, so we could keep on
* trying until none is available
* For some other terminals this is quite slow, that's why we don't do
* it.
*/
len = read_from_input_buf(buf, (long)maxlen);
if (len > 0)
return len;
if (do_resize /* interrupted by SIGWINCH signal */
#ifdef FEAT_CLIENTSERVER
|| server_waiting()
#endif
#ifdef MESSAGE_QUEUE
|| interrupted
#endif
|| wait_time > 0
|| !did_start_blocking)
continue;
/* no character available or interrupted */
break;
}
return 0;
}
static void

View File

@ -136,6 +136,34 @@ func WaitFor(expr)
return 1000
endfunc
" Wait for up to a given milliseconds.
" With the +timers feature this waits for key-input by getchar(), Resume()
" feeds key-input and resumes process. Return time waited in milliseconds.
" Without +timers it uses simply :sleep.
func Standby(msec)
if has('timers')
let start = reltime()
let g:_standby_timer = timer_start(a:msec, function('s:feedkeys'))
call getchar()
return float2nr(reltimefloat(reltime(start)) * 1000)
else
execute 'sleep ' a:msec . 'm'
return a:msec
endif
endfunc
func Resume()
if exists('g:_standby_timer')
call timer_stop(g:_standby_timer)
call s:feedkeys(0)
unlet g:_standby_timer
endif
endfunc
func s:feedkeys(timer)
call feedkeys('x', 'nt')
endfunc
" Run Vim, using the "vimcmd" file and "-u NORC".
" "before" is a list of Vim commands to be executed before loading plugins.
" "after" is a list of Vim commands to be executed after loading plugins.

View File

@ -1362,9 +1362,11 @@ func Test_exit_callback()
endif
endfunc
let g:exit_cb_time = {'start': 0, 'end': 0}
function MyExitTimeCb(job, status)
let g:exit_cb_time.end = reltime(g:exit_cb_time.start)
if job_info(a:job).process == g:exit_cb_val.process
let g:exit_cb_val.end = reltime(g:exit_cb_val.start)
endif
call Resume()
endfunction
func Test_exit_callback_interval()
@ -1372,11 +1374,30 @@ func Test_exit_callback_interval()
return
endif
let g:exit_cb_time.start = reltime()
let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
call WaitFor('g:exit_cb_time.end != 0')
let elapsed = reltimefloat(g:exit_cb_time.end)
call assert_true(elapsed > 0.3)
let g:exit_cb_val.process = job_info(job).process
call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
let elapsed = reltimefloat(g:exit_cb_val.end)
call assert_true(elapsed > 0.5)
call assert_true(elapsed < 1.0)
" case: unreferenced job, using timer
if !has('timers')
return
endif
let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
let g:exit_cb_val.process = job_info(g:job).process
unlet g:job
call Standby(1000)
if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0
let elapsed = reltimefloat(g:exit_cb_val.end)
else
let elapsed = 1.0
endif
call assert_true(elapsed > 0.5)
call assert_true(elapsed < 1.0)
endfunc

View File

@ -764,6 +764,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
50,
/**/
49,
/**/