Asynchronous ReadFile with ReadIntervalTimeout=MAXDWORD

Open forum for end-user questions about Wine. Before asking questions, check out the Wiki as a first step.
Forum Rules
Post Reply
aknister
Newbie
Newbie
Posts: 1
Joined: Fri Jan 29, 2021 4:08 pm

Asynchronous ReadFile with ReadIntervalTimeout=MAXDWORD

Post by aknister » Fri Jan 29, 2021 4:39 pm

I'm trying to track down an issue using TeraTerm to access a serial port with Wine. It mostly works, but data read from the serial port is frequently garbled and large chunks are not displayed to the terminal.

The code sets the following timeout parameters:

Code: Select all

ReadIntervalTimeout = MAXDWORD;
WriteTotalTimeoutConstant = 500;
It looks like what happens is the TeraTerm code calls ReadFile, if ReadFile completes with a pending I/O, it then waits on the lpOverlapped event pointer for 1 second and if it doesn't return signaled it moves on. What's happening under Wine is the wait times out, but thereafter the read is completed asynchronously.

Initially I thought this was obviously an error with TeraTerm not re-trying if the wait failed but after doing some more reading I'm not so sure. There's documentation linked from the ReadFile API (https://docs.microsoft.com/en-us/window ... mmtimeouts) talking about comm timeouts. It says that:
A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received.
Given that, it strikes me that ReadFile called when the comm timeout parameters are set as above, ought not to trigger an asynchronous read but instead return immediately with whatever data is present on the device. I think this means a modification to NtReadFile, probably right around line 5072 (https://github.com/wine-mirror/wine/blo ... le.c#L5072).

I'm happy to propose a patch, but I feel a little like I'm running with scissors and would appreciate guidance as to whether or not this is the right approach :)

In case it's helpful, here's the code snippet from TeraTerm that does the reading from the serial port. Note that PReadFile is defined as ReadFile:

Code: Select all

        do {
                ClearCommError(cv->ComID,&DErr,NULL);
                if (! PReadFile(cv->ComID,&(cv->InBuff[cv->InBuffCount]),
                                InBuffSize-cv->InBuffCount,&C,&rol)) {
                        if (GetLastError() == ERROR_IO_PENDING) {
                                if (WaitForSingleObject(rol.hEvent, 1000) != WAIT_OBJECT_0) {
                                        C = 0;
                                }
                                else {
                                        GetOverlappedResult(cv->ComID,&rol,&C,FALSE);
                                }
                        }
                        else {
                                C = 0;
                        }
                }
                cv->InBuffCount = cv->InBuffCount + C;
        } while ((C!=0) && (cv->InBuffCount<InBuffSize));

Post Reply