Cygwin: serial: read: if VMIN > 0, wait for VMIN chars in inbound queue

Per termios, read waits for MIN chars even if the number of requested
bytes is less.  This requires to add WaitCommEvent to wait non-busily
for MIN chars prior to calling ReadFile, so, reintroduce it.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2020-03-25 12:21:59 +01:00
parent 2a4b1de773
commit 082f2513c7
1 changed files with 26 additions and 12 deletions

View File

@ -34,19 +34,20 @@ void __reg3
fhandler_serial::raw_read (void *ptr, size_t& ulen)
{
OVERLAPPED ov = { 0 };
DWORD io_err;
DWORD io_err, event;
COMSTAT st;
DWORD bytes_to_read, read_bytes;
ssize_t tot = 0;
bool wait_for_vmin, ret;
if (ulen > SSIZE_MAX)
ulen = SSIZE_MAX;
if (ulen == 0)
return;
/* If VMIN > 0 in blocking mode, we have to read at least VMIN chars,
otherwise we're in polling mode and there's no minimum chars. */
ssize_t minchars = (!is_nonblocking () && vmin_) ? MIN (vmin_, ulen) : 0;
/* If VMIN > 0 in blocking mode, we have to wait for at least VMIN chars.
Otherwise we're in polling mode and there's no minimum chars. */
ssize_t minchars = is_nonblocking () ? 0 : vmin_;
debug_printf ("ulen %ld, vmin_ %u, vtime_ %u", ulen, vmin_, vtime_);
@ -54,6 +55,8 @@ fhandler_serial::raw_read (void *ptr, size_t& ulen)
do
{
wait_for_vmin = false;
/* First check if chars are already in the inbound queue. */
if (!ClearCommError (get_handle (), &io_err, &st))
goto err;
@ -82,14 +85,22 @@ fhandler_serial::raw_read (void *ptr, size_t& ulen)
and don't wait. */
if (st.cbInQue && st.cbInQue >= minchars)
bytes_to_read = MIN (st.cbInQue, bytes_to_read);
/* Otherwise, if VMIN > 0, VTIME == 0, we have to wait until
VMIN bytes are available in the inbound queue. */
else if (minchars && !vtime_)
wait_for_vmin = true;
}
ResetEvent (ov.hEvent);
if (!ReadFile (get_handle (), ptr, bytes_to_read, &read_bytes, &ov))
if (wait_for_vmin)
ret = WaitCommEvent (get_handle (), &event, &ov);
else
ret = ReadFile (get_handle (), ptr, bytes_to_read, &read_bytes, &ov);
if (!ret)
{
if (GetLastError () != ERROR_IO_PENDING)
goto err;
if (is_nonblocking ())
if (!wait_for_vmin && is_nonblocking ())
{
CancelIo (get_handle ());
if (!GetOverlappedResult (get_handle (), &ov, &read_bytes,
@ -134,12 +145,15 @@ fhandler_serial::raw_read (void *ptr, size_t& ulen)
}
}
}
tot += read_bytes;
ptr = (void *) ((caddr_t) ptr + read_bytes);
ulen -= read_bytes;
minchars -= read_bytes;
debug_printf ("vtime_ %u, vmin_ %u, read_bytes %u, tot %D",
vtime_, vmin_, read_bytes, tot);
if (!wait_for_vmin)
{
tot += read_bytes;
ptr = (void *) ((caddr_t) ptr + read_bytes);
ulen -= read_bytes;
minchars -= read_bytes;
debug_printf ("vtime_ %u, vmin_ %u, read_bytes %u, tot %D",
vtime_, vmin_, read_bytes, tot);
}
continue;
err: