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

Johannes Schindelin Johannes.Schindelin@gmx.de
Wed Jul 8 15:01:47 GMT 2026


Hi Takashi,

On Wed, 8 Jul 2026, Takashi Yano wrote:

> 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 <takashi.yano@nifty.ne.jp>
> Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> ---
> v2: Release all masks owned by myself on cleanup()
> v3: Reverts the change that made num_reader and slave_reading shared
> v4: Correct what mutex shoud be acquired in mask_switch_to_nat_pipe()

v4 is the right shape. Taking `input_mutex` at the top matches the
ordering used elsewhere in the file, and because it is a named mutex the
race is closed across processes attaching to the same tty, not just across
threads.

One non-blocking suggestion: As far as I can tell, the new guard is
correct only because every caller holds `input_mutex`. That is a non-local
invariant, and a short comment above the guard would help future refactors
preserve it.

  Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>

Ciao,
Johannes

>  winsup/cygwin/fhandler/pty.cc | 27 ++++++++++++++++++++++-----
>  1 file changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
> index ca85ae679..1b453a499 100644
> --- a/winsup/cygwin/fhandler/pty.cc
> +++ b/winsup/cygwin/fhandler/pty.cc
> @@ -1282,6 +1282,10 @@ fhandler_pty_slave::open_setup (int flags)
>  void
>  fhandler_pty_slave::cleanup ()
>  {
> +  fhandler_pty_slave *arch = (fhandler_pty_slave *) archetype ? : this;
> +  while (arch->num_reader)
> +    mask_switch_to_nat_pipe (false, false);
> +
>    if (get_ttyp ()->pcon_activated && get_ttyp ()->getpgid () == myself->pgid)
>      req_fixup_pcon_state ();
>  
> @@ -1543,19 +1547,20 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
>  void
>  fhandler_pty_slave::mask_switch_to_nat_pipe (bool mask, bool xfer)
>  {
> +  WaitForSingleObject (input_mutex, mutex_timeout);
>    char name[MAX_PATH];
>    shared_name (name, TTY_SLAVE_READING, get_minor ());
>    HANDLE masked = OpenEvent (READ_CONTROL, FALSE, name);
>    CloseHandle (masked);
>  
> -  WaitForSingleObject (input_mutex, mutex_timeout);
> +  fhandler_pty_slave *arch = (fhandler_pty_slave *) archetype ? : this;
>    if (mask)
>      {
> -      if (InterlockedIncrement (&num_reader) == 1)
> -	slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
> +      if (InterlockedIncrement (&arch->num_reader) == 1)
> +	arch->slave_reading = CreateEvent (&sec_none_nih, TRUE, FALSE, name);
>      }
> -  else if (InterlockedDecrement (&num_reader) == 0)
> -    CloseHandle (slave_reading);
> +  else if (InterlockedDecrement (&arch->num_reader) == 0)
> +    CloseHandle (arch->slave_reading);
>  
>    if (!!masked != mask && xfer && get_ttyp ()->switch_to_nat_pipe)
>      {
> @@ -4460,6 +4465,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 ();
> -- 
> 2.51.0
> 
> 


More information about the Cygwin-patches mailing list