kernel32/tests: Fix the test_waittxempty() timeout.
Francois Gouget
fgouget at free.fr
Tue Oct 1 09:56:31 CDT 2013
The timeout was too short and would only work for UARTs that have a FIFO and where the trigger level was set just right. With this patch we calculate how much time sending the test data will actually take and tack on a small margin to take into account scheduling delays.
This actually fixes the tests on Wine which behaves like a FIFO-less UART.
This patch also checks that WaitCommEvent() returns immediately, which it should since the file handle is in overlapped mode.
---
Here is some reference material which explains how FIFO-equipped UARTs
work:
http://www.naval-acad.bg/HOWTO/Modem-HOWTO-14.html
http://www.tldp.org/HOWTO/Serial-HOWTO-18.html
To sumarize:
* Modern UARTs typically have a 16 bytes FIFO.
* They raise an interrupt to ask for more data not when the buffer
is empty but a bit before so the software side has time to refill it.
* This is called the trigger level and can typically be set by the OS
or driver at 4, 8 or 14 bytes. It's not clear which of the OS or
the driver set the trigger level but since it's hardware-dependent
it's likely the driver. It's also not clear that either Linux or
Windows provide any user-space way to change the trigger level.
* Windows reports that all bytes have been sent not when the UART's
buffer is empty but when they all made it to the UART's buffer. Note
that this can be tested (see next mail).
And this is why this test managed to stay under the 900 ms mark. It
seems like Windows uses a 14 bytes trigger level, i.e. it raises the
interrupt when it starts sending the 14th byte in the buffer. So:
* Windows fills the UART buffer with 16 bytes and keeps 1 byte in its
internal buffer.
* 866 ms later the UART has sent the first 13 bytes and raises an
interrupt.
* Windows then puts the 17th byte into the UART buffer.
* The Windows buffer is now empty so it signals the event after only
about 872 ms. But there's still 4 bytes to send.
However this test would fail both with older UARTs, like the 8250 which
has no FIFO, or modern UARTs with a slightly bigger FIFO / trigger level
(for instance a 24 bytes FIFO with a 16 bytes trigger level).
More fundamentally this is a hardware-dependent issue which is out of
the scope of Wine's conformance tests.
dlls/kernel32/tests/comm.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/kernel32/tests/comm.c b/dlls/kernel32/tests/comm.c
index 7ec5fc5..9625182 100644
--- a/dlls/kernel32/tests/comm.c
+++ b/dlls/kernel32/tests/comm.c
@@ -793,7 +793,7 @@ static void test_waittxempty(void)
DCB dcb;
COMMTIMEOUTS timeouts;
char tbuf[]="test_waittxempty";
- DWORD before, after, bytes, timediff, evtmask, errors, i;
+ DWORD timeout, before, after, bytes, timediff, evtmask, errors, i;
BOOL res;
DWORD baud = SLOWBAUD;
OVERLAPPED ovl_write, ovl_wait, ovl_wait2;
@@ -802,7 +802,7 @@ static void test_waittxempty(void)
hcom = test_OpenComm(TRUE);
if (hcom == INVALID_HANDLE_VALUE) return;
- /* set a low baud rate to have ample time*/
+ /* set a low baud rate to have ample time */
res = GetCommState(hcom, &dcb);
ok(res, "GetCommState error %d\n", GetLastError());
dcb.BaudRate = baud;
@@ -814,6 +814,13 @@ static void test_waittxempty(void)
res = SetCommState(hcom, &dcb);
ok(res, "SetCommState error %d\n", GetLastError());
+ /* 8 data bits, 1 stop bit, no parity => 10 raw bits
+ * Add a few milliseconds to allow for scheduling delays. Note that the
+ * actual time may be shorter depending on how the UART's FIFO trigger
+ * level was set.
+ */
+ timeout = ((sizeof(tbuf) * 10 * 1000) / baud) + 40;
+
ZeroMemory( &timeouts, sizeof(timeouts));
timeouts.ReadTotalTimeoutConstant = TIMEOUT;
res = SetCommTimeouts(hcom, &timeouts);
@@ -856,8 +863,9 @@ todo_wine
SetLastError(0xdeadbeef);
res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
ok(!res && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %d\n", GetLastError());
- res = WaitForSingleObject(ovl_wait.hEvent, TIMEOUT);
-todo_wine
+ after = GetTickCount();
+ ok(after - before < 30, "WaitCommEvent should have returned immediately, took %d ms\n", after - before);
+ res = WaitForSingleObject(ovl_wait.hEvent, timeout);
ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
if (res == WAIT_OBJECT_0)
{
@@ -879,16 +887,13 @@ todo_wine
res = FALSE;
}
after = GetTickCount();
-todo_wine
ok(res, "WaitCommEvent error %d\n", GetLastError());
-todo_wine
ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
CloseHandle(ovl_wait.hEvent);
timediff = after - before;
- trace("WaitCommEvent for EV_TXEMPTY took %d ms (timeout %d)\n", timediff, TIMEOUT);
-todo_wine
- ok(timediff < 900, "WaitCommEvent used %d ms for waiting\n", timediff);
+ trace("WaitCommEvent for EV_TXEMPTY took %d ms (timeout %d)\n", timediff, timeout);
+ ok(timediff < timeout, "WaitCommEvent took %d ms (timeout %d)\n", timediff, timeout);
res = WaitForSingleObject(ovl_write.hEvent, 0);
ok(res == WAIT_OBJECT_0, "WriteFile failed with a timeout\n");
--
1.8.4.rc3
More information about the wine-patches
mailing list