[PATCH 3/3] Cygwin: console: Fix typeahead input for bash

Takashi Yano <[email protected]> Thu, 11 Jun 2026 01:35:14 +0900
Newsgroups gmane.os.cygwin.patches
Message-ID <[email protected]>
Currently, following misbehaviour occurs in bash.
  1) Run "sleep 10".
  2) Type "cmd<enter>ps<enter>" while "sleep is running".
  3) After "sleep" ends, "ps" does not run in "cmd".
  4) exit from "cmd". Then, "ps" is executed.
This is because process_input_message() handles all the events in
the console input buffer, and stores key input into readahead buffer.
However, since the readahead buffer is unique to process, "cmd"
cannot read it. Since "ps<enter>" is stored in bash's readahead
buffer, it is executed by bash after "cmd" exits. With this patch,
process_input_message() handles only the requested amount of events
by read().

Fixes: 8382778cdb57 ("Cygwin: console: fix select() behaviour")
Signed-off-by: Takashi Yano <[email protected]>
Reviewed-by:
---
 winsup/cygwin/fhandler/console.cc       | 15 ++++++++++++---
 winsup/cygwin/local_includes/fhandler.h |  2 +-
 winsup/cygwin/select.cc                 |  2 +-
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
index 9ac492980..1e4367816 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -1273,7 +1273,7 @@ wait_retry:
 
       int ret;
       acquire_input_mutex (mutex_timeout);
-      ret = process_input_message ();
+      ret = process_input_message (buflen);
       switch (ret)
 	{
 	case input_error:
@@ -1328,9 +1328,10 @@ sig_exit:
 }
 
 fhandler_console::input_states
-fhandler_console::process_input_message (void)
+fhandler_console::process_input_message (size_t len)
 {
   char tmp[60];
+  size_t num_chars = 0;
 
   if (!shared_console_info[unit])
     return input_error;
@@ -1717,6 +1718,7 @@ fhandler_console::process_input_message (void)
 	  continue;
 	}
 
+      num_chars += nread;
       if (toadd)
 	{
 	  ssize_t ret;
@@ -1734,15 +1736,22 @@ fhandler_console::process_input_message (void)
 		goto out;
 	    }
 	}
+      /* len == 0 if called from select.cc:peek_console() */
+      if (len && num_chars >= len)
+	goto out;
     }
 out:
+  if (len == 0)
+    /* If len == 0, cancel reading from console input buffer.
+       Clear readahead buffer. */
+    eat_readahead (-1);
   /* Discard processed recored. */
   DWORD discard_len = min (total_read, i + 1);
   /* If input is signalled, do not discard input here because
      tcflush() is already called from line_edit(). */
   if (stat == input_signalled && !(ti->c_lflag & NOFLSH))
     discard_len = 0;
-  if (discard_len)
+  if (discard_len && (len || stat != input_ok))
     {
       acquire_attach_mutex (mutex_timeout);
       DWORD resume_pid = attach_console (con.owner);
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 49e0e7983..322592bf1 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -2327,7 +2327,7 @@ private:
     fh->copy_from (this);
     return fh;
   }
-  input_states process_input_message ();
+  input_states process_input_message (size_t len);
   bg_check_types bg_check (int sig, bool dontsignal = false);
   void setup_io_mutex (void);
   DWORD __acquire_input_mutex (const char *fn, int ln, DWORD ms);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 523c46ee6..b72083447 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -1172,7 +1172,7 @@ peek_console (select_record *me, bool)
 	  if (!r || !events_read)
 	    break;
 	}
-      if (fhandler_console::input_winch == fh->process_input_message ()
+      if (fhandler_console::input_winch == fh->process_input_message (0)
 	  && global_sigs[SIGWINCH].sa_handler != SIG_IGN
 	  && global_sigs[SIGWINCH].sa_handler != SIG_DFL)
 	{
-- 
2.51.0