Re: [PATCH 1/3] Cygwin: console: Ensure the master thread runs only when it is supposed to
Takashi Yano <[email protected]> Mon, 29 Jun 2026 20:23:55 +0900
| Newsgroups | gmane.os.cygwin.patches |
|---|---|
| Message-ID | <[email protected]> |
Hi Johannes,
On Sat, 27 Jun 2026 10:34:20 +0200 (CEST)
Johannes Schindelin wrote:
> Hi Takashi & Mark,
>
> An AutoHotKey-based test I added to
> https://github.com/git-for-windows/msys2-runtime/pull/131 bisected a
> Ctrl-C regression to this commit after it landed on master: Ctrl-C stopped
> interrupting `cat` in the pipeline `cat | ping`. The diagnosis and the fix
> I would propose are below.
>
> On Thu, 11 Jun 2026, Takashi Yano wrote:
>
> > @@ -1190,8 +1191,8 @@ fhandler_console::bg_check (int sig, bool dontsignal)
> > in the same process group. */
> > if (sig == SIGTTIN && con.curr_input_mode != tty::cygwin)
> > {
> > - set_disable_master_thread (false, this);
> > set_input_mode (tty::cygwin, &tc ()->ti, get_handle_set ());
> > + set_disable_master_thread (false, this);
> > }
> > if (sig == SIGTTOU && con.curr_output_mode != tty::cygwin)
> > set_output_mode (tty::cygwin, &tc ()->ti, get_handle_set ());
> > @@ -2087,8 +2088,8 @@ fhandler_console::post_open_setup (int fd)
> > /* Setting-up console mode for cygwin app started from non-cygwin app. */
> > if (fd == 0)
> > {
> > - set_disable_master_thread (false, this);
> > set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
> > + set_disable_master_thread (false, this);
> > }
> > else if (fd == 1 || fd == 2)
> > set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
>
> The console only delivers Ctrl-C as a raw `0x03` byte (which the console
> master thread then reads and turns into a `SIGINT` for the foreground
> process group) while that thread is live. When the master thread is
> suspended or disabled, `set_input_mode (tty::cygwin)` instead requests
> `ENABLE_PROCESSED_INPUT`, so the console raises a `CTRL_C_EVENT` and the
> `0x03` byte never reaches the master thread.
>
> The reorder above has `set_input_mode (tty::cygwin)` run while
> `disable_master_thread` is still set, so `ENABLE_PROCESSED_INPUT` stays on
> and a cygwin program sharing a foreground pgrp with a non-cygwin program
> (e.g. the pipeline `cat | ping`) never receives its `SIGINT`. Clearing
> `disable_master_thread` first, so the mode is configured with the master
> thread already live, restores the previous behavior in both `bg_check ()`
> and `post_open_setup ()`. The disable paths and the synchronous suspension
> this commit added are load-bearing for non-cygwin programs and are left
> untouched, so the master thread is still reliably suspended for them.
>
> The fix I would propose is in
> https://github.com/git-for-windows/msys2-runtime/pull/131/commits/73aae37a62d8246e1abaac6e52d6c6bb89bc4c5d:
Thanks for catching this!
> -- snip --
> From 73aae37a62d8246e1abaac6e52d6c6bb89bc4c5d Mon Sep 17 00:00:00 2001
> From: Johannes Schindelin <[email protected]>
> Date: Fri, 26 Jun 2026 09:16:49 +0200
> Subject: [PATCH] Cygwin: console: re-enable the master thread before selecting
> cygwin input mode
>
> When a cygwin program and a non-cygwin program run in the same foreground
> process group (for example the pipeline `cat | ping`), Ctrl-C stopped
> interrupting the cygwin program after "Cygwin: console: Ensure the master
> thread runs only when it is supposed to".
>
> The console only delivers Ctrl-C as a raw 0x03 byte (which the console
> master thread reads and turns into a SIGINT for the foreground process
> group) while that thread is live. When it is suspended or disabled,
> set_input_mode (tty::cygwin) instead requests ENABLE_PROCESSED_INPUT, so
> the console raises a CTRL_C_EVENT and the 0x03 byte never reaches the
> master thread. The referenced commit reordered the two enable paths,
> bg_check () and post_open_setup (), so that set_input_mode (tty::cygwin)
> runs while disable_master_thread is still set; that leaves
> ENABLE_PROCESSED_INPUT on and the cygwin program never receives its SIGINT.
>
> Clear disable_master_thread before selecting cygwin input mode in those two
> paths, so the mode is configured with the master thread already live and
> ENABLE_PROCESSED_INPUT stays off. The disable paths and the synchronous
> suspension that the referenced commit added are left unchanged, so
> non-cygwin programs still get the master thread reliably suspended.
>
> Fixes: 733d5a953fa9 ("Cygwin: console: Ensure the master thread runs only when it is supposed to")
> Assisted-by: Opus 4.8
> Signed-off-by: Johannes Schindelin <[email protected]>
> ---
> winsup/cygwin/fhandler/console.cc | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
> index 0136652878..685e99d62c 100644
> --- a/winsup/cygwin/fhandler/console.cc
> +++ b/winsup/cygwin/fhandler/console.cc
> @@ -1147,8 +1147,8 @@ fhandler_console::bg_check (int sig, bool dontsignal)
> in the same process group. */
> if (sig == SIGTTIN && con.curr_input_mode != tty::cygwin)
> {
> - set_input_mode (tty::cygwin, &tc ()->ti, get_handle_set ());
> set_disable_master_thread (false, this);
> + set_input_mode (tty::cygwin, &tc ()->ti, get_handle_set ());
> }
> if (sig == SIGTTOU && con.curr_output_mode != tty::cygwin)
> set_output_mode (tty::cygwin, &tc ()->ti, get_handle_set ());
> @@ -2035,8 +2035,8 @@ fhandler_console::post_open_setup (int fd)
> /* Setting-up console mode for cygwin app started from non-cygwin app. */
> if (fd == 0)
> {
> - set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
> set_disable_master_thread (false, this);
> + set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
> }
> else if (fd == 1 || fd == 2)
> set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
> -- snap --
I think we also need the following.
diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
index d2ffaa0c4..340bc3f2e 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -991,6 +994,7 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p)
termios *ti = shared_console_info[unit] ?
&(shared_console_info[unit]->tty_min_state.ti) : &dummy;
/* Cleaning-up console mode for non-cygwin app. */
+ set_disable_master_thread (con.owner == GetCurrentProcessId ());
/* conmode can be tty::restore when non-cygwin app is
exec'ed from login shell. */
tty::cons_mode conmode = cons_mode_on_close (p);
@@ -998,7 +1002,6 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p)
set_output_mode (conmode, ti, p);
if (con.curr_input_mode != conmode)
set_input_mode (conmode, ti, p);
- set_disable_master_thread (con.owner == GetCurrentProcessId ());
}
/* Return the tty structure associated with a given tty number. If the
--
Takashi Yano <[email protected]>