On 2020-03-12 12:40, Corinna Vinschen wrote:

I inspected the serial I/O read function and I only see a subtil
difference in terms of VMIN/VTIME which doesn't seem to be the culprit
at first glance.  In O_NONBLOCK mode, the underlying Windows function
ReadFile is called unconditionally.  My current hunch is this:

- If VMIN>0 && VTIME>0, the Windows equivalent of tcsetattr is
   told that VMIN>0.

- So, assuming VMIN == 2 in Windows.  If VTIME > 0, the Cygwin read
   function sets the number of bytes_to_read to 1 (this is old code,
   don't ask why).
Do you have a pointer to this? I can not find it...

- My assumption now is that the ReadFile function fails because it's
   supposed to return only 1 char, but VMIN is > 1.

There are two issues here.

- If my assumption is correct, the tcsetattr function must not
   set the Windows VMIN equivalent to != 0 in the O_NONBLOCK case.

- Also, as mention above, if VTIME > 0, Cygwin's read sets the number of
   bytes_to_read to 1.   Weirdly, it does so even if there are more than
   1 byte in the inbound queue.  This sounds wrong to me.

I think the problem is if the number of bytes requested are more than what is in the buffer it is going to overlap the read function (because of VTIME) and immediately after that CancelIO is called. Contrary to what is mentioned in the source code I think CancelIO is actually discarding data...

  /* Use CancelIo rather than PurgeComm (PURGE_RXABORT) since
         PurgeComm apparently discards in-flight bytes while CancelIo
         only stops the overlapped IO routine. */


My suggestion is the following patch:

diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc
index 69e5768f6..afa8871bf 100644
--- a/winsup/cygwin/fhandler_serial.cc
+++ b/winsup/cygwin/fhandler_serial.cc
@@ -898,7 +898,11 @@ fhandler_serial::tcsetattr (int action, const struct termios *t)
   {
     memset (&to, 0, sizeof (to));

-    if ((vmin_ > 0) && (vtime_ == 0))
+       if (is_nonblocking())
+       {
+               to.ReadIntervalTimeout = MAXDWORD;
+       }
+    else if ((vmin_ > 0) && (vtime_ == 0))
       {
        /* Returns immediately with whatever is in buffer on a ReadFile();
           or blocks if nothing found.  We will keep calling ReadFile(); until


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

Reply via email to