# HG changeset patch # User Christian Brabandt # Date 1480005004 -3600 # Node ID 42911b23324582e3c21804b38a5cc8ea399d83e0 # Parent 4d35d83f4537b5c0cd27e368271696dd35170897 commit https://github.com/vim/vim/commit/833eb1d752426689051bf2001083359899536939 Author: Bram Moolenaar Date: Thu Nov 24 17:22:50 2016 +0100 patch 8.0.0097 Problem: When a channel callback consumes a lot of time Vim becomes unresponsive. (skywind) Solution: Bail out of checking channel readahead after 100 msec. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -3815,6 +3815,11 @@ channel_parse_messages(void) int ret = FALSE; int r; ch_part_T part = PART_SOCK; +#ifdef ELAPSED_FUNC + ELAPSED_TYPE start_tv; + + ELAPSED_INIT(start_tv); +#endif ++safe_to_invoke_callback; @@ -3859,7 +3864,14 @@ channel_parse_messages(void) r = may_invoke_callback(channel, part); if (r == OK) ret = TRUE; - if (channel_unref(channel) || r == OK) + if (channel_unref(channel) || (r == OK +#ifdef ELAPSED_FUNC + /* Limit the time we loop here to 100 msec, otherwise + * Vim becomes unresponsive when the callback takes + * more than a bit of time. */ + && ELAPSED_FUNC(start_tv) < 100L +#endif + )) { /* channel was freed or something was done, start over */ channel = first_channel; diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -6263,3 +6263,34 @@ parse_queued_messages(void) # endif } #endif + +#ifdef ELAPSED_TIMEVAL /* proto is defined in vim.h */ +/* + * Return time in msec since "start_tv". + */ + long +elapsed(struct timeval *start_tv) +{ + struct timeval now_tv; + + gettimeofday(&now_tv, NULL); + return (now_tv.tv_sec - start_tv->tv_sec) * 1000L + + (now_tv.tv_usec - start_tv->tv_usec) / 1000L; +} +#endif + +#ifdef ELAPSED_TICKCOUNT +/* + * Return time in msec since "start_tick". + */ + long +elapsed(DWORD start_tick) +{ + DWORD now = GetTickCount(); + + if (now < start_tick) + /* overflow */ + return (long)now; + return (long)now - (long)start_tick; +} +#endif diff --git a/src/os_unix.c b/src/os_unix.c --- a/src/os_unix.c +++ b/src/os_unix.c @@ -376,21 +376,6 @@ mch_write(char_u *s, int len) RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL); } -#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) -/* - * Return time in msec since "start_tv". - */ - static long -elapsed(struct timeval *start_tv) -{ - struct timeval now_tv; - - gettimeofday(&now_tv, NULL); - return (now_tv.tv_sec - start_tv->tv_sec) * 1000L - + (now_tv.tv_usec - start_tv->tv_usec) / 1000L; -} -#endif - /* * mch_inchar(): low level input function. * Get a characters from the keyboard. @@ -411,10 +396,10 @@ mch_inchar( 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); +#ifdef ELAPSED_FUNC + ELAPSED_TYPE start_tv; + + ELAPSED_INIT(start_tv); #endif /* repeat until we got a character or waited long enough */ @@ -438,8 +423,8 @@ mch_inchar( 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); +#ifdef ELAPSED_FUNC + elapsed_time = ELAPSED_FUNC(start_tv); #endif wait_time -= elapsed_time; if (wait_time < 0) @@ -1554,18 +1539,16 @@ mch_input_isatty(void) #ifdef FEAT_X11 -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \ +# if defined(ELAPSED_TIMEVAL) \ && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)) -static void xopen_message(struct timeval *start_tv); - /* * Give a message about the elapsed time for opening the X window. */ static void -xopen_message(struct timeval *start_tv) -{ - smsg((char_u *)_("Opening the X display took %ld msec"), elapsed(start_tv)); +xopen_message(long elapsed_msec) +{ + smsg((char_u *)_("Opening the X display took %ld msec"), elapsed_msec); } # endif #endif @@ -1864,11 +1847,11 @@ get_x11_windis(void) #endif if (x11_display != NULL) { -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) +# ifdef ELAPSED_FUNC if (p_verbose > 0) { verbose_enter(); - xopen_message(&start_tv); + xopen_message(ELAPSED_FUNC(start_tv)); verbose_leave(); } # endif @@ -4630,8 +4613,8 @@ mch_call_shell( ga_init2(&ga, 1, BUFLEN); noread_cnt = 0; -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) - gettimeofday(&start_tv, NULL); +# ifdef ELAPSED_FUNC + ELAPSED_INIT(start_tv); # endif for (;;) { @@ -4666,8 +4649,8 @@ mch_call_shell( /* Get extra characters when we don't have any. * Reset the counter and timer. */ noread_cnt = 0; -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) - gettimeofday(&start_tv, NULL); +# ifdef ELAPSED_FUNC + ELAPSED_INIT(start_tv); # endif len = ui_inchar(ta_buf, BUFLEN, 10L, 0); } @@ -4886,10 +4869,10 @@ mch_call_shell( if (got_int) break; -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) +# ifdef ELAPSED_FUNC if (wait_pid == 0) { - long msec = elapsed(&start_tv); + long msec = ELAPSED_FUNC(start_tv); /* Avoid that we keep looping here without * checking for a CTRL-C for a long time. Don't @@ -5632,15 +5615,14 @@ RealWaitForChar(int fd, long msec, int * /* May retry getting characters after an event was handled. */ # define MAY_LOOP -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) +# ifdef ELAPSED_FUNC /* Remember at what time we started, so that we know how much longer we * should wait after being interrupted. */ -# define USE_START_TV long start_msec = msec; - struct timeval start_tv; + ELAPSED_TYPE start_tv; if (msec > 0) - gettimeofday(&start_tv, NULL); + ELAPSED_INIT(start_tv); # endif /* Handle being called recursively. This may happen for the session @@ -5947,9 +5929,9 @@ select_eintr: /* We're going to loop around again, find out for how long */ if (msec > 0) { -# ifdef USE_START_TV +# ifdef ELAPSED_FUNC /* Compute remaining wait time. */ - msec = start_msec - elapsed(&start_tv); + msec = start_msec - ELAPSED_FUNC(start_tv); # else /* Guess we got interrupted halfway. */ msec = msec / 2; @@ -7046,11 +7028,11 @@ setup_term_clip(void) #if defined(HAVE_SETJMP_H) int (*oldIOhandler)(); #endif -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) - struct timeval start_tv; +# ifdef ELAPSED_FUNC + ELAPSED_TYPE start_tv; if (p_verbose > 0) - gettimeofday(&start_tv, NULL); + ELAPSED_INIT(start_tv); # endif /* Ignore X errors while opening the display */ @@ -7092,11 +7074,11 @@ setup_term_clip(void) /* Catch terminating error of the X server connection. */ (void)XSetIOErrorHandler(x_IOerror_handler); -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) +# ifdef ELAPSED_FUNC if (p_verbose > 0) { verbose_enter(); - xopen_message(&start_tv); + xopen_message(ELAPSED_FUNC(start_tv)); verbose_leave(); } # endif diff --git a/src/os_win32.c b/src/os_win32.c --- a/src/os_win32.c +++ b/src/os_win32.c @@ -4287,9 +4287,6 @@ mch_system_piped(char *cmd, int options) /* Get extra characters when we don't have any. Reset the * counter and timer. */ noread_cnt = 0; -# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) - gettimeofday(&start_tv, NULL); -# endif len = ui_inchar(ta_buf, BUFLEN, 10L, 0); } if (ta_len > 0 || len > 0) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 97, +/**/ 96, /**/ 95, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -2503,4 +2503,20 @@ typedef enum # define OPEN_CHR_FILES #endif +#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) +# define ELAPSED_TIMEVAL +# define ELAPSED_INIT(v) gettimeofday(&v, NULL) +# define ELAPSED_FUNC(v) elapsed(&v) +# define ELAPSED_TYPE struct timeval + long elapsed(struct timeval *start_tv); +#else +# if defined(WIN32) +# define ELAPSED_TICKCOUNT +# define ELAPSED_INIT(v) v = GetTickCount +# define ELAPSED_FUNC(v) elapsed(v) +# define ELAPSED_TYPE DWORD + long elapsed(DWORD start_tick); +# endif +#endif + #endif /* VIM__H */