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
|
* Return TRUE when there is any job that has an exit callback and might exit,
|
||||||
* job_check_ended() should be called once in a while.
|
* which means job_check_ended() should be called more often.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
has_pending_job(void)
|
has_pending_job(void)
|
||||||
@ -4652,7 +4652,11 @@ has_pending_job(void)
|
|||||||
job_T *job;
|
job_T *job;
|
||||||
|
|
||||||
for (job = first_job; job != NULL; job = job->jv_next)
|
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 TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
202
src/os_unix.c
202
src/os_unix.c
@ -404,139 +404,121 @@ mch_inchar(
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
int interrupted = FALSE;
|
int interrupted = FALSE;
|
||||||
|
int did_start_blocking = FALSE;
|
||||||
long wait_time;
|
long wait_time;
|
||||||
|
long elapsed_time = 0;
|
||||||
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
|
||||||
struct timeval start_tv;
|
struct timeval start_tv;
|
||||||
|
|
||||||
gettimeofday(&start_tv, NULL);
|
gettimeofday(&start_tv, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MESSAGE_QUEUE
|
/* repeat until we got a character or waited long enough */
|
||||||
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();
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (wtime >= 0)
|
/* Check if window changed size while we were busy, perhaps the ":set
|
||||||
wait_time = wtime;
|
* columns=99" command was used. */
|
||||||
else
|
while (do_resize)
|
||||||
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 */
|
|
||||||
handle_resize();
|
handle_resize();
|
||||||
|
|
||||||
#ifdef MESSAGE_QUEUE
|
#ifdef MESSAGE_QUEUE
|
||||||
parse_queued_messages();
|
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
|
#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
|
* We want to be interrupted by the winch signal
|
||||||
* or by an event on the monitored file descriptors.
|
* 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 */
|
/* If input was put directly in typeahead buffer bail out here. */
|
||||||
continue;
|
if (typebuf_changed(tb_change_cnt))
|
||||||
#ifdef MESSAGE_QUEUE
|
return 0;
|
||||||
if (interrupted || wtime_now > 0)
|
|
||||||
{
|
/*
|
||||||
parse_queued_messages();
|
* For some terminals we only get one character at a time.
|
||||||
continue;
|
* We want the get all available characters, so we could keep on
|
||||||
}
|
* trying until none is available
|
||||||
#endif
|
* For some other terminals this is quite slow, that's why we don't
|
||||||
return 0;
|
* 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. */
|
/* no character available */
|
||||||
if (typebuf_changed(tb_change_cnt))
|
#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
|
||||||
return 0;
|
/* estimate the elapsed time */
|
||||||
|
elapsed += wait_time;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
if (do_resize /* interrupted by SIGWINCH signal */
|
||||||
* For some terminals we only get one character at a time.
|
#ifdef FEAT_CLIENTSERVER
|
||||||
* We want the get all available characters, so we could keep on
|
|| server_waiting()
|
||||||
* trying until none is available
|
#endif
|
||||||
* For some other terminals this is quite slow, that's why we don't do
|
#ifdef MESSAGE_QUEUE
|
||||||
* it.
|
|| interrupted
|
||||||
*/
|
#endif
|
||||||
len = read_from_input_buf(buf, (long)maxlen);
|
|| wait_time > 0
|
||||||
if (len > 0)
|
|| !did_start_blocking)
|
||||||
return len;
|
continue;
|
||||||
|
|
||||||
|
/* no character available or interrupted */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -136,6 +136,34 @@ func WaitFor(expr)
|
|||||||
return 1000
|
return 1000
|
||||||
endfunc
|
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".
|
" Run Vim, using the "vimcmd" file and "-u NORC".
|
||||||
" "before" is a list of Vim commands to be executed before loading plugins.
|
" "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.
|
" "after" is a list of Vim commands to be executed after loading plugins.
|
||||||
|
@ -1362,9 +1362,11 @@ func Test_exit_callback()
|
|||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
let g:exit_cb_time = {'start': 0, 'end': 0}
|
|
||||||
function MyExitTimeCb(job, status)
|
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
|
endfunction
|
||||||
|
|
||||||
func Test_exit_callback_interval()
|
func Test_exit_callback_interval()
|
||||||
@ -1372,11 +1374,30 @@ func Test_exit_callback_interval()
|
|||||||
return
|
return
|
||||||
endif
|
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'})
|
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 g:exit_cb_val.process = job_info(job).process
|
||||||
let elapsed = reltimefloat(g:exit_cb_time.end)
|
call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
|
||||||
call assert_true(elapsed > 0.3)
|
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)
|
call assert_true(elapsed < 1.0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
@ -764,6 +764,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 */
|
||||||
|
/**/
|
||||||
|
50,
|
||||||
/**/
|
/**/
|
||||||
49,
|
49,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user