[PATCH v3] Cygwin: pty: Make Ctrl-C work for non-cygwin app in GDB

Takashi Yano takashi.yano@nifty.ne.jp
Wed Apr 15 04:13:29 GMT 2026


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.

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.

Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
---
 winsup/cygwin/fhandler/pty.cc        | 32 +++++++++------------
 winsup/cygwin/fhandler/termios.cc    | 27 ++++++-----------
 winsup/cygwin/local_includes/pinfo.h | 43 ++++++++++++++++++++++++++--
 winsup/cygwin/tty.cc                 |  7 ++---
 4 files changed, 65 insertions(+), 44 deletions(-)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index cdfb363c9..cc74c8726 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -249,7 +249,6 @@ void release_attach_mutex (void)
 static bool isHybrid; /* Set true if the active pipe is set to nat pipe
 			 owned by myself even though the current process
 			 is a cygwin process. */
-static HANDLE h_gdb_inferior; /* Handle of GDB inferior process. */
 
 static void
 set_switch_to_nat_pipe (HANDLE *in, HANDLE *out, HANDLE *err)
@@ -362,9 +361,9 @@ atexit_func (void)
 	if (cfd->get_device () == (dev_t) myself->ctty)
 	  {
 	    DWORD force_switch_to = 0;
-	    if (WaitForSingleObject (h_gdb_inferior, 0) == WAIT_TIMEOUT
-		&& !debug_process)
-	      force_switch_to = GetProcessId (h_gdb_inferior);
+	    if (WaitForSingleObject (myself->h_debuggee_maybe, 0)
+		== WAIT_TIMEOUT && !debug_process)
+	      force_switch_to = GetProcessId (myself->h_debuggee_maybe);
 	    fhandler_base *fh = cfd;
 	    fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
 	    tty *ttyp = (tty *) ptys->tc ();
@@ -383,7 +382,7 @@ atexit_func (void)
 							    force_switch_to);
 	    break;
 	  }
-      CloseHandle (h_gdb_inferior);
+      CloseHandle (myself->h_debuggee_maybe);
     }
 }
 
@@ -416,9 +415,9 @@ CreateProcessA_Hooked
     set_switch_to_nat_pipe (&siov->hStdInput, &siov->hStdOutput,
 			    &siov->hStdError);
   BOOL ret = CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
-  h_gdb_inferior = pi->hProcess;
-  DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
-		   GetCurrentProcess (), &h_gdb_inferior,
+  myself->h_debuggee_maybe = pi->hProcess;
+  DuplicateHandle (GetCurrentProcess (), myself->h_debuggee_maybe,
+		   GetCurrentProcess (), &myself->h_debuggee_maybe,
 		   0, 0, DUPLICATE_SAME_ACCESS);
   debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
   if (debug_process)
@@ -455,9 +454,9 @@ CreateProcessW_Hooked
     set_switch_to_nat_pipe (&siov->hStdInput, &siov->hStdOutput,
 			    &siov->hStdError);
   BOOL ret = CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, siov, pi);
-  h_gdb_inferior = pi->hProcess;
-  DuplicateHandle (GetCurrentProcess (), h_gdb_inferior,
-		   GetCurrentProcess (), &h_gdb_inferior,
+  myself->h_debuggee_maybe = pi->hProcess;
+  DuplicateHandle (GetCurrentProcess (), myself->h_debuggee_maybe,
+		   GetCurrentProcess (), &myself->h_debuggee_maybe,
 		   0, 0, DUPLICATE_SAME_ACCESS);
   debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS));
   if (debug_process)
@@ -1236,9 +1235,6 @@ fhandler_pty_slave::set_switch_to_nat_pipe (void)
     {
       isHybrid = true;
       setup_locale ();
-      myself->exec_dwProcessId = myself->dwProcessId; /* Set this as a marker
-							 for tty::nat_fg()
-							 and process_sigs() */
       bool stdin_is_ptys = GetStdHandle (STD_INPUT_HANDLE) == get_handle ();
       setup_for_non_cygwin_app (false, NULL, stdin_is_ptys);
     }
