diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index fda5a4ec9..abd62d72a 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1902,12 +1902,15 @@ class fhandler_termios: public fhandler_base virtual void release_input_mutex_if_necessary (void) {}; virtual void discard_input () {}; + /* Result status of processing keys in process_sigs(). */ enum process_sig_state { - signalled, - not_signalled, - not_signalled_but_done, - not_signalled_with_nat_reader, - done_with_debugger + signalled, /* Signalled normally */ + not_signalled, /* Not signalled at all */ + not_signalled_but_done, /* Not signalled, but CTRL_C_EVENT was sent. */ + not_signalled_with_nat_reader, /* Not signalled, but detected non-cygwin + process may be reading the tty. */ + done_with_debugger /* The key was processed (CTRL_C_EVENT was sent) + for inferior of GDB. */ }; public: diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index 767b28302..f82ac76dc 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -149,7 +149,8 @@ tty_min::kill_pgrp (int sig, pid_t target_pgid) if (!p || !p->exists () || p->ctty != ntty || p->pgid != target_pgid) continue; if (p->process_state & PID_NOTCYGWIN) - continue; + continue; /* Do not send signal to non-cygwin process to prevent + cmd.exe from crash. */ if (p == myself) killself = sig != __SIGSETPGRP && !exit_state; else @@ -309,32 +310,52 @@ fhandler_termios::echo_erase (int force) doecho ("\b \b", 3); } +/* The basic policy is as follows: + - The signal generated by key press will be sent only to cygwin process. + - For non-cygwin process, CTRL_C_EVENT will be sent on Ctrl-C. */ +/* The inferior of GDB is an exception. GDB does not support to hook signal + even if the inferior is a cygwin app. As a result, inferior cannot be + continued after interruption by Ctrl-C if SIGINT was sent. Therefore, + CTRL_C_EVENT rather than SIGINT is sent to the inferior of GDB. */ fhandler_termios::process_sig_state fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh) { termios &ti = ttyp->ti; pid_t pgid = ttyp->pgid; + /* The name *_nat stands for 'native' which means non-cygwin apps. */ pinfo leader (pgid); - bool cyg_leader = leader && !(leader->process_state & PID_NOTCYGWIN); + bool cyg_leader = /* The process leader is a cygwin process. */ + leader && !(leader->process_state & PID_NOTCYGWIN); bool ctrl_c_event_sent = false; bool need_discard_input = false; - bool pg_with_nat = false; - bool need_send_sig = false; - bool nat_shell = false; - bool cyg_reader = false; - bool with_debugger = false; - bool with_debugger_nat = false; + bool pg_with_nat = false; /* The process group has non-cygwin processes. */ + bool need_send_sig = false; /* There is process which need the signal. */ + bool nat_shell = false; /* The shell seems to be a non-cygwin process. */ + bool cyg_reader = false; /* Cygwin process is reading the tty. */ + bool with_debugger = false; /* GDB is debugging cygwin app. */ + bool with_debugger_nat = false; /* GDB is debugging non-cygwin app. */ winpids pids ((DWORD) 0); for (unsigned i = 0; i < pids.npids; i++) { _pinfo *p = pids[i]; + /* PID_NOTCYGWIN: check this for non-cygwin process. + PID_NEW_PG: check this ofr GDB with non-cygwin inferior in pty + without pcon enabled. In this case, the inferior is not + cygwin process list. PID_NEW_PG is set as a marker for + GDB with non-cygwin inferior in pty code. + !PID_CYGPARENT: check this for GDB with cygwin inferior. */ if (c == '\003' && p && p->ctty == ttyp->ntty && p->pgid == pgid && ((p->process_state & PID_NOTCYGWIN) || (p->process_state & PID_NEW_PG) || !(p->process_state & PID_CYGPARENT))) { + /* Ctrl-C event will be sent only to the processes attaching + to the same console. Therefore, attach to the console to + which the target process is attaching before sending the + CTRL_C_EVENT. After sending the event, reattach to the + console to which the process was previously attached. */ pinfo pinfo_resume = pinfo (myself->ppid); DWORD resume_pid = 0; if (pinfo_resume) @@ -361,7 +382,8 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh) && (p->process_state & PID_NOTCYGWIN)) GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, p->dwProcessId); else if ((!fh || fh->need_send_ctrl_c_event () || cyg_leader) - && !ctrl_c_event_sent) + && !ctrl_c_event_sent) /* cyg_leader is needed by GDB + with non-cygwin inferior */ { GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0); ctrl_c_event_sent = true; @@ -378,13 +400,13 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh) if (p && p->ctty == ttyp->ntty && p->pgid == pgid) { if (p->process_state & PID_NOTCYGWIN) - pg_with_nat = true; + pg_with_nat = true; /* The process group has non-cygwin process */ if (!(p->process_state & PID_NOTCYGWIN)) - need_send_sig = true; + need_send_sig = true; /* Process which needs signal exists */ if (!p->cygstarted) - nat_shell = true; + nat_shell = true; /* The shell seems to a non-cygwin shell */ if (p->process_state & PID_TTYIN) - cyg_reader = true; + cyg_reader = true; /* Theh process is reading the tty */ if (!p->cygstarted && !(p->process_state & PID_NOTCYGWIN) && (p != myself || being_debugged ()) && cyg_leader) /* inferior is cygwin app */ @@ -406,8 +428,12 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh) return done_with_debugger; } if (with_debugger_nat) - return not_signalled; - /* Send SIGQUIT to non-cygwin process. */ + return not_signalled; /* Do not process slgnal keys further. + The non-cygwin inferior of GDB cannot receive + the signals. */ + /* Send SIGQUIT to non-cygwin process. Non-cygwin app will not be alerted + by kill_pgrp(), however, QUIT key should quit the non-cygwin app + if it is started along with cygwin process from cygwin shell. */ if ((ti.c_lflag & ISIG) && CCEQ (ti.c_cc[VQUIT], c) && pg_with_nat && need_send_sig && !nat_shell) { @@ -426,7 +452,9 @@ fhandler_termios::process_sigs (char c, tty* ttyp, fhandler_termios *fh) sig = SIGINT; else if (CCEQ (ti.c_cc[VQUIT], c)) sig = SIGQUIT; - else if (pg_with_nat) + else if (pg_with_nat) /* If the process group has a non-cygwin process, + it cannot be suspended correctly. Therefore, + do not send SIGTSTP. */ goto not_a_sig; else if (CCEQ (ti.c_cc[VSUSP], c)) sig = SIGTSTP;