[PATCH v2] Cygwin: pty: Do not transfer input to nat-pipe while masked

Takashi Yano <[email protected]> Tue, 30 Jun 2026 17:14:29 +0900
Newsgroups gmane.os.cygwin.patches
Message-ID <[email protected]>
On the command "cat | non-cygwin-app", `cat` sometimes fails to read
key input. This happens when `cat` starts to read input before `non-
cygwin-app` configures pseudo console. This is because pipe state is
switched to nat-pipe when pseudo console is configured.

This patch prevent the pipe state from changing to nat-pipe state if
some cygwin process is reading input from the cyg-pipe.

Fixes: f20641789427 ("Cygwin: pty: Reduce unecessary input transfer.")
Signed-off-by: Takashi Yano <[email protected]>
Reviewed-by:
---
v2: Release all masks owned by myself on cleanup()

 winsup/cygwin/fhandler/pty.cc           | 33 +++++++++++++++++++++----
 winsup/cygwin/local_includes/fhandler.h |  3 +--
 winsup/cygwin/local_includes/tty.h      |  2 ++
 3 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 35e320507..54cd64a47 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -951,7 +951,7 @@ out:
 
 fhandler_pty_slave::fhandler_pty_slave (int unit, dev_t via)
   : fhandler_pty_common (), inuse (NULL), output_handle_nat (NULL),
-  io_handle_nat (NULL), slave_reading (NULL), num_reader (0)
+  io_handle_nat (NULL), masked_cnt (0)
 {
   dev_referred_via = via;
   if (unit >= 0)
@@ -1230,6 +1230,10 @@ fhandler_pty_slave::open_setup (int flags)
 void
 fhandler_pty_slave::cleanup ()
 {
+  fhandler_pty_slave *arch = (fhandler_pty_slave *) archetype ? : this;
+  while (arch->masked_cnt)
+    mask_switch_to_nat_pipe (false, false);
+
   if (get_ttyp ()->pcon_activated && get_ttyp ()->getpgid () == myself->pgid)
     req_fixup_pcon_state ();
 
@@ -1499,11 +1503,18 @@ fhandler_pty_slave::mask_switch_to_nat_pipe (bool mask, bool xfer)
   WaitForSingleObject (input_mutex, mutex_timeout);
   if (mask)
     {
-      if (InterlockedIncrement (&num_reader) == 1)
-	slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
+      if (InterlockedIncrement (&get_ttyp ()->num_reader) == 1)
+	get_ttyp ()->slave_reading =
+	  CreateEvent (&sec_none_nih, TRUE, FALSE, name);
     }
-  else if (InterlockedDecrement (&num_reader) == 0)
-    CloseHandle (slave_reading);
+  else if (InterlockedDecrement (&get_ttyp ()->num_reader) == 0)
+    CloseHandle (get_ttyp ()->slave_reading);
+
+  fhandler_pty_slave *arch = (fhandler_pty_slave *) archetype ? : this;
+  if (mask)
+    InterlockedIncrement (&arch->masked_cnt);
+  else
+    InterlockedDecrement (&arch->masked_cnt);
 
   if (!!masked != mask && xfer && get_ttyp ()->switch_to_nat_pipe)
     {
@@ -4401,6 +4412,18 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp,
 				    HANDLE input_available_event,
 				    HANDLE input_transferred_to_cyg)
 {
+  if (dir == tty::to_nat)
+    {
+      char name[MAX_PATH];
+      shared_name (name, TTY_SLAVE_READING, ttyp->get_minor ());
+      HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
+      CloseHandle (masked);
+      if (masked)
+	/* Cygwin process is reading cyg-pipe.
+	   Do not transfer input to nat-pipe. */
+	return;
+    }
+
   HANDLE to;
   if (dir == tty::to_nat)
     to = ttyp->to_slave_nat ();
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 8e9cbef4b..d8b6f5950 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -2442,8 +2442,7 @@ class fhandler_pty_slave: public fhandler_pty_common
 {
   HANDLE inuse;			// used to indicate that a tty is in use
   HANDLE output_handle_nat, io_handle_nat;
-  HANDLE slave_reading;
-  LONG num_reader;
+  LONG masked_cnt;
 
   /* Helper functions for fchmod and fchown. */
   bool fch_open_handles (bool chown);
diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h
index c5102eb81..407565ce9 100644
--- a/winsup/cygwin/local_includes/tty.h
+++ b/winsup/cygwin/local_includes/tty.h
@@ -146,6 +146,8 @@ private:
   bool discard_input;
   bool stop_fwd_thread;
   bool req_fixup_pcon_cur_pos;
+  HANDLE slave_reading;
+  LONG num_reader;
 
 public:
   HANDLE from_master_nat () const { return _from_master_nat; }
-- 
2.51.0