From c846bca9921f577956499aa0d8463c04e5694d46 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 22 Apr 2015 13:22:59 +0200 Subject: [PATCH] Fix OPOST for non-Cygwin pty slaves * fhandler.h (class fhandler_base): Add virtual function get_io_handle_cyg() to get handle from which OPOST-processed output is read on PTY master. (class fhandler_pty_slave): Add variable output_handle_cyg to store a handle to which OPOST-processed output is written. Add two functions, i.e., set_output_handle_cyg() and get_output_handle_cyg(), regarding variable output_handle_cyg. Now, output_handle is used only by native windows program. The data before OPOST-processing is written to output_handle and OPOST-processing is applied in the master-side. For a cygwin process, OPOST-processing is applied in the slave-side, and the data after OPOST-processing is written to output_handle_cyg. (class fhandler_pty_master): Add two variables, i.e., io_handle_cyg and to_master_cyg, to store handles of a pipe through which OPOST-processed output passes. Add pty_master_fwd_thread and function pty_master_fwd_thread() for a thread which applies OPOST-processing and forwards data from io_handle to to_master_cyg. Add function get_io_handle_cyg() regarding variable io_handle_cyg. Now, the pipe between io_handle and to_master are used only by native windows program for applying OPOST-processing in the master-side. For a cygwin process, the pipe between io_handle_cyg and to_master_cyg is used for passing through the data which is applied OPOST-processing in the slave-side. * fhandler_tty.cc (struct pipe_reply): Add member to_master_cyg. (fhandler_pty_master::process_slave_output): Read slave output from io_handle_cyg rather than io_handle. (fhandler_pty_slave::fhandler_pty_salve): Initialize output_handle_cyg. (fhandler_pty_slave::open): Set output_handle_cyg by duplicating handle to_master_cyg on PTY master. (fhandler_pty_slave::close): Close handle output_handle_cyg. (fhandler_pty_slave::write): Write data to output_handle_cyg rather than output_handle. (fhandler_pty_slave::fch_close_handles): Close handle output_handle_cyg. (fhandler_pty_master::fhandler_pty_master): Initialize io_handle_cyg, to_master_cyg and master_fwd_thread. (fhandler_pty_master::cleanup): Clean up to_master_cyg as well. (fhandler_pty_master::close): Print to_master_cyg as well in debug message. Terminate master forwarding thread. Close handles to_master_cyg and io_handle_cyg. (fhandler_pty_master::ioctl): Use io_handle_cyg rather than to_master. (fhandler_pty_master::pty_master_thread): Add code for duplicating handle to_master_cyg. (fhandler_pty_master::pty_master_fwd_thread): New function for a thread to forward OPOST-processed data from io_handle to to_master_cyg. This thread applies OPOST-processing to the output of native windows program. (::pty_master_fwd_thread): Ditto. (fhandler_pty_master::setup): Create a new pipe to pass thruegh OPOST- processed output. Create new thread to forward data from io_handle to to_master_cyg. Set handle to_master_cyg to tty. Print io_handle_cyg as well in debug message. Close handles io_handle_cyg and to_master_cyg in case of error. (fhandler_pty_master::fixup_after_fork): Set handle to_master_cyg to tty. Copy handle to_master_cyg from arch->to_master_cyg. (fhandler_pty_master::fixup_after_exec): Clean up to_master_cyg. * select.cc: Check handle returned by get_io_handle_cyg() rather than get_handle(). * tty.h (class tty): Add variable _to_master_cyg to store a handle to which OPOST-processed data is written. Add two functions, to_master_cyg() and set_to_master_cyg(), regarding _to_master_cyg. Signed-off-by: Corinna Vinschen --- winsup/cygwin/ChangeLog | 60 +++++++++++++++++ winsup/cygwin/fhandler.h | 9 +++ winsup/cygwin/fhandler_tty.cc | 121 +++++++++++++++++++++++++++++----- winsup/cygwin/select.cc | 4 +- winsup/cygwin/tty.h | 3 + 5 files changed, 178 insertions(+), 19 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb79fcc07..7e9de3f72 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,63 @@ +2015-04-22 Takashi Yano + + * fhandler.h (class fhandler_base): Add virtual function + get_io_handle_cyg() to get handle from which OPOST-processed output is + read on PTY master. + (class fhandler_pty_slave): Add variable output_handle_cyg to store a + handle to which OPOST-processed output is written. Add two functions, + i.e., set_output_handle_cyg() and get_output_handle_cyg(), regarding + variable output_handle_cyg. Now, output_handle is used only by native + windows program. The data before OPOST-processing is written to + output_handle and OPOST-processing is applied in the master-side. For a + cygwin process, OPOST-processing is applied in the slave-side, and the + data after OPOST-processing is written to output_handle_cyg. + (class fhandler_pty_master): Add two variables, i.e., io_handle_cyg and + to_master_cyg, to store handles of a pipe through which OPOST-processed + output passes. Add pty_master_fwd_thread and function + pty_master_fwd_thread() for a thread which applies OPOST-processing + and forwards data from io_handle to to_master_cyg. Add function + get_io_handle_cyg() regarding variable io_handle_cyg. Now, the pipe + between io_handle and to_master are used only by native windows program + for applying OPOST-processing in the master-side. For a cygwin process, + the pipe between io_handle_cyg and to_master_cyg is used for passing + through the data which is applied OPOST-processing in the slave-side. + * fhandler_tty.cc (struct pipe_reply): Add member to_master_cyg. + (fhandler_pty_master::process_slave_output): Read slave output from + io_handle_cyg rather than io_handle. + (fhandler_pty_slave::fhandler_pty_salve): Initialize output_handle_cyg. + (fhandler_pty_slave::open): Set output_handle_cyg by duplicating handle + to_master_cyg on PTY master. + (fhandler_pty_slave::close): Close handle output_handle_cyg. + (fhandler_pty_slave::write): Write data to output_handle_cyg rather + than output_handle. + (fhandler_pty_slave::fch_close_handles): Close handle output_handle_cyg. + (fhandler_pty_master::fhandler_pty_master): Initialize io_handle_cyg, + to_master_cyg and master_fwd_thread. + (fhandler_pty_master::cleanup): Clean up to_master_cyg as well. + (fhandler_pty_master::close): Print to_master_cyg as well in debug + message. Terminate master forwarding thread. Close handles + to_master_cyg and io_handle_cyg. + (fhandler_pty_master::ioctl): Use io_handle_cyg rather than to_master. + (fhandler_pty_master::pty_master_thread): Add code for duplicating + handle to_master_cyg. + (fhandler_pty_master::pty_master_fwd_thread): New function for a thread + to forward OPOST-processed data from io_handle to to_master_cyg. This + thread applies OPOST-processing to the output of native windows program. + (::pty_master_fwd_thread): Ditto. + (fhandler_pty_master::setup): Create a new pipe to pass thruegh OPOST- + processed output. Create new thread to forward data from io_handle to + to_master_cyg. Set handle to_master_cyg to tty. Print io_handle_cyg as + well in debug message. Close handles io_handle_cyg and to_master_cyg in + case of error. + (fhandler_pty_master::fixup_after_fork): Set handle to_master_cyg to + tty. Copy handle to_master_cyg from arch->to_master_cyg. + (fhandler_pty_master::fixup_after_exec): Clean up to_master_cyg. + * select.cc: Check handle returned by get_io_handle_cyg() rather than + get_handle(). + * tty.h (class tty): Add variable _to_master_cyg to store a handle to + which OPOST-processed data is written. Add two functions, + to_master_cyg() and set_to_master_cyg(), regarding _to_master_cyg. + 2015-04-22 Corinna Vinschen * path.cc (basename): Undefine basename before defining function to diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 694c23bdd..e15f94632 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -412,6 +412,7 @@ public: that some fd's have two handles. */ virtual HANDLE& get_handle () { return io_handle; } virtual HANDLE& get_io_handle () { return io_handle; } + virtual HANDLE& get_io_handle_cyg () { return io_handle; } virtual HANDLE& get_output_handle () { return io_handle; } virtual HANDLE get_stat_handle () { return pc.handle () ?: io_handle; } virtual HANDLE get_echo_handle () const { return NULL; } @@ -1516,6 +1517,7 @@ class fhandler_pty_common: public fhandler_termios class fhandler_pty_slave: public fhandler_pty_common { HANDLE inuse; // used to indicate that a tty is in use + HANDLE output_handle_cyg; /* Helper functions for fchmod and fchown. */ bool fch_open_handles (bool chown); @@ -1526,6 +1528,9 @@ class fhandler_pty_slave: public fhandler_pty_common /* Constructor */ fhandler_pty_slave (int); + void set_output_handle_cyg (HANDLE h) { output_handle_cyg = h; } + HANDLE& get_output_handle_cyg () { return output_handle_cyg; } + int open (int flags, mode_t mode = 0); void open_setup (int flags); ssize_t __stdcall write (const void *ptr, size_t len); @@ -1575,13 +1580,17 @@ class fhandler_pty_master: public fhandler_pty_common HANDLE from_master, to_master; HANDLE echo_r, echo_w; DWORD dwProcessId; // Owner of master handles + HANDLE io_handle_cyg, to_master_cyg; + cygthread *master_fwd_thread; // Master forwarding thread public: HANDLE get_echo_handle () const { return echo_r; } + HANDLE& get_io_handle_cyg () { return io_handle_cyg; } /* Constructor */ fhandler_pty_master (int); DWORD pty_master_thread (); + DWORD pty_master_fwd_thread (); int process_slave_output (char *buf, size_t len, int pktmode_on); void doecho (const void *str, DWORD len); int accept_input (); diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index daa24ebcc..d3fbcee86 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -42,6 +42,7 @@ struct pipe_request { struct pipe_reply { HANDLE from_master; HANDLE to_master; + HANDLE to_master_cyg; DWORD error; }; @@ -236,7 +237,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on /* Check echo pipe first. */ if (::bytes_available (echo_cnt, echo_r) && echo_cnt > 0) break; - if (!bytes_available (n)) + if (!::bytes_available (n, get_io_handle_cyg ())) goto err; if (n) break; @@ -297,7 +298,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on goto err; } } - else if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL)) + else if (!ReadFile (get_io_handle_cyg (), outbuf, rlen, &n, NULL)) { termios_printf ("ReadFile failed, %E"); goto err; @@ -332,7 +333,7 @@ out: /* pty slave stuff */ fhandler_pty_slave::fhandler_pty_slave (int unit) - : fhandler_pty_common (), inuse (NULL) + : fhandler_pty_common (), inuse (NULL), output_handle_cyg (NULL) { if (unit >= 0) dev ().parse (DEV_PTYS_MAJOR, unit); @@ -341,11 +342,11 @@ fhandler_pty_slave::fhandler_pty_slave (int unit) int fhandler_pty_slave::open (int flags, mode_t) { - HANDLE pty_owner, from_master_local, to_master_local; + HANDLE pty_owner, from_master_local, to_master_local, to_master_cyg_local; HANDLE *handles[] = { &from_master_local, &input_available_event, &input_mutex, &inuse, - &output_mutex, &to_master_local, &pty_owner, + &output_mutex, &to_master_local, &pty_owner, &to_master_cyg_local, NULL }; @@ -397,7 +398,8 @@ fhandler_pty_slave::open (int flags, mode_t) release_output_mutex (); } - if (!get_ttyp ()->from_master () || !get_ttyp ()->to_master ()) + if (!get_ttyp ()->from_master () || + !get_ttyp ()->to_master () || !get_ttyp ()->to_master_cyg ()) { errmsg = "pty handles have been closed"; set_errno (EACCES); @@ -448,6 +450,13 @@ fhandler_pty_slave::open (int flags, mode_t) errmsg = "can't duplicate output, %E"; goto err; } + if (!DuplicateHandle (pty_owner, get_ttyp ()->to_master_cyg (), + GetCurrentProcess (), &to_master_cyg_local, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + errmsg = "can't duplicate output for cygwin, %E"; + goto err; + } if (pty_owner != GetCurrentProcess ()) CloseHandle (pty_owner); } @@ -468,7 +477,8 @@ fhandler_pty_slave::open (int flags, mode_t) } from_master_local = repl.from_master; to_master_local = repl.to_master; - if (!from_master_local || !to_master_local) + to_master_cyg_local = repl.to_master_cyg; + if (!from_master_local || !to_master_local || !to_master_cyg_local) { SetLastError (repl.error); errmsg = "error duplicating pipes, %E"; @@ -477,14 +487,18 @@ fhandler_pty_slave::open (int flags, mode_t) } VerifyHandle (from_master_local); VerifyHandle (to_master_local); + VerifyHandle (to_master_cyg_local); termios_printf ("duplicated from_master %p->%p from pty_owner", get_ttyp ()->from_master (), from_master_local); termios_printf ("duplicated to_master %p->%p from pty_owner", get_ttyp ()->to_master (), to_master_local); + termios_printf ("duplicated to_master_cyg %p->%p from pty_owner", + get_ttyp ()->to_master_cyg (), to_master_cyg_local); set_io_handle (from_master_local); set_output_handle (to_master_local); + set_output_handle_cyg (to_master_cyg_local); fhandler_console::need_invisible (); set_open_status (); @@ -533,6 +547,9 @@ fhandler_pty_slave::close () termios_printf ("CloseHandle (inuse), %E"); if (!ForceCloseHandle (input_available_event)) termios_printf ("CloseHandle (input_available_event<%p>), %E", input_available_event); + if (!ForceCloseHandle (get_output_handle_cyg ())) + termios_printf ("CloseHandle (get_output_handle_cyg ()<%p>), %E", + get_output_handle_cyg ()); if ((unsigned) myself->ctty == FHDEV (DEV_PTYS_MAJOR, get_minor ())) fhandler_console::free_console (); /* assumes that we are the last pty closer */ return fhandler_pty_common::close (); @@ -591,7 +608,7 @@ fhandler_pty_slave::write (const void *ptr, size_t len) push_process_state process_state (PID_TTYOU); - if (!process_opost_output (get_output_handle (), ptr, towrite, false)) + if (!process_opost_output (get_output_handle_cyg (), ptr, towrite, false)) { DWORD err = GetLastError (); termios_printf ("WriteFile failed, %E"); @@ -1069,6 +1086,7 @@ fhandler_pty_slave::fch_close_handles () { close_maybe (get_io_handle ()); close_maybe (get_output_handle ()); + close_maybe (get_output_handle_cyg ()); close_maybe (input_available_event); close_maybe (output_mutex); close_maybe (input_mutex); @@ -1142,7 +1160,8 @@ errout: fhandler_pty_master::fhandler_pty_master (int unit) : fhandler_pty_common (), pktmode (0), master_ctl (NULL), master_thread (NULL), from_master (NULL), to_master (NULL), - echo_r (NULL), echo_w (NULL), dwProcessId (0) + echo_r (NULL), echo_w (NULL), dwProcessId (0), + io_handle_cyg (NULL), to_master_cyg (NULL), master_fwd_thread (NULL) { if (unit >= 0) dev ().parse (DEV_PTYM_MAJOR, unit); @@ -1200,15 +1219,15 @@ fhandler_pty_master::cleanup () { report_tty_counts (this, "closing master", ""); if (archetype) - from_master = to_master = NULL; + from_master = to_master = to_master_cyg = NULL; fhandler_base::cleanup (); } int fhandler_pty_master::close () { - termios_printf ("closing from_master(%p)/to_master(%p) since we own them(%u)", - from_master, to_master, dwProcessId); + termios_printf ("closing from_master(%p)/to_master(%p)/to_master_cyg(%p) since we own them(%u)", + from_master, to_master, to_master_cyg, dwProcessId); if (cygwin_finished_initializing) { if (master_ctl && get_ttyp ()->master_pid == myself->pid) @@ -1231,6 +1250,7 @@ fhandler_pty_master::close () master_ctl = NULL; } release_output_mutex (); + master_fwd_thread->terminate_thread (); } } @@ -1247,6 +1267,11 @@ fhandler_pty_master::close () if (!ForceCloseHandle (to_master)) termios_printf ("error closing to_master %p, %E", to_master); from_master = to_master = NULL; + if (!ForceCloseHandle (get_io_handle_cyg ())) + termios_printf ("error closing io_handle_cyg %p, %E", get_io_handle_cyg ()); + if (!ForceCloseHandle (to_master_cyg)) + termios_printf ("error closing to_master_cyg %p, %E", to_master_cyg); + get_io_handle_cyg () = to_master_cyg = NULL; ForceCloseHandle (echo_r); ForceCloseHandle (echo_w); echo_r = echo_w = NULL; @@ -1353,7 +1378,7 @@ fhandler_pty_master::ioctl (unsigned int cmd, void *arg) case FIONREAD: { DWORD n; - if (!::bytes_available (n, to_master)) + if (!::bytes_available (n, get_io_handle_cyg ())) { set_errno (EINVAL); return -1; @@ -1523,6 +1548,13 @@ fhandler_pty_master::pty_master_thread () termios_printf ("DuplicateHandle (to_master), %E"); goto reply; } + if (!DuplicateHandle (GetCurrentProcess (), to_master_cyg, + client, &repl.to_master_cyg, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + termios_printf ("DuplicateHandle (to_master_cyg), %E"); + goto reply; + } } reply: repl.error = GetLastError (); @@ -1548,6 +1580,40 @@ pty_master_thread (VOID *arg) return ((fhandler_pty_master *) arg)->pty_master_thread (); } +DWORD +fhandler_pty_master::pty_master_fwd_thread () +{ + DWORD rlen; + char outbuf[OUT_BUFFER_SIZE]; + + termios_printf("Started."); + for (;;) + { + if (!ReadFile (get_io_handle (), outbuf, sizeof outbuf, &rlen, NULL)) + { + termios_printf ("ReadFile for forwarding failed, %E"); + break; + } + ssize_t wlen = rlen; + while (rlen>0) + { + if (!process_opost_output (to_master_cyg, outbuf, wlen, false)) + { + termios_printf ("WriteFile for forwarding failed, %E"); + break; + } + rlen -= wlen; + } + } + return 0; +} + +static DWORD WINAPI +pty_master_fwd_thread (VOID *arg) +{ + return ((fhandler_pty_master *) arg)->pty_master_fwd_thread (); +} + bool fhandler_pty_master::setup () { @@ -1574,7 +1640,7 @@ fhandler_pty_master::setup () termios_printf ("can't set output_handle(%p) to non-blocking mode", get_output_handle ()); - char pipename[sizeof("ptyNNNN-from-master")]; + char pipename[sizeof("ptyNNNN-to-master-cyg")]; __small_sprintf (pipename, "pty%d-to-master", unit); res = fhandler_pipe::create (&sec_none, &get_io_handle (), &to_master, fhandler_pty_common::pipesize, pipename, 0); @@ -1584,6 +1650,15 @@ fhandler_pty_master::setup () goto err; } + __small_sprintf (pipename, "pty%d-to-master-cyg", unit); + res = fhandler_pipe::create (&sec_none, &get_io_handle_cyg (), &to_master_cyg, + fhandler_pty_common::pipesize, pipename, 0); + if (res) + { + errstr = "output pipe for cygwin"; + goto err; + } + ProtectHandle1 (get_io_handle (), from_pty); __small_sprintf (pipename, "pty%d-echoloop", unit); @@ -1643,28 +1718,38 @@ fhandler_pty_master::setup () errstr = "pty master control thread"; goto err; } + master_fwd_thread = new cygthread (::pty_master_fwd_thread, this, "ptymf"); + if (!master_fwd_thread) + { + errstr = "pty master forwarding thread"; + goto err; + } t.set_from_master (from_master); t.set_to_master (to_master); + t.set_to_master_cyg (to_master_cyg); t.winsize.ws_col = 80; t.winsize.ws_row = 25; t.master_pid = myself->pid; dev ().parse (DEV_PTYM_MAJOR, unit); - termios_printf ("this %p, pty%d opened - from_pty %p, to_pty %p", this, unit, - get_io_handle (), get_output_handle ()); + termios_printf ("this %p, pty%d opened - from_pty <%p,%p>, to_pty %p", + this, unit, get_io_handle (), get_io_handle_cyg (), + get_output_handle ()); return true; err: __seterrno (); close_maybe (get_io_handle ()); + close_maybe (get_io_handle_cyg ()); close_maybe (get_output_handle ()); close_maybe (input_available_event); close_maybe (output_mutex); close_maybe (input_mutex); close_maybe (from_master); close_maybe (to_master); + close_maybe (to_master_cyg); close_maybe (echo_r); close_maybe (echo_w); close_maybe (master_ctl); @@ -1684,11 +1769,13 @@ fhandler_pty_master::fixup_after_fork (HANDLE parent) { t.set_from_master (arch->from_master); t.set_to_master (arch->to_master); + t.set_to_master_cyg (arch->to_master_cyg); } arch->dwProcessId = wpid; } from_master = arch->from_master; to_master = arch->to_master; + to_master_cyg = arch->to_master_cyg; report_tty_counts (this, "inherited master", ""); } @@ -1698,7 +1785,7 @@ fhandler_pty_master::fixup_after_exec () if (!close_on_exec ()) fixup_after_fork (spawn_info->parent); else - from_master = to_master = NULL; + from_master = to_master = to_master_cyg = NULL; } BOOL diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 1706c87c8..803e5d5f5 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -80,7 +80,7 @@ details. */ #define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n)); #define set_handle_or_return_if_not_open(h, s) \ - h = (s)->fh->get_handle (); \ + h = (s)->fh->get_io_handle_cyg (); \ if (cygheap->fdtab.not_open ((s)->fd)) \ { \ (s)->thread_errno = EBADF; \ @@ -1264,7 +1264,7 @@ fhandler_base::select_read (select_stuff *ss) s->startup = no_startup; s->verify = verify_ok; } - s->h = get_handle (); + s->h = get_io_handle_cyg (); s->read_selected = true; s->read_ready = true; return s; diff --git a/winsup/cygwin/tty.h b/winsup/cygwin/tty.h index 27d43f731..522cf9e36 100644 --- a/winsup/cygwin/tty.h +++ b/winsup/cygwin/tty.h @@ -92,12 +92,15 @@ public: private: HANDLE _from_master; HANDLE _to_master; + HANDLE _to_master_cyg; public: HANDLE from_master() const { return _from_master; } HANDLE to_master() const { return _to_master; } + HANDLE to_master_cyg() const { return _to_master_cyg; } void set_from_master (HANDLE h) { _from_master = h; } void set_to_master (HANDLE h) { _to_master = h; } + void set_to_master_cyg (HANDLE h) { _to_master_cyg = h; } int read_retval; bool was_opened; /* True if opened at least once. */