# HG changeset patch # User Christian Brabandt # Date 1465040705 -7200 # Node ID c19eb05b19df0136c70b0f9de119e6bb11c01c0f # Parent 61b9dfe91682e18e3245ecda6eaba7b302aa638c commit https://github.com/vim/vim/commit/cda7764d8e65325d4524e5d6c3174121eeb12cad Author: Bram Moolenaar Date: Sat Jun 4 13:32:35 2016 +0200 patch 7.4.1886 Problem: When waiting for a character is interrupted by receiving channel data and the first character of a mapping was typed, the mapping times out. (Ramel Eshed) Solution: When dealing with channel data don't return from mch_inchar(). diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -129,6 +129,7 @@ static int vgetorpeek(int); static void map_free(mapblock_T **); static void validate_maphash(void); static void showmap(mapblock_T *mp, int local); +static int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt); #ifdef FEAT_EVAL static char_u *eval_map_expr(char_u *str, int c); #endif @@ -2941,7 +2942,7 @@ vgetorpeek(int advance) * Return the number of obtained characters. * Return -1 when end of input script reached. */ - int + static int inchar( char_u *buf, int maxlen, diff --git a/src/os_unix.c b/src/os_unix.c --- a/src/os_unix.c +++ b/src/os_unix.c @@ -175,12 +175,12 @@ typedef int waitstatus; #endif static pid_t wait4pid(pid_t, waitstatus *); -static int WaitForChar(long); -static int WaitForCharOrMouse(long, int *break_loop); +static int WaitForChar(long msec, int *interrupted); +static int WaitForCharOrMouse(long msec, int *interrupted); #if defined(__BEOS__) || defined(VMS) -int RealWaitForChar(int, long, int *, int *break_loop); +int RealWaitForChar(int, long, int *, int *interrupted); #else -static int RealWaitForChar(int, long, int *, int *break_loop); +static int RealWaitForChar(int, long, int *, int *interrupted); #endif #ifdef FEAT_XCLIPBOARD @@ -385,6 +385,7 @@ mch_inchar( int tb_change_cnt) { int len; + int interrupted = FALSE; #ifdef MESSAGE_QUEUE parse_queued_messages(); @@ -397,20 +398,31 @@ mch_inchar( if (wtime >= 0) { - while (!WaitForChar(wtime)) /* no character available */ + /* TODO: when looping reduce wtime by the elapsed time. */ + while (!WaitForChar(wtime, &interrupted)) { + /* no character available */ if (do_resize) + { handle_resize(); + continue; + } #ifdef FEAT_CLIENTSERVER - else if (!server_waiting()) -#else - else -#endif - /* return if not interrupted by resize or server */ - return 0; + if (server_waiting()) + { + parse_queued_messages(); + continue; + } +#endif #ifdef MESSAGE_QUEUE - parse_queued_messages(); -#endif + if (interrupted) + { + parse_queued_messages(); + continue; + } +#endif + /* return if not interrupted by resize or server */ + return 0; } } else /* wtime == -1 */ @@ -420,8 +432,9 @@ mch_inchar( * flush all the swap files to disk. * Also done when interrupted by SIGWINCH. */ - if (!WaitForChar(p_ut)) + if (!WaitForChar(p_ut, &interrupted)) { + /* TODO: if interrupted is set loop to wait the remaining time. */ #ifdef FEAT_AUTOCMD if (trigger_cursorhold() && maxlen >= 3 && !typebuf_changed(tb_change_cnt)) @@ -436,7 +449,8 @@ mch_inchar( } } - for (;;) /* repeat until we got a character */ + /* repeat until we got a character */ + for (;;) { long wtime_now = -1L; @@ -462,10 +476,17 @@ mch_inchar( * We want to be interrupted by the winch signal * or by an event on the monitored file descriptors. */ - if (!WaitForChar(wtime_now)) + if (!WaitForChar(wtime_now, &interrupted)) { if (do_resize) /* interrupted by SIGWINCH signal */ - handle_resize(); + continue; +#ifdef MESSAGE_QUEUE + if (interrupted || wtime_now > 0) + { + parse_queued_messages(); + continue; + } +#endif return 0; } @@ -482,9 +503,7 @@ mch_inchar( */ len = read_from_input_buf(buf, (long)maxlen); if (len > 0) - { return len; - } } } @@ -501,7 +520,7 @@ handle_resize(void) int mch_char_avail(void) { - return WaitForChar(0L); + return WaitForChar(0L, NULL); } #if defined(HAVE_TOTAL_MEM) || defined(PROTO) @@ -691,7 +710,7 @@ mch_delay(long msec, int ignoreinput) in_mch_delay = FALSE; } else - WaitForChar(msec); + WaitForChar(msec, NULL); } #if defined(HAVE_STACK_LIMIT) \ @@ -5229,6 +5248,10 @@ mch_start_job(char **argv, job_T *job, j if (stderr_works) perror("executing job failed"); +#ifdef EXITFREE + /* calling free_all_mem() here causes problems. Ignore valgrind + * reporting possibly leaked memory. */ +#endif _exit(EXEC_FAILED); /* exec failed, return failure code */ } @@ -5376,16 +5399,17 @@ mch_breakcheck(void) * from inbuf[]. * "msec" == -1 will block forever. * Invokes timer callbacks when needed. + * "interrupted" (if not NULL) is set to TRUE when no character is available + * but something else needs to be done. + * Returns TRUE when a character is available. * When a GUI is being used, this will never get called -- webb - * Returns TRUE when a character is available. */ static int -WaitForChar(long msec) +WaitForChar(long msec, int *interrupted) { #ifdef FEAT_TIMERS long due_time; long remaining = msec; - int break_loop = FALSE; int tb_change_cnt = typebuf.tb_change_cnt; /* When waiting very briefly don't trigger timers. */ @@ -5404,9 +5428,9 @@ WaitForChar(long msec) } if (due_time <= 0 || (msec > 0 && due_time > remaining)) due_time = remaining; - if (WaitForCharOrMouse(due_time, &break_loop)) + if (WaitForCharOrMouse(due_time, interrupted)) return TRUE; - if (break_loop) + if (interrupted != NULL && *interrupted) /* Nothing available, but need to return so that side effects get * handled, such as handling a message on a channel. */ return FALSE; @@ -5415,7 +5439,7 @@ WaitForChar(long msec) } return FALSE; #else - return WaitForCharOrMouse(msec, NULL); + return WaitForCharOrMouse(msec, interrupted); #endif } @@ -5423,10 +5447,12 @@ WaitForChar(long msec) * Wait "msec" msec until a character is available from the mouse or keyboard * or from inbuf[]. * "msec" == -1 will block forever. + * "interrupted" (if not NULL) is set to TRUE when no character is available + * but something else needs to be done. * When a GUI is being used, this will never get called -- webb */ static int -WaitForCharOrMouse(long msec, int *break_loop) +WaitForCharOrMouse(long msec, int *interrupted) { #ifdef FEAT_MOUSE_GPM int gpm_process_wanted; @@ -5473,9 +5499,9 @@ WaitForCharOrMouse(long msec, int *break # ifdef FEAT_MOUSE_GPM gpm_process_wanted = 0; avail = RealWaitForChar(read_cmd_fd, msec, - &gpm_process_wanted, break_loop); + &gpm_process_wanted, interrupted); # else - avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); + avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted); # endif if (!avail) { @@ -5498,7 +5524,7 @@ WaitForCharOrMouse(long msec, int *break ; #else - avail = RealWaitForChar(read_cmd_fd, msec, NULL, break_loop); + avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted); #endif return avail; } @@ -5511,13 +5537,15 @@ WaitForCharOrMouse(long msec, int *break * When a GUI is being used, this will not be used for input -- webb * Or when a Linux GPM mouse event is waiting. * Or when a clientserver message is on the queue. + * "interrupted" (if not NULL) is set to TRUE when no character is available + * but something else needs to be done. */ #if defined(__BEOS__) int #else static int #endif -RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *break_loop) +RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted) { int ret; int result; @@ -5627,12 +5655,14 @@ RealWaitForChar(int fd, long msec, int * #ifdef FEAT_JOB_CHANNEL nfd = channel_poll_setup(nfd, &fds); #endif + if (interrupted != NULL) + *interrupted = FALSE; ret = poll(fds, nfd, towait); result = ret > 0 && (fds[0].revents & POLLIN); - if (break_loop != NULL && ret > 0) - *break_loop = TRUE; + if (result == 0 && interrupted != NULL && ret > 0) + *interrupted = TRUE; # ifdef FEAT_MZSCHEME if (ret == 0 && mzquantum_used) @@ -5679,7 +5709,6 @@ RealWaitForChar(int fd, long msec, int * ret = channel_poll_check(ret, &fds); #endif - #else /* HAVE_SELECT */ struct timeval tv; @@ -5760,13 +5789,15 @@ select_eintr: # ifdef FEAT_JOB_CHANNEL maxfd = channel_select_setup(maxfd, &rfds, &wfds); # endif + if (interrupted != NULL) + *interrupted = FALSE; ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp); result = ret > 0 && FD_ISSET(fd, &rfds); if (result) --ret; - if (break_loop != NULL && ret > 0) - *break_loop = TRUE; + else if (interrupted != NULL && ret > 0) + *interrupted = TRUE; # ifdef EINTR if (ret == -1 && errno == EINTR) diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -47,7 +47,6 @@ int vpeekc_nomap(void); int vpeekc_any(void); int char_avail(void); void vungetc(int c); -int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt); int fix_input_buffer(char_u *buf, int len, int script); int input_available(void); int do_map(int maptype, char_u *arg, int mode, int abbrev); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1886, +/**/ 1885, /**/ 1884,