[newlib-cygwin/cygwin-3_6-branch] Cygwin: pty: Make Ctrl-C work for non-cygwin app in GDB

Takashi Yano via Cygwin-cvs <[email protected]> Fri, 17 Apr 2026 17:41:02 +0000 (GMT)
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D5c29d7aee5b=
c01cb829d1380c1ec419b87615190

commit 5c29d7aee5bc01cb829d1380c1ec419b87615190
Author: Takashi Yano <[email protected]>
Date:   Sat Feb 28 15:48:51 2026 +0900

    Cygwin: pty: Make Ctrl-C work for non-cygwin app in GDB
   =20
    At some point in the past, GDB sets terminal pgid to inferior pid
    when the inferior is running. Moreover, the inferior is non-cygwin
    process, GDB sets the terminal pgid to windows pid of the inferior.
    Due to this behaviour, Ctrl-C does not work if the inferior is a
    non-cygwin app. This is because, the current code sends Ctrl-C to
    GDB only when GDB's pgid equeals to terminal pgid. This patch omit
    checking pgid when recognizing GDB process whose inferior is non-
    cygwin app. This patch also fixes the issue that the cygwin debuggee
    under strace cannot be terminated by Ctrl-C.
   =20
    In addition, to improve the readabiliby of the code, this patch
    introduces inline functions such as:
    is_foreground_special_process (),
    is_gdb_with_foreground_non_cygwin_inferior (), etc.,
    instead of complicated conditions in 'if' clauses.
   =20
    Signed-off-by: Takashi Yano <[email protected]>
    Reviewed-by: Johannes Schindelin <[email protected]>
    Reviewed-by: Corinna Vinschen <[email protected]>
    (cherry picked from commit 10a3de565b1c26a3c600148fa6e478e3501cbbc2)

Diff:
---
 winsup/cygwin/exceptions.cc          |  4 +--
 winsup/cygwin/fhandler/pty.cc        |  7 +++--
 winsup/cygwin/fhandler/termios.cc    | 54 ++++++++++++++------------------=
----
 winsup/cygwin/local_includes/pinfo.h | 42 ++++++++++++++++++++++++++--
 winsup/cygwin/tty.cc                 |  7 ++---
 5 files changed, 69 insertions(+), 45 deletions(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index b49adc345..138ef5a74 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1202,8 +1202,8 @@ ctrl_c_handler (DWORD type)
   if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
     return TRUE;
=20
-  if (type =3D=3D CTRL_C_EVENT && ::cygheap->ctty
-      && !cygheap->ctty->need_console_handler ())
+  if (type =3D=3D CTRL_C_EVENT && !myself->is_cygwin_inferior_being_debugg=
ed ()
+      && ::cygheap->ctty && !cygheap->ctty->need_console_handler ())
     /* Ctrl-C is handled in fhandler_console::cons_master_thread(). */
     return TRUE;
=20
diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 4c10ae32d..cae047a08 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -219,6 +219,7 @@ atexit_func (void)
 	    break;
 	  }
       CloseHandle (h_gdb_inferior);
+      myself->wpid_debuggee_maybe =3D 0;
     }
 }
=20
@@ -255,6 +256,7 @@ CreateProcessA_Hooked
   DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
 		   GetCurrentProcess (), &h_gdb_inferior,
 		   0, 0, DUPLICATE_SAME_ACCESS);
+  myself->wpid_debuggee_maybe =3D pi->dwProcessId;
   debug_process =3D !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
   if (debug_process)
     mutex_timeout =3D 0; /* to avoid deadlock in GDB */
@@ -294,6 +296,7 @@ CreateProcessW_Hooked
   DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
 		   GetCurrentProcess (), &h_gdb_inferior,
 		   0, 0, DUPLICATE_SAME_ACCESS);
+  myself->wpid_debuggee_maybe =3D pi->dwProcessId;
   debug_process =3D !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
   if (debug_process)
     mutex_timeout =3D 0; /* to avoid deadlock in GDB */
@@ -1071,9 +1074,6 @@ fhandler_pty_slave::set_switch_to_nat_pipe (void)
     {
       isHybrid =3D true;
       setup_locale ();
-      myself->exec_dwProcessId =3D myself->dwProcessId; /* Set this as a m=
arker
-							 for tty::nat_fg()
-							 and process_sigs() */
       bool stdin_is_ptys =3D GetStdHandle (STD_INPUT_HANDLE) =3D=3D get_ha=
ndle ();
       setup_for_non_cygwin_app (false, NULL, stdin_is_ptys);
     }
