diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 4226bfd695..c2d91ea117 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1941,6 +1941,8 @@ class fhandler_termios: public fhandler_base fh->copy_from (this); return fh; } + static bool path_iscygexec_a (LPCSTR n, LPSTR c); + static bool path_iscygexec_w (LPCWSTR n, LPWSTR c); }; enum ansi_intensity diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index da1d2e80f6..17de688f00 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -32,6 +32,7 @@ details. */ #include "sync.h" #include "child_info.h" #include "cygwait.h" +#include "winf.h" /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer is allocated using tmp_pathbuf!!! */ @@ -238,6 +239,33 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) char c = (char) wc; bool processed = false; termios &ti = ttyp->ti; + pinfo pi (ttyp->getpgid ()); + if (pi && pi->ctty == ttyp->ntty + && (pi->process_state & PID_NOTCYGWIN) + && input_rec[i].EventType == KEY_EVENT && c == '\003') + { + bool not_a_sig = false; + if (!CCEQ (ti.c_cc[VINTR], c) + && !CCEQ (ti.c_cc[VQUIT], c) + && !CCEQ (ti.c_cc[VSUSP], c)) + not_a_sig = true; + if (input_rec[i].Event.KeyEvent.bKeyDown) + { + /* CTRL_C_EVENT does not work for the process started with + CREATE_NEW_PROCESS_GROUP flag, so send CTRL_BREAK_EVENT + instead. */ + if (pi->process_state & PID_NEW_PG) + GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, + pi->dwProcessId); + else + GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0); + if (not_a_sig) + goto skip_writeback; + } + processed = true; + if (not_a_sig) + goto remove_record; + } switch (input_rec[i].EventType) { case KEY_EVENT: @@ -310,6 +338,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) processed = true; break; } +remove_record: if (processed) { /* Remove corresponding record. */ memmove (input_rec + i, input_rec + i + 1, @@ -458,16 +487,18 @@ void fhandler_console::set_input_mode (tty::cons_mode m, const termios *t, const handle_set_t *p) { - DWORD flags = 0, oflags; + DWORD oflags; WaitForSingleObject (p->input_mutex, mutex_timeout); GetConsoleMode (p->input_handle, &oflags); + DWORD flags = oflags + & (ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE); switch (m) { case tty::restore: - flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + flags |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; break; case tty::cygwin: - flags = ENABLE_WINDOW_INPUT; + flags |= ENABLE_WINDOW_INPUT; if (wincap.has_con_24bit_colors () && !con_is_legacy) flags |= ENABLE_VIRTUAL_TERMINAL_INPUT; else @@ -3555,10 +3586,32 @@ set_console_title (char *title) debug_printf ("title '%W'", buf); } +static bool NO_COPY gdb_inferior_noncygwin = false; +static void +set_console_mode_to_native () +{ + cygheap_fdenum cfd (false); + while (cfd.next () >= 0) + if (cfd->get_major () == DEV_CONS_MAJOR) + { + fhandler_console *cons = (fhandler_console *) (fhandler_base *) cfd; + if (cons->get_device () == cons->tc ()->getntty ()) + { + termios *cons_ti = &((tty *) cons->tc ())->ti; + fhandler_console::set_input_mode (tty::native, cons_ti, + cons->get_handle_set ()); + fhandler_console::set_output_mode (tty::native, cons_ti, + cons->get_handle_set ()); + break; + } + } +} + #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig /* CreateProcess() is hooked for GDB etc. */ DEF_HOOK (CreateProcessA); DEF_HOOK (CreateProcessW); +DEF_HOOK (ContinueDebugEvent); static BOOL WINAPI CreateProcessA_Hooked @@ -3568,6 +3621,9 @@ CreateProcessA_Hooked { if (f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) mutex_timeout = 0; /* to avoid deadlock in GDB */ + gdb_inferior_noncygwin = !fhandler_termios::path_iscygexec_a (n, c); + if (gdb_inferior_noncygwin) + set_console_mode_to_native (); return CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, si, pi); } @@ -3579,9 +3635,21 @@ CreateProcessW_Hooked { if (f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) mutex_timeout = 0; /* to avoid deadlock in GDB */ + gdb_inferior_noncygwin = !fhandler_termios::path_iscygexec_w (n, c); + if (gdb_inferior_noncygwin) + set_console_mode_to_native (); return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi); } +static BOOL WINAPI +ContinueDebugEvent_Hooked + (DWORD p, DWORD t, DWORD s) +{ + if (gdb_inferior_noncygwin) + set_console_mode_to_native (); + return ContinueDebugEvent_Orig (p, t, s); +} + void fhandler_console::fixup_after_fork_exec (bool execing) { @@ -3601,6 +3669,7 @@ fhandler_console::fixup_after_fork_exec (bool execing) /* CreateProcess() is hooked for GDB etc. */ DO_HOOK (NULL, CreateProcessA); DO_HOOK (NULL, CreateProcessW); + DO_HOOK (NULL, ContinueDebugEvent); } // #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS) diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index 3461d17856..b935a70bc3 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -147,6 +147,8 @@ tty_min::kill_pgrp (int sig) _pinfo *p = pids[i]; if (!p || !p->exists () || p->ctty != ntty || p->pgid != pgid) continue; + if (p->process_state & PID_NOTCYGWIN) + continue; if (p == myself) killself = sig != __SIGSETPGRP && !exit_state; else @@ -326,7 +328,48 @@ fhandler_termios::line_edit (const char *rptr, size_t nread, termios& ti, if (ti.c_iflag & ISTRIP) c &= 0x7f; - if (ti.c_lflag & ISIG) + winpids pids ((DWORD) 0); + bool need_check_sigs = get_ttyp ()->pcon_input_state_eq (tty::to_cyg); + if (get_ttyp ()->pcon_input_state_eq (tty::to_nat)) + { + bool need_discard_input = false; + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + if (c == '\003' && p && p->ctty == tc ()->ntty + && p->pgid == tc ()->getpgid () + && (p->process_state & PID_NOTCYGWIN)) + { + /* CTRL_C_EVENT does not work for the process started with + CREATE_NEW_PROCESS_GROUP flag, so send CTRL_BREAK_EVENT + instead. */ + if (p->process_state & PID_NEW_PG) + GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, + p->dwProcessId); + else + GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0); + need_discard_input = true; + } + if (p->ctty == get_ttyp ()->ntty + && p->pgid == get_ttyp ()->getpgid () && !p->cygstarted) + need_check_sigs = true; + } + if (!CCEQ (ti.c_cc[VINTR], c) + && !CCEQ (ti.c_cc[VQUIT], c) + && !CCEQ (ti.c_cc[VSUSP], c)) + need_check_sigs = false; + if (need_discard_input && !need_check_sigs) + { + if (!(ti.c_lflag & NOFLSH)) + { + eat_readahead (-1); + discard_input (); + } + ti.c_lflag &= ~FLUSHO; + continue; + } + } + if ((ti.c_lflag & ISIG) && need_check_sigs) { int sig; if (CCEQ (ti.c_cc[VINTR], c)) @@ -431,7 +474,7 @@ fhandler_termios::line_edit (const char *rptr, size_t nread, termios& ti, } continue; } - else if (CCEQ (ti.c_cc[VEOF], c)) + else if (CCEQ (ti.c_cc[VEOF], c) && need_check_sigs) { termios_printf ("EOF"); accept_input (); diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 10566ac918..a35cee0451 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -157,6 +157,66 @@ set_switch_to_pcon (HANDLE *in, HANDLE *out, HANDLE *err, bool iscygwin) *err = replace_err->get_output_handle_nat (); } +static bool +path_iscygexec_a_w (LPCSTR na, LPSTR ca, LPCWSTR nw, LPWSTR cw) +{ + path_conv path; + tmp_pathbuf tp; + char *prog =tp.c_get (); + if (na) + { + __small_sprintf (prog, "%s", na); + find_exec (prog, path); + } + else if (nw) + { + __small_sprintf (prog, "%W", nw); + find_exec (prog, path); + } + else + { + if (ca) + __small_sprintf (prog, "%s", ca); + else if (cw) + __small_sprintf (prog, "%W", cw); + else + return true; + char *p = prog; + char *p1; + do + if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p))) + { + p = p1; + if (*p == ' ') + { + *p = '\0'; + find_exec (prog, path); + *p = ' '; + p ++; + } + else if (*p == '\0') + find_exec (prog, path); + } + while (!path.exists() && *p); + } + const char *argv[] = {"", NULL}; /* Dummy */ + av av1; + av1.setup ("", path, "", 1, argv, false); + return path.iscygexec (); +} + +bool +fhandler_termios::path_iscygexec_a (LPCSTR n, LPSTR c) +{ + return path_iscygexec_a_w (n, c, NULL, NULL); +} + +bool +fhandler_termios::path_iscygexec_w (LPCWSTR n, LPWSTR c) +{ + return path_iscygexec_a_w (NULL, NULL, n, c); +} + static bool atexit_func_registered = false; static bool debug_process = false; @@ -220,37 +280,9 @@ CreateProcessA_Hooked siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); siov->hStdError = GetStdHandle (STD_ERROR_HANDLE); } - path_conv path; - tmp_pathbuf tp; - char *prog =tp.c_get (); - if (n) - __small_sprintf (prog, "%s", n); - else - { - __small_sprintf (prog, "%s", c); - char *p = prog; - char *p1; - do - if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p))) - { - p = p1; - if (*p == ' ') - { - *p = '\0'; - find_exec (prog, path); - *p = ' '; - p ++; - } - else if (*p == '\0') - find_exec (prog, path); - } - while (!path.exists() && *p); - } - const char *argv[] = {"", NULL}; /* Dummy */ - av av1; - av1.setup ("", path, "", 1, argv, false); + bool path_iscygexec = fhandler_termios::path_iscygexec_a (n, c); set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError, - path.iscygexec ()); + path_iscygexec); BOOL ret = CreateProcessA_Orig (n, c, pa, ta, inh, f, e, d, siov, pi); h_gdb_process = pi->hProcess; DuplicateHandle (GetCurrentProcess (), h_gdb_process, @@ -259,7 +291,7 @@ CreateProcessA_Hooked debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)); if (debug_process) mutex_timeout = 0; /* to avoid deadlock in GDB */ - if (!atexit_func_registered && !path.iscygexec ()) + if (!atexit_func_registered && !path_iscygexec) { atexit (atexit_func); atexit_func_registered = true; @@ -286,37 +318,9 @@ CreateProcessW_Hooked siov->hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); siov->hStdError = GetStdHandle (STD_ERROR_HANDLE); } - path_conv path; - tmp_pathbuf tp; - char *prog =tp.c_get (); - if (n) - __small_sprintf (prog, "%W", n); - else - { - __small_sprintf (prog, "%W", c); - char *p = prog; - char *p1; - do - if ((p1 = strchr (p, ' ')) || (p1 = p + strlen (p))) - { - p = p1; - if (*p == ' ') - { - *p = '\0'; - find_exec (prog, path); - *p = ' '; - p ++; - } - else if (*p == '\0') - find_exec (prog, path); - } - while (!path.exists() && *p); - } - const char *argv[] = {"", NULL}; /* Dummy */ - av av1; - av1.setup ("", path, "", 1, argv, false); + bool path_iscygexec = fhandler_termios::path_iscygexec_w (n, c); set_switch_to_pcon (&siov->hStdInput, &siov->hStdOutput, &siov->hStdError, - path.iscygexec ()); + path_iscygexec); BOOL ret = CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, siov, pi); h_gdb_process = pi->hProcess; DuplicateHandle (GetCurrentProcess (), h_gdb_process, @@ -325,7 +329,7 @@ CreateProcessW_Hooked debug_process = !!(f & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)); if (debug_process) mutex_timeout = 0; /* to avoid deadlock in GDB */ - if (!atexit_func_registered && !path.iscygexec ()) + if (!atexit_func_registered && !path_iscygexec) { atexit (atexit_func); atexit_func_registered = true; @@ -438,6 +442,9 @@ fhandler_pty_master::discard_input () while (::bytes_available (bytes_in_pipe, from_master) && bytes_in_pipe) ReadFile (from_master, buf, sizeof(buf), &n, NULL); ResetEvent (input_available_event); + if (!get_ttyp ()->pcon_activated) + while (::bytes_available (bytes_in_pipe, from_master_nat) && bytes_in_pipe) + ReadFile (from_master_nat, buf, sizeof(buf), &n, NULL); get_ttyp ()->discard_input = true; ReleaseMutex (input_mutex); } @@ -496,11 +503,9 @@ void fhandler_pty_master::doecho (const void *str, DWORD len) { ssize_t towrite = len; - acquire_output_mutex (mutex_timeout); if (!process_opost_output (echo_w, str, towrite, true, get_ttyp (), is_nonblocking ())) termios_printf ("Write to echo pipe failed, %E"); - release_output_mutex (); } int @@ -1124,7 +1129,7 @@ fhandler_pty_slave::reset_switch_to_pcon (void) if (WaitForSingleObject (h_gdb_process, 0) == WAIT_TIMEOUT) { if (isHybrid) - get_ttyp ()->wait_pcon_fwd (false); + get_ttyp ()->wait_pcon_fwd (); } else { @@ -2719,6 +2724,9 @@ fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p) for (;;) { p->ttyp->pcon_last_time = GetTickCount (); + DWORD n; + p->ttyp->pcon_fwd_not_empty = + ::bytes_available (n, p->from_slave_nat) && n; if (!ReadFile (p->from_slave_nat, outbuf, NT_MAX_PATH, &rlen, NULL)) { termios_printf ("ReadFile for forwarding failed, %E"); diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d7ee5fea79..434a4a0231 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -657,23 +657,18 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, } else if (fh && fh->get_major () == DEV_CONS_MAJOR) { - fhandler_console *cons = (fhandler_console *) fh; - if (!iscygwin ()) + if (!iscygwin () && cons_native == NULL) { - if (cons_native == NULL) - { - cons_native = cons; - cons_ti = &((tty *)cons->tc ())->ti; - cons_owner = cons->get_owner (); - } + fhandler_console *cons = (fhandler_console *) fh; + cons_native = cons; + cons_ti = &((tty *)cons->tc ())->ti; + cons_owner = cons->get_owner (); tty::cons_mode conmode = (ctty_pgid && ctty_pgid == myself->pgid) ? tty::native : tty::restore; - if (fd == 0) - fhandler_console::set_input_mode (conmode, + fhandler_console::set_input_mode (conmode, cons_ti, cons->get_handle_set ()); - else if (fd == 1 || fd == 2) - fhandler_console::set_output_mode (conmode, + fhandler_console::set_output_mode (conmode, cons_ti, cons->get_handle_set ()); } } diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index 7895288562..c0015aceb4 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -240,6 +240,7 @@ tty::init () pcon_pid = 0; term_code_page = 0; pcon_last_time = 0; + pcon_fwd_not_empty = false; pcon_start = false; pcon_start_pid = 0; pcon_cap_checked = false; @@ -308,7 +309,8 @@ tty_min::setpgid (int pid) fhandler_pty_slave *ptys = NULL; cygheap_fdenum cfd (false); while (cfd.next () >= 0 && ptys == NULL) - if (cfd->get_device () == getntty ()) + if (cfd->get_device () == getntty () + && cfd->get_major () == DEV_PTYS_MAJOR) ptys = (fhandler_pty_slave *) (fhandler_base *) cfd; if (ptys) @@ -367,7 +369,7 @@ tty_min::setpgid (int pid) } void -tty::wait_pcon_fwd (bool init) +tty::wait_pcon_fwd () { /* The forwarding in pseudo console sometimes stops for 16-32 msec even if it already has data to transfer. @@ -377,11 +379,11 @@ tty::wait_pcon_fwd (bool init) thread when the last data is transfered. */ const int sleep_in_pcon = 16; const int time_to_wait = sleep_in_pcon * 2 + 1/* margine */; - if (init) - pcon_last_time = GetTickCount (); - while (GetTickCount () - pcon_last_time < time_to_wait) + int elapsed; + while (pcon_fwd_not_empty + || (elapsed = GetTickCount () - pcon_last_time) < time_to_wait) { - int tw = time_to_wait - (GetTickCount () - pcon_last_time); + int tw = pcon_fwd_not_empty ? 10 : (time_to_wait - elapsed); cygwait (tw); } } diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h index 519d7c0d59..2cd12a665f 100644 --- a/winsup/cygwin/tty.h +++ b/winsup/cygwin/tty.h @@ -116,6 +116,7 @@ class tty: public tty_min DWORD pcon_pid; UINT term_code_page; DWORD pcon_last_time; + bool pcon_fwd_not_empty; HANDLE h_pcon_write_pipe; HANDLE h_pcon_condrv_reference; HANDLE h_pcon_conhost_process; @@ -166,7 +167,7 @@ class tty: public tty_min void set_master_ctl_closed () {master_pid = -1;} static void __stdcall create_master (int); static void __stdcall init_session (); - void wait_pcon_fwd (bool init = true); + void wait_pcon_fwd (); bool pcon_input_state_eq (xfer_dir x) { return pcon_input_state == x; } bool pcon_fg (pid_t pgid); friend class fhandler_pty_common;