changeset 9205:c19eb05b19df v7.4.1886

commit https://github.com/vim/vim/commit/cda7764d8e65325d4524e5d6c3174121eeb12cad Author: Bram Moolenaar <Bram@vim.org> 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().
author Christian Brabandt <cb@256bit.org>
date Sat, 04 Jun 2016 13:45:05 +0200
parents 61b9dfe91682
children f90932493177
files src/getchar.c src/os_unix.c src/proto/getchar.pro src/version.c
diffstat 4 files changed, 72 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- 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,
--- 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)
--- 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);
--- 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,