# HG changeset patch # User Bram Moolenaar # Date 1547069406 -3600 # Node ID 440e5071f3f8cc8fec525c948dc4db491008dccb # Parent 62e66e6b2c794e78713b66361538242f61364408 patch 8.1.0710: when using timers may wait for job exit quite long commit https://github.com/vim/vim/commit/c46af534102c65b43912311d67f55f5049e5ef7a Author: Bram Moolenaar Date: Wed Jan 9 22:24:49 2019 +0100 patch 8.1.0710: when using timers may wait for job exit quite long Problem: When using timers may wait for job exit quite long. Solution: Return from ui_wait_for_chars_or_timer() when a job or channel needs to be handled. (Ozaki Kiichi, closes #3783) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1893,3 +1893,40 @@ func Test_keep_pty_open() call assert_inrange(200, 1000, elapsed) call job_stop(job) endfunc + +func Test_job_start_in_timer() + if !has('job') || !has('timers') + return + endif + + func OutCb(chan, msg) + endfunc + + func ExitCb(job, status) + let g:val = 1 + call Resume() + endfunc + + func TimerCb(timer) + if has('win32') + let cmd = ['cmd', '/c', 'echo.'] + else + let cmd = ['echo'] + endif + let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'}) + call substitute(repeat('a', 100000), '.', '', 'g') + endfunc + + " We should be interrupted before 'updatetime' elapsed. + let g:val = 0 + call timer_start(1, 'TimerCb') + let elapsed = Standby(&ut) + call assert_inrange(1, &ut / 2, elapsed) + call job_stop(g:job) + + delfunc OutCb + delfunc ExitCb + delfunc TimerCb + unlet! g:val + unlet! g:job +endfunc diff --git a/src/ui.c b/src/ui.c --- a/src/ui.c +++ b/src/ui.c @@ -205,7 +205,7 @@ theend: return retval; } -#if defined(FEAT_TIMERS) || defined(PROT) +#if defined(FEAT_TIMERS) || defined(PROTO) /* * Wait for a timer to fire or "wait_func" to return non-zero. * Returns OK when something was read. @@ -221,15 +221,18 @@ ui_wait_for_chars_or_timer( int due_time; long remaining = wtime; int tb_change_cnt = typebuf.tb_change_cnt; - - /* When waiting very briefly don't trigger timers. */ +# ifdef FEAT_JOB_CHANNEL + int brief_wait = TRUE; +# endif + + // When waiting very briefly don't trigger timers. if (wtime >= 0 && wtime < 10L) return wait_func(wtime, NULL, ignore_input); while (wtime < 0 || remaining > 0) { - /* Trigger timers and then get the time in wtime until the next one is - * due. Wait up to that time. */ + // Trigger timers and then get the time in wtime until the next one is + // due. Wait up to that time. due_time = check_due_timer(); if (typebuf.tb_change_cnt != tb_change_cnt) { @@ -238,11 +241,28 @@ ui_wait_for_chars_or_timer( } if (due_time <= 0 || (wtime > 0 && due_time > remaining)) due_time = remaining; +# ifdef FEAT_JOB_CHANNEL + if ((due_time < 0 || due_time > 10L) +# ifdef FEAT_GUI + && !gui.in_use +# endif + && (has_pending_job() || channel_any_readahead())) + { + // There is a pending job or channel, should return soon in order + // to handle them ASAP. Do check for input briefly. + due_time = 10L; + brief_wait = TRUE; + } +# endif if (wait_func(due_time, interrupted, ignore_input)) return OK; - if (interrupted != NULL && *interrupted) - /* Nothing available, but need to return so that side effects get - * handled, such as handling a message on a channel. */ + if ((interrupted != NULL && *interrupted) +# ifdef FEAT_JOB_CHANNEL + || brief_wait +# endif + ) + // Nothing available, but need to return so that side effects get + // handled, such as handling a message on a channel. return FAIL; if (wtime > 0) remaining -= due_time; @@ -252,7 +272,7 @@ ui_wait_for_chars_or_timer( #endif /* - * return non-zero if a character is available + * Return non-zero if a character is available. */ int ui_char_avail(void) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -800,6 +800,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 710, +/**/ 709, /**/ 708,