* fhandler.h (fhandler_base::get_echo_handle): New virtual method.

(class fhandler_pty_master): Add echo_r and echo_w handles constituting
	read and write side of new echo pipe.
	* select.cc (peek_pipe): On pty masters, check additionally if input
	from the echo pipe is available.
	* fhandler_tty.cc (fhandler_pty_master::doecho): Drop output_mutex
	locking.  Write output to echo pipe.
	(fhandler_pty_master::process_slave_output): Check if input is available
	in echo pipe and prefer to read from it, if so.
	(fhandler_pty_slave::write): Drop output_mutex locking.
	(fhandler_pty_master::fhandler_pty_master): Initialize echo pipe
	handles to NULL.
	(fhandler_pty_master::close): Close and NULL echo pipe handles.
	(fhandler_pty_master::setup): Create echo pipe, close in case of error.
This commit is contained in:
Corinna Vinschen 2015-03-05 12:57:34 +00:00
parent e185d3febe
commit 3bf693dde1
5 changed files with 71 additions and 11 deletions

View File

@ -1,3 +1,20 @@
2015-03-05 Corinna Vinschen <corinna@vinschen.de>
* fhandler.h (fhandler_base::get_echo_handle): New virtual method.
(class fhandler_pty_master): Add echo_r and echo_w handles constituting
read and write side of new echo pipe.
* select.cc (peek_pipe): On pty masters, check additionally if input
from the echo pipe is available.
* fhandler_tty.cc (fhandler_pty_master::doecho): Drop output_mutex
locking. Write output to echo pipe.
(fhandler_pty_master::process_slave_output): Check if input is available
in echo pipe and prefer to read from it, if so.
(fhandler_pty_slave::write): Drop output_mutex locking.
(fhandler_pty_master::fhandler_pty_master): Initialize echo pipe
handles to NULL.
(fhandler_pty_master::close): Close and NULL echo pipe handles.
(fhandler_pty_master::setup): Create echo pipe, close in case of error.
2015-03-04 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/version.h (CYGWIN_VERSION_DLL_MINOR): Bump to 36.

View File

@ -414,6 +414,7 @@ public:
virtual HANDLE& get_io_handle () { 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; }
virtual bool hit_eof () {return false;}
virtual select_record *select_read (select_stuff *);
virtual select_record *select_write (select_stuff *);
@ -1569,11 +1570,13 @@ class fhandler_pty_master: public fhandler_pty_common
HANDLE master_ctl; // Control socket for handle duplication
cygthread *master_thread; // Master control thread
HANDLE from_master, to_master;
HANDLE echo_r, echo_w;
DWORD dwProcessId; // Owner of master handles
public:
int need_nl; // Next read should start with \n
HANDLE get_echo_handle () const { return echo_r; }
/* Constructor */
fhandler_pty_master (int);

View File

@ -145,10 +145,8 @@ fhandler_pty_common::__release_output_mutex (const char *fn, int ln)
void
fhandler_pty_master::doecho (const void *str, DWORD len)
{
acquire_output_mutex (INFINITE);
if (!WriteFile (to_master, str, len, &len, NULL))
termios_printf ("Write to %p failed, %E", to_master);
release_output_mutex ();
if (!WriteFile (echo_w, str, len, &len, NULL))
termios_printf ("Write to echo pipe failed, %E");
}
int
@ -221,6 +219,7 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
size_t rlen;
char outbuf[OUT_BUFFER_SIZE + 1];
DWORD n;
DWORD echo_cnt;
int column = 0;
int rc = 0;
@ -257,9 +256,12 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
if (rlen > sizeof outbuf)
rlen = sizeof outbuf;
n = 0;
n = echo_cnt = 0;
for (;;)
{
/* Check echo pipe first. */
if (::bytes_available (echo_cnt, echo_r) && echo_cnt > 0)
break;
if (!bytes_available (n))
goto err;
if (n)
@ -287,7 +289,17 @@ fhandler_pty_master::process_slave_output (char *buf, size_t len, int pktmode_on
flush_to_slave ();
}
if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL))
/* If echo pipe has data (something has been typed or pasted), prefer
it over slave output. */
if (echo_cnt > 0)
{
if (!ReadFile (echo_r, outbuf, rlen, &n, NULL))
{
termios_printf ("ReadFile on echo pipe failed, %E");
goto err;
}
}
else if (!ReadFile (get_handle (), outbuf, rlen, &n, NULL))
{
termios_printf ("ReadFile failed, %E");
goto err;
@ -653,7 +665,6 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
while (tc ()->output_stopped)
cygwait (10);
acquire_output_mutex (INFINITE);
/* Previous write may have set write_error to != 0. Check it here.
This is less than optimal, but the alternative slows down pty
@ -663,12 +674,10 @@ fhandler_pty_slave::write (const void *ptr, size_t len)
set_errno (get_ttyp ()->write_error);
towrite = -1;
get_ttyp ()->write_error = 0;
release_output_mutex ();
break;
}
BOOL res = WriteFile (get_output_handle (), buf, n, &n, NULL);
release_output_mutex ();
if (!res)
{
DWORD err = GetLastError ();
@ -1228,7 +1237,7 @@ 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),
dwProcessId (0), need_nl (0)
echo_r (NULL), echo_w (NULL), dwProcessId (0), need_nl (0)
{
if (unit >= 0)
dev ().parse (DEV_PTYM_MAJOR, unit);
@ -1317,6 +1326,9 @@ fhandler_pty_master::close ()
if (!ForceCloseHandle (to_master))
termios_printf ("error closing from_master %p, %E", to_master);
from_master = to_master = NULL;
ForceCloseHandle (echo_r);
ForceCloseHandle (echo_w);
echo_r = echo_w = NULL;
fhandler_pty_common::close ();
@ -1660,6 +1672,15 @@ fhandler_pty_master::setup ()
ProtectHandle1 (get_io_handle (), from_pty);
__small_sprintf (pipename, "pty%d-echoloop", unit);
res = fhandler_pipe::create (&sec_none, &echo_r, &echo_w,
fhandler_pty_common::pipesize, pipename, 0);
if (res)
{
errstr = "echo pipe";
goto err;
}
/* Create security attribute. Default permissions are 0620. */
sd.malloc (sizeof (SECURITY_DESCRIPTOR));
RtlCreateSecurityDescriptor (sd, SECURITY_DESCRIPTOR_REVISION);
@ -1730,6 +1751,8 @@ err:
close_maybe (input_mutex);
close_maybe (from_master);
close_maybe (to_master);
close_maybe (echo_r);
close_maybe (echo_w);
close_maybe (master_ctl);
termios_printf ("pty%d open failed - failed to create %s", unit, errstr);
return false;

View File

@ -0,0 +1,14 @@
What's new:
-----------
What changed:
-------------
Bug Fixes
---------
- Fix potential hang in pseudo ttys when generating ECHO output while the slave
is flooding the pty with output.
Addresses: https://cygwin.com/ml/cygwin/2015-03/msg00019.html

View File

@ -1,7 +1,7 @@
/* select.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Red Hat, Inc.
This file is part of Cygwin.
@ -626,6 +626,9 @@ peek_pipe (select_record *s, bool from_select)
goto out;
}
int n = pipe_data_available (s->fd, fh, h, false);
/* On PTY masters, check if input from the echo pipe is available. */
if (n == 0 && fh->get_echo_handle ())
n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), false);
if (n < 0)
{