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:
parent
2f97912800
commit
01688ad545
@ -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;
|
||||
}
|
||||
|
202
src/os_unix.c
202
src/os_unix.c
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -764,6 +764,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
50,
|
||||
/**/
|
||||
49,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user