* fhandler_tty.cc (fhandler_tty_slave::read): Set WFMO timeout to 0 for

nonblocking case.  Drop useless waiter variable.  Rewrite wait for
	input_available_event to use a switch statement.  Handle timeout and
	failure more gracefully.  Make restartable and cancelable.  Rewrite
	wait for input_mutex to use WFMO and a switch statement.  Handle
	timeout and failure more gracefully.  Make restartable and cancelable.
This commit is contained in:
Corinna Vinschen 2011-05-03 07:58:13 +00:00
parent af4f7961d0
commit 3ff46ba853
2 changed files with 84 additions and 38 deletions

View File

@ -1,3 +1,12 @@
2011-05-03 Corinna Vinschen <corinna@vinschen.de>
* fhandler_tty.cc (fhandler_tty_slave::read): Set WFMO timeout to 0 for
nonblocking case. Drop useless waiter variable. Rewrite wait for
input_available_event to use a switch statement. Handle timeout and
failure more gracefully. Make restartable and cancelable. Rewrite
wait for input_mutex to use WFMO and a switch statement. Handle
timeout and failure more gracefully. Make restartable and cancelable.
2011-05-02 Christopher Faylor <me.cygwin2011@cgf.cx> 2011-05-02 Christopher Faylor <me.cygwin2011@cgf.cx>
* signal.cc (_pinfo::kill): Avoid referencing 'pid' after ESRCH. * signal.cc (_pinfo::kill): Avoid referencing 'pid' after ESRCH.

View File

@ -808,12 +808,10 @@ fhandler_tty_slave::read (void *ptr, size_t& len)
char buf[INP_BUFFER_SIZE]; char buf[INP_BUFFER_SIZE];
char peek_buf[INP_BUFFER_SIZE]; char peek_buf[INP_BUFFER_SIZE];
DWORD time_to_wait; DWORD time_to_wait;
DWORD rc;
HANDLE w4[2];
termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ()); termios_printf ("read(%x, %d) handle %p", ptr, len, get_handle ());
if (!ptr) /* Indicating tcflush(). */ if (is_nonblocking () || !ptr) /* Indicating tcflush(). */
time_to_wait = 0; time_to_wait = 0;
else if ((get_ttyp ()->ti.c_lflag & ICANON)) else if ((get_ttyp ()->ti.c_lflag & ICANON))
time_to_wait = INFINITE; time_to_wait = INFINITE;
@ -833,47 +831,88 @@ fhandler_tty_slave::read (void *ptr, size_t& len)
time_to_wait = !vtime ? INFINITE : 100 * vtime; time_to_wait = !vtime ? INFINITE : 100 * vtime;
} }
w4[0] = signal_arrived;
w4[1] = input_available_event;
DWORD waiter = time_to_wait;
while (len) while (len)
{ {
rc = WaitForMultipleObjects (2, w4, FALSE, waiter); HANDLE w4[3] = { input_available_event, signal_arrived,
pthread::get_cancel_event () };
if (rc == WAIT_TIMEOUT) DWORD cnt = w4[2] ? 3 : 2;
switch (WaitForMultipleObjects (cnt, w4, FALSE, time_to_wait))
{ {
termios_printf ("wait timed out, waiter %u", waiter); case WAIT_OBJECT_0:
break; break;
} case WAIT_OBJECT_0 + 1:
if (rc == WAIT_FAILED)
{
termios_printf ("wait for input event failed, %E");
break;
}
if (rc == WAIT_OBJECT_0)
{
/* if we've received signal after successfully reading some data,
just return all data successfully read */
if (totalread > 0) if (totalread > 0)
break; goto out;
if (_my_tls.call_signal_handler ())
continue;
termios_printf ("wait catched signal");
set_sig_errno (EINTR); set_sig_errno (EINTR);
len = (size_t) -1; totalread = -1;
return; goto out;
case WAIT_OBJECT_0 + 2:
pthread::static_cancel_self ();
/*NOTREACHED*/
case WAIT_TIMEOUT:
termios_printf ("wait timed out, time_to_wait %u", time_to_wait);
if (!totalread)
{
set_sig_errno (EAGAIN);
totalread = -1;
}
goto out;
default:
termios_printf ("wait for input event failed, %E");
if (!totalread)
{
__seterrno ();
totalread = -1;
}
goto out;
} }
/* Now that we know that input is available we have to grab the
rc = WaitForSingleObject (input_mutex, 1000); input mutex. */
if (rc == WAIT_FAILED) w4[0] = input_mutex;
switch (WaitForMultipleObjects (cnt, w4, FALSE, 1000))
{ {
case WAIT_OBJECT_0:
case WAIT_ABANDONED_0:
break;
case WAIT_OBJECT_0 + 1:
if (totalread > 0)
goto out;
if (_my_tls.call_signal_handler ())
continue;
termios_printf ("wait for mutex catched signal");
set_sig_errno (EINTR);
totalread = -1;
goto out;
case WAIT_OBJECT_0 + 2:
pthread::static_cancel_self ();
/*NOTREACHED*/
case WAIT_TIMEOUT:
termios_printf ("failed to acquire input mutex after input event "
"arrived");
/* If we have a timeout, we can simply handle this failure to
grab the mutex as an EAGAIN situation. Otherwise, if this
is an infinitely blocking read, restart the loop. */
if (time_to_wait != INFINITE)
{
if (!totalread)
{
set_sig_errno (EAGAIN);
totalread = -1;
}
goto out;
}
continue;
default:
termios_printf ("wait for input mutex failed, %E"); termios_printf ("wait for input mutex failed, %E");
break; if (!totalread)
} {
else if (rc == WAIT_TIMEOUT) __seterrno ();
{ totalread = -1;
termios_printf ("failed to acquire input mutex after input event arrived"); }
break; goto out;
} }
if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL)) if (!PeekNamedPipe (get_handle (), peek_buf, sizeof (peek_buf), &bytes_in_pipe, NULL, NULL))
{ {
@ -974,10 +1013,8 @@ fhandler_tty_slave::read (void *ptr, size_t& len)
if (vmin == 0) if (vmin == 0)
break; break;
if (n)
waiter = time_to_wait;
} }
out:
termios_printf ("%d=read(%x, %d)", totalread, ptr, len); termios_printf ("%d=read(%x, %d)", totalread, ptr, len);
len = (size_t) totalread; len = (size_t) totalread;
} }