[PATCH 2/3] Cygwin: console: Fix NOFLSH mode a little

Takashi Yano <[email protected]> Thu, 11 Jun 2026 01:35:13 +0900
Newsgroups gmane.os.cygwin.patches
Message-ID <[email protected]>
If you run "stty noflsh; cat" in "bash", and stop "cat" by Ctrl-C,
a stray ^C is passed to "bash". The current code calls tcflush() if
NOFLSH is not set, however, tcflush() is not called when NOFLSH is
set. So, Ctrl-C remains in console input buffer. This should be
discarded even in NOFLSH mode. This patch introduces a helper
function discard_key_events() and call it to erase Ctrl-C in the
console input buffer.

Note that even with this patch, NOFLSH is not fully functional in
console because the readahead buffer is unique to process, so it
cannot be inherited to other processes. However, it should work
intra process.

Fixes: 118e51be1d04 ("(tty_min::kill_pgrp): Handle tty flush when signal detected.")
Signed-off-by: Takashi Yano <[email protected]>
Reviewed-by:
---
 winsup/cygwin/fhandler/console.cc       | 20 +++++++++++++++++---
 winsup/cygwin/fhandler/termios.cc       | 10 +++++++---
 winsup/cygwin/local_includes/fhandler.h |  2 ++
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
index a5e6cd89d..9ac492980 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -1744,17 +1744,31 @@ out:
     discard_len = 0;
   if (discard_len)
     {
-      DWORD discarded;
       acquire_attach_mutex (mutex_timeout);
       DWORD resume_pid = attach_console (con.owner);
-      ReadConsoleInputW (get_handle (), input_rec, discard_len, &discarded);
+      discard_key_events (discard_len);
       detach_console (resume_pid, con.owner);
       release_attach_mutex ();
-      con.num_processed -= min (con.num_processed, discarded);
     }
   return stat;
 }
 
+void
+fhandler_console::discard_key_events (size_t n)
+{
+  DWORD discarded = 0;
+  INPUT_RECORD input_rec[INREC_SIZE];
+  DWORD n1 = min (INREC_SIZE, n);
+  while (n)
+    {
+      ReadConsoleInputW (get_handle (), input_rec, n1, &n1);
+      n -= n1;
+      discarded += n1;
+      n1 = min (INREC_SIZE, n);
+    }
+  con.num_processed -= min (con.num_processed, discarded);
+}
+
 bool
 dev_console::fillin (HANDLE h)
 {
diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc
index ca5fa4b7e..605258731 100644
--- a/winsup/cygwin/fhandler/termios.cc
+++ b/winsup/cygwin/fhandler/termios.cc
@@ -666,9 +666,13 @@ fhandler_termios::sigflush ()
      be NULL while this is alive.  However, we can conceivably close a
      ctty while exiting and that will zero this. */
   if ((!have_execed || have_execed_cygwin) && tc ()
-      && (tc ()->getpgid () == myself->pgid)
-      && !(tc ()->ti.c_lflag & NOFLSH))
-    tcflush (TCIFLUSH);
+      && (tc ()->getpgid () == myself->pgid))
+    {
+      if (!(tc ()->ti.c_lflag & NOFLSH))
+	tcflush (TCIFLUSH);
+      else
+	discard_key_events (1);
+    }
 }
 
 pid_t
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 4f5605524..49e0e7983 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -1983,6 +1983,7 @@ class fhandler_termios: public fhandler_base
   pid_t tcgetsid ();
   virtual int fstat (struct stat *buf);
   int tcflow (int);
+  virtual void discard_key_events (size_t n) {}
 
   fhandler_termios (void *) {}
 
@@ -2363,6 +2364,7 @@ private:
   void wpbuf_put (char c);
   void wpbuf_send ();
   int fstat (struct stat *buf);
+  void discard_key_events (size_t n);
 
   class console_unit
   {
-- 
2.51.0