Skip to content

Commit 01688ad

Browse files
committed
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.
1 parent 2f97912 commit 01688ad

5 files changed

Lines changed: 151 additions & 114 deletions

File tree

src/channel.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4643,16 +4643,20 @@ job_stop_on_exit(void)
46434643
}
46444644

46454645
/*
4646-
* Return TRUE when there is any job that might exit, which means
4647-
* job_check_ended() should be called once in a while.
4646+
* Return TRUE when there is any job that has an exit callback and might exit,
4647+
* which means job_check_ended() should be called more often.
46484648
*/
46494649
int
46504650
has_pending_job(void)
46514651
{
46524652
job_T *job;
46534653

46544654
for (job = first_job; job != NULL; job = job->jv_next)
4655-
if (job_still_alive(job))
4655+
/* Only should check if the channel has been closed, if the channel is
4656+
* open the job won't exit. */
4657+
if (job->jv_status == JOB_STARTED && job->jv_exit_cb != NULL
4658+
&& (job->jv_channel == NULL
4659+
|| !channel_still_useful(job->jv_channel)))
46564660
return TRUE;
46574661
return FALSE;
46584662
}

src/os_unix.c

Lines changed: 87 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -404,139 +404,121 @@ mch_inchar(
404404
{
405405
int len;
406406
int interrupted = FALSE;
407+
int did_start_blocking = FALSE;
407408
long wait_time;
409+
long elapsed_time = 0;
408410
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
409411
struct timeval start_tv;
410412

411413
gettimeofday(&start_tv, NULL);
412414
#endif
413415

414-
#ifdef MESSAGE_QUEUE
415-
parse_queued_messages();
416-
#endif
417-
418-
/* Check if window changed size while we were busy, perhaps the ":set
419-
* columns=99" command was used. */
420-
while (do_resize)
421-
handle_resize();
422-
416+
/* repeat until we got a character or waited long enough */
423417
for (;;)
424418
{
425-
if (wtime >= 0)
426-
wait_time = wtime;
427-
else
428-
wait_time = p_ut;
429-
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
430-
wait_time -= elapsed(&start_tv);
431-
if (wait_time >= 0)
432-
{
433-
#endif
434-
if (WaitForChar(wait_time, &interrupted))
435-
break;
419+
/* Check if window changed size while we were busy, perhaps the ":set
420+
* columns=99" command was used. */
421+
while (do_resize)
422+
handle_resize();
436423

437-
/* no character available */
438-
if (do_resize)
439-
{
440-
handle_resize();
441-
continue;
442-
}
443-
#ifdef FEAT_CLIENTSERVER
444-
if (server_waiting())
445-
{
446-
parse_queued_messages();
447-
continue;
448-
}
449-
#endif
450424
#ifdef MESSAGE_QUEUE
451-
if (interrupted)
452-
{
453-
parse_queued_messages();
454-
continue;
455-
}
425+
parse_queued_messages();
456426
#endif
427+
if (wtime < 0 && did_start_blocking)
428+
/* blocking and already waited for p_ut */
429+
wait_time = -1;
430+
else
431+
{
432+
if (wtime >= 0)
433+
wait_time = wtime;
434+
else
435+
/* going to block after p_ut */
436+
wait_time = p_ut;
457437
#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
458-
}
438+
elapsed_time = elapsed(&start_tv);
459439
#endif
460-
if (wtime >= 0)
461-
/* no character available within "wtime" */
462-
return 0;
440+
wait_time -= elapsed_time;
441+
if (wait_time < 0)
442+
{
443+
if (wtime >= 0)
444+
/* no character available within "wtime" */
445+
return 0;
463446

464-
/* wtime == -1: no character available within 'updatetime' */
447+
if (wtime < 0)
448+
{
449+
/* no character available within 'updatetime' */
450+
did_start_blocking = TRUE;
465451
#ifdef FEAT_AUTOCMD
466-
if (trigger_cursorhold() && maxlen >= 3
467-
&& !typebuf_changed(tb_change_cnt))
468-
{
469-
buf[0] = K_SPECIAL;
470-
buf[1] = KS_EXTRA;
471-
buf[2] = (int)KE_CURSORHOLD;
472-
return 3;
473-
}
452+
if (trigger_cursorhold() && maxlen >= 3
453+
&& !typebuf_changed(tb_change_cnt))
454+
{
455+
buf[0] = K_SPECIAL;
456+
buf[1] = KS_EXTRA;
457+
buf[2] = (int)KE_CURSORHOLD;
458+
return 3;
459+
}
474460
#endif
475-
/*
476-
* If there is no character available within 'updatetime' seconds
477-
* flush all the swap files to disk.
478-
* Also done when interrupted by SIGWINCH.
479-
*/
480-
before_blocking();
481-
break;
482-
}
483-
484-
/* repeat until we got a character */
485-
for (;;)
486-
{
487-
long wtime_now = -1L;
488-
489-
while (do_resize) /* window changed size */
490-
handle_resize();
491-
492-
#ifdef MESSAGE_QUEUE
493-
parse_queued_messages();
494-
495-
# ifdef FEAT_JOB_CHANNEL
496-
if (has_pending_job())
497-
{
498-
/* Don't wait longer than a few seconds, checking for a finished
499-
* job requires polling. */
500-
if (p_ut > 9000L)
501-
wtime_now = 1000L;
502-
else
503-
wtime_now = 10000L - p_ut;
461+
/*
462+
* If there is no character available within 'updatetime'
463+
* seconds flush all the swap files to disk.
464+
* Also done when interrupted by SIGWINCH.
465+
*/
466+
before_blocking();
467+
continue;
468+
}
469+
}
504470
}
505-
# endif
471+
472+
#ifdef FEAT_JOB_CHANNEL
473+
/* Checking if a job ended requires polling. Do this every 100 msec. */
474+
if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
475+
wait_time = 100L;
506476
#endif
477+
507478
/*
508479
* We want to be interrupted by the winch signal
509480
* or by an event on the monitored file descriptors.
510481
*/
511-
if (!WaitForChar(wtime_now, &interrupted))
482+
if (WaitForChar(wait_time, &interrupted))
512483
{
513-
if (do_resize) /* interrupted by SIGWINCH signal */
514-
continue;
515-
#ifdef MESSAGE_QUEUE
516-
if (interrupted || wtime_now > 0)
517-
{
518-
parse_queued_messages();
519-
continue;
520-
}
521-
#endif
522-
return 0;
484+
/* If input was put directly in typeahead buffer bail out here. */
485+
if (typebuf_changed(tb_change_cnt))
486+
return 0;
487+
488+
/*
489+
* For some terminals we only get one character at a time.
490+
* We want the get all available characters, so we could keep on
491+
* trying until none is available
492+
* For some other terminals this is quite slow, that's why we don't
493+
* do it.
494+
*/
495+
len = read_from_input_buf(buf, (long)maxlen);
496+
if (len > 0)
497+
return len;
498+
continue;
523499
}
524500

525-
/* If input was put directly in typeahead buffer bail out here. */
526-
if (typebuf_changed(tb_change_cnt))
527-
return 0;
501+
/* no character available */
502+
#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
503+
/* estimate the elapsed time */
504+
elapsed += wait_time;
505+
#endif
528506

529-
/*
530-
* For some terminals we only get one character at a time.
531-
* We want the get all available characters, so we could keep on
532-
* trying until none is available
533-
* For some other terminals this is quite slow, that's why we don't do
534-
* it.
535-
*/
536-
len = read_from_input_buf(buf, (long)maxlen);
537-
if (len > 0)
538-
return len;
507+
if (do_resize /* interrupted by SIGWINCH signal */
508+
#ifdef FEAT_CLIENTSERVER
509+
|| server_waiting()
510+
#endif
511+
#ifdef MESSAGE_QUEUE
512+
|| interrupted
513+
#endif
514+
|| wait_time > 0
515+
|| !did_start_blocking)
516+
continue;
517+
518+
/* no character available or interrupted */
519+
break;
539520
}
521+
return 0;
540522
}
541523

542524
static void

src/testdir/shared.vim

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,34 @@ func WaitFor(expr)
136136
return 1000
137137
endfunc
138138

139+
" Wait for up to a given milliseconds.
140+
" With the +timers feature this waits for key-input by getchar(), Resume()
141+
" feeds key-input and resumes process. Return time waited in milliseconds.
142+
" Without +timers it uses simply :sleep.
143+
func Standby(msec)
144+
if has('timers')
145+
let start = reltime()
146+
let g:_standby_timer = timer_start(a:msec, function('s:feedkeys'))
147+
call getchar()
148+
return float2nr(reltimefloat(reltime(start)) * 1000)
149+
else
150+
execute 'sleep ' a:msec . 'm'
151+
return a:msec
152+
endif
153+
endfunc
154+
155+
func Resume()
156+
if exists('g:_standby_timer')
157+
call timer_stop(g:_standby_timer)
158+
call s:feedkeys(0)
159+
unlet g:_standby_timer
160+
endif
161+
endfunc
162+
163+
func s:feedkeys(timer)
164+
call feedkeys('x', 'nt')
165+
endfunc
166+
139167
" Run Vim, using the "vimcmd" file and "-u NORC".
140168
" "before" is a list of Vim commands to be executed before loading plugins.
141169
" "after" is a list of Vim commands to be executed after loading plugins.

src/testdir/test_channel.vim

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,21 +1362,42 @@ func Test_exit_callback()
13621362
endif
13631363
endfunc
13641364

1365-
let g:exit_cb_time = {'start': 0, 'end': 0}
13661365
function MyExitTimeCb(job, status)
1367-
let g:exit_cb_time.end = reltime(g:exit_cb_time.start)
1366+
if job_info(a:job).process == g:exit_cb_val.process
1367+
let g:exit_cb_val.end = reltime(g:exit_cb_val.start)
1368+
endif
1369+
call Resume()
13681370
endfunction
13691371

13701372
func Test_exit_callback_interval()
13711373
if !has('job')
13721374
return
13731375
endif
13741376

1375-
let g:exit_cb_time.start = reltime()
1377+
let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
13761378
let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1377-
call WaitFor('g:exit_cb_time.end != 0')
1378-
let elapsed = reltimefloat(g:exit_cb_time.end)
1379-
call assert_true(elapsed > 0.3)
1379+
let g:exit_cb_val.process = job_info(job).process
1380+
call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
1381+
let elapsed = reltimefloat(g:exit_cb_val.end)
1382+
call assert_true(elapsed > 0.5)
1383+
call assert_true(elapsed < 1.0)
1384+
1385+
" case: unreferenced job, using timer
1386+
if !has('timers')
1387+
return
1388+
endif
1389+
1390+
let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
1391+
let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1392+
let g:exit_cb_val.process = job_info(g:job).process
1393+
unlet g:job
1394+
call Standby(1000)
1395+
if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0
1396+
let elapsed = reltimefloat(g:exit_cb_val.end)
1397+
else
1398+
let elapsed = 1.0
1399+
endif
1400+
call assert_true(elapsed > 0.5)
13801401
call assert_true(elapsed < 1.0)
13811402
endfunc
13821403

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,8 @@ static char *(features[]) =
764764

765765
static int included_patches[] =
766766
{ /* Add new patch number below this line */
767+
/**/
768+
50,
767769
/**/
768770
49,
769771
/**/

0 commit comments

Comments
 (0)