Skip to content

Commit

Permalink
patch 8.0.0050
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
brammool committed Oct 27, 2016
1 parent 2f97912 commit 01688ad
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 114 deletions.
10 changes: 7 additions & 3 deletions src/channel.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4643,16 +4643,20 @@ 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)
{ {
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;
} }
Expand Down
192 changes: 87 additions & 105 deletions src/os_unix.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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; handle_resize();
#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 #ifdef MESSAGE_QUEUE
if (interrupted) parse_queued_messages();
{
parse_queued_messages();
continue;
}
#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) #if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
} elapsed_time = elapsed(&start_tv);
#endif #endif
if (wtime >= 0) wait_time -= elapsed_time;
/* no character available within "wtime" */ if (wait_time < 0)
return 0; {
if (wtime >= 0)
/* no character available within "wtime" */
return 0;


/* wtime == -1: no character available within 'updatetime' */ if (wtime < 0)
{
/* no character available within 'updatetime' */
did_start_blocking = TRUE;
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
if (trigger_cursorhold() && maxlen >= 3 if (trigger_cursorhold() && maxlen >= 3
&& !typebuf_changed(tb_change_cnt)) && !typebuf_changed(tb_change_cnt))
{ {
buf[0] = K_SPECIAL; buf[0] = K_SPECIAL;
buf[1] = KS_EXTRA; buf[1] = KS_EXTRA;
buf[2] = (int)KE_CURSORHOLD; buf[2] = (int)KE_CURSORHOLD;
return 3; return 3;
} }
#endif #endif
/* /*
* If there is no character available within 'updatetime' seconds * If there is no character available within 'updatetime'
* flush all the swap files to disk. * seconds flush all the swap files to disk.
* Also done when interrupted by SIGWINCH. * Also done when interrupted by SIGWINCH.
*/ */
before_blocking(); before_blocking();
break; continue;
} }

}
/* repeat until we got a character */
for (;;)
{
long wtime_now = -1L;

while (do_resize) /* window changed size */
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
#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 #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
Expand Down
28 changes: 28 additions & 0 deletions src/testdir/shared.vim
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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.
Expand Down
33 changes: 27 additions & 6 deletions src/testdir/test_channel.vim
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1362,21 +1362,42 @@ 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()
if !has('job') if !has('job')
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


Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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,
/**/ /**/
Expand Down

0 comments on commit 01688ad

Please sign in to comment.