@@ -1259,17 +1255,17 @@ nat_pipe_owner_self (DWORD pid)
 void
 fhandler_pty_slave::reset_switch_to_nat_pipe (void)
 {
-  if (h_gdb_inferior)
+  if (myself->h_debuggee_maybe)
     {
-      if (WaitForSingleObject (h_gdb_inferior, 0) == WAIT_TIMEOUT)
+      if (WaitForSingleObject (myself->h_debuggee_maybe, 0) == WAIT_TIMEOUT)
 	{
 	  if (isHybrid)
 	    get_ttyp ()->wait_fwd ();
 	}
       else
 	{
-	  CloseHandle (h_gdb_inferior);
-	  h_gdb_inferior = NULL;
+	  CloseHandle (myself->h_debuggee_maybe);
+	  myself->h_debuggee_maybe = NULL;
 	  mutex_timeout = INFINITE;
 	  if (isHybrid)
 	    {
diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc
index 694a5c20f..d5721494d 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, fhandler_termios *fh)
   for (unsigned i = 0; i < pids.npids; i++)
     {
       _pinfo *p = pids[i];
-      /* PID_NOTCYGWIN: check this for non-cygwin process.
-	 exec_dwProcessId == 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 == '\003' && p && p->ctty == ttyp->ntty && p->pgid == pgid
-	  && ((p->process_state & PID_NOTCYGWIN)
-	      || ((p->exec_dwProcessId == p->dwProcessId)
-		  && ttyp->pty_input_state_eq (tty::to_nat))
-	      || !(p->process_state & PID_CYGPARENT)))
+      if (c == '\003' && p && p->ctty == ttyp->ntty
+	  && (p->is_foreground_special_process (pgid)
+	      || p->is_gdb_with_foreground_non_cygwin_inferior (ttyp)))
 	{
 	  /* 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, fhandler_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 == p->dwProcessId)
+		    || p->is_gdb_with_foreground_non_cygwin_inferior (ttyp))
 		   && !ctrl_c_event_sent)
 	    {
 	      GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0);
@@ -403,12 +393,11 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh)
 	  if (!p->cygstarted && !(p->process_state & PID_NOTCYGWIN)
 	      && (p->process_state & PID_DEBUGGED))
 	    with_debugger = true; /* inferior is cygwin app */
-	  if (!(p->process_state & PID_NOTCYGWIN)
-	      && (p->exec_dwProcessId == p->dwProcessId) /* Check marker */
-	      && ttyp->pty_input_state_eq (tty::to_nat)
-	      && p->pid == pgid)
-	    with_debugger_nat = true; /* inferior is non-cygwin app */
 	}
+      if (p &&  p->ctty == ttyp->ntty
+	  && !(p->process_state & PID_NOTCYGWIN)
+	  && p->is_gdb_with_foreground_non_cygwin_inferior (ttyp))
+	with_debugger_nat = true; /* inferior is non-cygwin app */
     }
   if ((with_debugger || with_debugger_nat) && need_discard_input)
     {
diff --git a/winsup/cygwin/local_includes/pinfo.h b/winsup/cygwin/local_includes/pinfo.h
index d1c9b001b..9553ce1eb 100644
--- a/winsup/cygwin/local_includes/pinfo.h
+++ b/winsup/cygwin/local_includes/pinfo.h
@@ -10,6 +10,7 @@ details. */
 
 #include <sys/resource.h>
 #include "thread.h"
+#include "tty.h"
 
 union commune_result
 {
@@ -46,6 +47,9 @@ enum picom
 
 class fhandler_pipe;
 
+pid_t create_cygwin_pid ();
+pid_t cygwin_pid (DWORD);
+
 class _pinfo
 {
 public:
@@ -126,10 +130,46 @@ public:
   bool exists ();
   const char *_ctty (char *);
 
+  /* "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 != 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 != tty_pgid)
+      return false;
+    return !!(process_state & PID_NOTCYGWIN);
+  }
+  inline bool is_gdb_with_foreground_non_cygwin_inferior (tty *ttyp)
+  {
+    if (h_debuggee_maybe == NULL)
+      return false;
+    if (cygwin_pid (GetProcessId (h_debuggee_maybe)))
+      return false;
+    return ttyp->pty_input_state_eq (tty::to_nat);
+  }
+  inline bool is_gdb_with_foreground_non_cygwin_inferior (pid_t tty_pgid)
+  {
+    if (pgid == tty_pgid) /* GDB is the foreground process */
+      return false;
+    if (h_debuggee_maybe == NULL)
+      return false;
+    /* Below is true for GDB with non-cygwin inferior */
+    return !cygwin_pid (GetProcessId (h_debuggee_maybe));
+  }
+
   /* signals */
   HANDLE sendsig;
   HANDLE exec_sendsig;
   DWORD exec_dwProcessId;
+
+  HANDLE h_debuggee_maybe;
 public:
   friend class pinfo_minimal;
 };
@@ -254,9 +294,6 @@ public:
   void release ();
 };
 
-pid_t create_cygwin_pid ();
-pid_t cygwin_pid (DWORD);
-
 void pinfo_init (char **, int);
 extern pinfo myself;
 
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index 40b270309..e8083dc1f 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -341,10 +341,9 @@ tty::nat_fg (pid_t pgid)
   for (unsigned i = 0; i < pids.npids; i++)
     {
       _pinfo *p = pids[i];
-      if (p->ctty == ntty && p->pgid == pgid
-	  && ((p->process_state & PID_NOTCYGWIN)
-	      /* Below is true for GDB with non-cygwin inferior */
-	      || p->exec_dwProcessId == p->dwProcessId))
+      if (p->ctty == ntty
+	  && (p->is_foreground_non_cygwin_process (pgid)
+	      || p->is_gdb_with_foreground_non_cygwin_inferior (pgid)))
 	return true;
     }
   if (pgid > MAX_PID)
-- 
2.51.0



More information about the Cygwin-patches mailing list