[newlib-cygwin] Cygwin: pty: Fixup pty state after a cygwin app exits
Takashi Yano via Cygwin-cvs <[email protected]> Wed, 24 Jun 2026 13:11:25 +0000 (GMT)
| Newsgroups | gmane.os.cygwin.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3Db34394d456b= 6d46fc112273183fc0cae5a613e18 commit b34394d456b6d46fc112273183fc0cae5a613e18 Author: Takashi Yano <[email protected]> Date: Sat Jun 13 22:02:14 2026 +0900 Cygwin: pty: Fixup pty state after a cygwin app exits =20 Previously, the cygwin process on pty is always a child of another cygwin app on pty. If a cygwin app is a child of non-cygwin app in pseudo console, it was running on console originating from pseudo console. Now, the child of a non-cygwin app on pseudo console is running on pty, so, it is necessary to restore the pty state to the state where the parent process is running. This patch does the following fixup when the cygwin process on pty exits: 1) Switch pipe mode from cyg-pipe to nat-pipe. 2) Notify the current cursor position to pseudo console =20 These prevent the problems: 1) Run 'cat' in cmd.exe and stop it by Ctrl-C. After that cmd.exe cannot receive key input. 2) Run 'ps' in cmd.exe. The cursor position will not be maintained correctly after that. =20 Signed-off-by: Takashi Yano <[email protected]> Reviewed-by: Mark Geisert <[email protected]> Diff: --- winsup/cygwin/fhandler/pty.cc | 79 +++++++++++++++++++++++++++++= ++-- winsup/cygwin/local_includes/fhandler.h | 2 + winsup/cygwin/local_includes/tty.h | 1 + 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 06babcde1..35e320507 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -388,6 +388,52 @@ atexit_func (void) } } =20 +void +fhandler_pty_slave::req_fixup_pcon_state (void) +{ + while (true) + { + WaitForSingleObject (input_mutex, mutex_timeout); + if (!get_ttyp ()->pcon_start_pid) + break; + /* Another request is on going. */ + ReleaseMutex (input_mutex); + yield (); + } + + DWORD n; + /* indicates that this "ESC[6n" is just for fixing-up cursor position */ + get_ttyp ()->req_fixup_pcon_cur_pos =3D true; + get_ttyp ()->req_xfer_input =3D true; /* indicates that this "ESC[6n" + is just for transfer input */ + get_ttyp ()->pcon_start =3D true; + get_ttyp ()->pcon_start_pid =3D myself->pid; + WriteFile (get_output_handle (), "\033[6n", 4, &n, NULL); + ReleaseMutex (input_mutex); + while (get_ttyp ()->pcon_start_pid) + /* wait for completion of fixing-up in master::write(). */ + yield (); +} + +void +fhandler_pty_master::fixup_pcon_cursor_position (int x, int y) +{ + HANDLE pcon_owner =3D OpenProcess (PROCESS_DUP_HANDLE, FALSE, + get_ttyp ()->nat_pipe_owner_pid); + HANDLE h_pcon_out =3D NULL; + DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out, + GetCurrentProcess (), &h_pcon_out, + 0, TRUE, DUPLICATE_SAME_ACCESS); + CloseHandle (pcon_owner); + DWORD target_pid =3D get_ttyp ()->nat_pipe_owner_pid; + DWORD resume_pid =3D + fhandler_pty_common::attach_console_temporarily (target_pid); + COORD cur_pos =3D {(SHORT) (x - 1), (SHORT) (y - 1)}; + SetConsoleCursorPosition (h_pcon_out, cur_pos); + fhandler_pty_common::resume_from_temporarily_attach (resume_pid); + CloseHandle (h_pcon_out); +} + #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig /* CreateProcess() is hooked for GDB etc. */ DEF_HOOK (CreateProcessA); @@ -1162,6 +1208,19 @@ err_no_msg: bool fhandler_pty_slave::open_setup (int flags) { + if (get_ttyp ()->pcon_activated) + { + HANDLE pcon_owner =3D OpenProcess (PROCESS_DUP_HANDLE, FALSE, + get_ttyp ()->nat_pipe_owner_pid); + DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_in, + GetCurrentProcess (), &get_handle_nat (), + 0, TRUE, DUPLICATE_SAME_ACCESS); + DuplicateHandle (pcon_owner, get_ttyp ()->h_pcon_out, + GetCurrentProcess (), &get_output_handle_nat (), + 0, TRUE, DUPLICATE_SAME_ACCESS); + CloseHandle (pcon_owner); + } + set_flags ((flags & ~O_TEXT) | O_BINARY); myself->set_ctty (this, flags); report_tty_counts (this, "opened", ""); @@ -1171,6 +1230,9 @@ fhandler_pty_slave::open_setup (int flags) void fhandler_pty_slave::cleanup () { + if (get_ttyp ()->pcon_activated && get_ttyp ()->getpgid () =3D=3D myself= ->pgid) + req_fixup_pcon_state (); + /* This used to always call fhandler_pty_common::close when we were exec= ing but that caused multiple closes of the handles associated with this p= ty. Since close_all_files is not called until after the cygwin process has @@ -2488,10 +2550,21 @@ fhandler_pty_master::write (const void *ptr, size_t= len) } if (state =3D=3D 2) { - /* req_xfer_input is true if "ESC[6n" was sent just for + /* req_fixup_pcon_cur_pos is true if "ESC[6n" was sent + for requesting cursor-position-fixup that is needed + when a non-cygwin app executes a cygwin app and the + cygwin app exits. + req_xfer_input is true if "ESC[6n" was sent just for triggering transfer_input() in master. In this case, the response sequence should not be written. */ - if (!get_ttyp ()->req_xfer_input) + if (get_ttyp ()->req_fixup_pcon_cur_pos) + { + int x, y; + sscanf (wpbuf, "\033[%d;%dR", &y, &x); + fixup_pcon_cursor_position (x, y); + get_ttyp ()->req_fixup_pcon_cur_pos =3D false; + } + else if (!get_ttyp ()->req_xfer_input) WriteFile (to_slave_nat, wpbuf, ixput, &n, NULL); ixput =3D 0; state =3D 0; @@ -4113,8 +4186,6 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, D= WORD force_switch_to) ttyp->pcon_activated =3D false; ttyp->switch_to_nat_pipe =3D false; ttyp->nat_pipe_owner_pid =3D 0; - ttyp->pcon_start =3D false; - ttyp->pcon_start_pid =3D 0; } if (ttyp->pcon_handle_ready_event) { diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_= includes/fhandler.h index 6c358a570..8e9cbef4b 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2533,6 +2533,7 @@ class fhandler_pty_slave: public fhandler_pty_common void setpgid_aux (pid_t pid); static void release_ownership_of_nat_pipe (tty *ttyp, fhandler_termios *= fh); void replace_nat_handles (HANDLE new_input, HANDLE new_output); + void req_fixup_pcon_state (void); }; =20 #define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit)) @@ -2641,6 +2642,7 @@ public: void apply_line_edit_to_transferred_input (); line_edit_status line_edit_maybe (const char *p, size_t len, termios&, ssize_t *n); + void fixup_pcon_cursor_position (int x, int y); }; =20 class fhandler_dev_null: public fhandler_base diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_inclu= des/tty.h index 507f7772e..c5102eb81 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -145,6 +145,7 @@ private: xfer_dir pty_input_state; bool discard_input; bool stop_fwd_thread; + bool req_fixup_pcon_cur_pos; =20 public: HANDLE from_master_nat () const { return _from_master_nat; }