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