@@ -1105,6 +1105,7 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void)
 	{
 	  CloseHandle (h_gdb_inferior);
 	  h_gdb_inferior =3D NULL;
+	  myself->wpid_debuggee_maybe =3D 0;
 	  mutex_timeout =3D INFINITE;
 	  if (isHybrid)
 	    {
diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/ter=
mios.cc
index 01d00daed..e2822c3ee 100644
--- a/winsup/cygwin/fhandler/termios.cc
+++ b/winsup/cygwin/fhandler/termios.cc
@@ -338,19 +338,9 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fha=
ndler_termios *fh)
   for (unsigned i =3D 0; i < pids.npids; i++)
     {
       _pinfo *p =3D pids[i];
-      /* PID_NOTCYGWIN: check this for non-cygwin process.
-	 exec_dwProcessId =3D=3D dwProcessId:
-		     check this for GDB with non-cygwin inferior in pty
-		     without pcon enabled. In this case, the inferior is not
-		     cygwin process list. This condition is set true as
-		     a marker for GDB with non-cygwin inferior in pty code.
-	 !PID_CYGPARENT: check this for GDB with cygwin inferior or
-			 cygwin apps started from non-cygwin shell. */
-      if (c =3D=3D '\003' && p && p->ctty =3D=3D ttyp->ntty && p->pgid =3D=
=3D pgid
-	  && ((p->process_state & PID_NOTCYGWIN)
-	      || ((p->exec_dwProcessId =3D=3D p->dwProcessId)
-		  && ttyp->pty_input_state_eq (tty::to_nat))
-	      || !(p->process_state & PID_CYGPARENT)))
+      if (c =3D=3D '\003' && p && p->ctty =3D=3D ttyp->ntty
+	  && (p->is_foreground_special_process (pgid)
+	      || p->is_gdb_with_foreground_non_cygwin_inferior (pgid)))
 	{
 	  /* Ctrl-C event will be sent only to the processes attaching
 	     to the same console. Therefore, attach to the console to
@@ -372,7 +362,7 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhan=
dler_termios *fh)
 	  if (p->process_state & PID_NEW_PG)
 	    GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, p->dwProcessId);
 	  else if ((!fh || fh->need_send_ctrl_c_event ()
-		    || p->exec_dwProcessId =3D=3D p->dwProcessId)
+		    || p->is_gdb_with_foreground_non_cygwin_inferior (pgid))
 		   && !ctrl_c_event_sent)
 	    {
 	      GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0);
@@ -390,24 +380,23 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fh=
andler_termios *fh)
 	    }
 	  need_discard_input =3D true;
 	}
-      if (p && p->ctty =3D=3D ttyp->ntty && p->pgid =3D=3D pgid)
+      if (p && p->ctty =3D=3D ttyp->ntty)
 	{
-	  if (p->process_state & PID_NOTCYGWIN)
-	    pg_with_nat =3D true; /* The process group has non-cygwin process */
-	  if (!(p->process_state & PID_NOTCYGWIN))
-	    need_send_sig =3D true; /* Process which needs signal exists */
-	  if (!p->cygstarted)
-	    nat_shell =3D true; /* The shell seems to a non-cygwin shell */
-	  if (p->process_state & PID_TTYIN)
-	    cyg_reader =3D true; /* Theh process is reading the tty */
-	  if (!p->cygstarted && !(p->process_state & PID_NOTCYGWIN)
-	      && (p->process_state & PID_DEBUGGED))
-	    with_debugger =3D true; /* inferior is cygwin app */
-	  if (!(p->process_state & PID_NOTCYGWIN)
-	      && (p->exec_dwProcessId =3D=3D p->dwProcessId) /* Check marker */
-	      && ttyp->pty_input_state_eq (tty::to_nat)
-	      && p->pid =3D=3D pgid)
-	    with_debugger_nat =3D true; /* inferior is non-cygwin app */
+	  if (p->pgid =3D=3D pgid)
+	    {
+	      if (p->process_state & PID_NOTCYGWIN)
+		pg_with_nat =3D true; /* The process group has non-cygwin app */
+	      if (!(p->process_state & PID_NOTCYGWIN))
+		need_send_sig =3D true; /* Process which needs signal exists */
+	      if (!p->cygstarted)
+		nat_shell =3D true; /* The shell seems to a non-cygwin shell */
+	      if (p->process_state & PID_TTYIN)
+		cyg_reader =3D true; /* Theh process is reading the tty */
+	      if (p->is_cygwin_inferior_being_debugged ())
+		with_debugger =3D true;
+	    }
+	  if (p->is_gdb_with_foreground_non_cygwin_inferior (pgid))
+	    with_debugger_nat =3D true;
 	}
     }
   if ((with_debugger || with_debugger_nat) && need_discard_input)
@@ -536,10 +525,9 @@ fhandler_termios::line_edit (const char *rptr, size_t =
nread, termios& ti,
       switch (process_sigs (c, get_ttyp (), this))
 	{
 	case signalled:
-	  sawsig =3D true;
-	  fallthrough;
 	case not_signalled_but_done:
 	case done_with_debugger:
+	  sawsig =3D true;
 	  get_ttyp ()->output_stopped =3D false;
 	  continue;
 	case not_signalled_with_nat_reader:
diff --git a/winsup/cygwin/local_includes/pinfo.h b/winsup/cygwin/local_inc=
ludes/pinfo.h
index d1c9b001b..6f817de6b 100644
--- a/winsup/cygwin/local_includes/pinfo.h
+++ b/winsup/cygwin/local_includes/pinfo.h
@@ -46,6 +46,9 @@ enum picom
=20
 class fhandler_pipe;
=20
+pid_t create_cygwin_pid ();
+pid_t cygwin_pid (DWORD);
+
 class _pinfo
 {
 public:
@@ -126,10 +129,46 @@ public:
   bool exists ();
   const char *_ctty (char *);
=20
+  /* "Special" here means a non-cygwin process or a process whose parent
+     is not a cygwin process */
+  inline bool is_foreground_special_process (pid_t tty_pgid)
+  {
+    if (pgid !=3D tty_pgid) /* The process is background */
+      return false;
+    if (!(process_state & PID_CYGPARENT))
+      return true;
+    return !!(process_state & PID_NOTCYGWIN);
+  }
+  inline bool is_foreground_non_cygwin_process (pid_t tty_pgid)
+  {
+    if (pgid !=3D tty_pgid)
+      return false;
+    return !!(process_state & PID_NOTCYGWIN);
+  }
+  inline bool is_gdb_with_foreground_non_cygwin_inferior (pid_t tty_pgid)
+  {
+    if (pgid =3D=3D tty_pgid) /* GDB is the foreground process */
+      return false;
+    if (wpid_debuggee_maybe =3D=3D 0)
+      return false;
+    /* Below is true for GDB with non-cygwin inferior */
+    return !cygwin_pid (wpid_debuggee_maybe);
+  }
+  inline bool is_cygwin_inferior_being_debugged ()
+  {
+    if (cygstarted)
+      return false;
+    if (process_state & PID_NOTCYGWIN)
+      return false;
+    return !!(process_state & PID_DEBUGGED);
+  }
+
   /* signals */
   HANDLE sendsig;
   HANDLE exec_sendsig;
   DWORD exec_dwProcessId;
+
+  DWORD wpid_debuggee_maybe;
 public:
   friend class pinfo_minimal;
 };
@@ -254,9 +293,6 @@ public:
   void release ();
 };
=20
-pid_t create_cygwin_pid ();
-pid_t cygwin_pid (DWORD);
-
 void pinfo_init (char **, int);
 extern pinfo myself;
=20
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 0c49dc2bd..c8730e81c 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -340,10 +340,9 @@ tty::nat_fg (pid_t pgid)
   for (unsigned i =3D 0; i < pids.npids; i++)
     {
       _pinfo *p =3D pids[i];
-      if (p->ctty =3D=3D ntty && p->pgid =3D=3D pgid
-	  && ((p->process_state & PID_NOTCYGWIN)
-	      /* Below is true for GDB with non-cygwin inferior */
-	      || p->exec_dwProcessId =3D=3D p->dwProcessId))
+      if (p->ctty =3D=3D ntty
+	  && (p->is_foreground_non_cygwin_process (pgid)
+	      || p->is_gdb_with_foreground_non_cygwin_inferior (pgid)))
 	return true;
     }
   if (pgid > MAX_PID)