No STATUS_PENDING if COMM_TIMEOUT indicates immediate return.

Michael Karcher wine at mkarcher.dialup.fu-berlin.de
Sun May 11 11:27:19 CDT 2008


If the COMM_TIMEOUT parameters are set to let read return immediately,
some programs (for example the 32 bit configuration program of our
SOHO PBX) goof on ReadFile (in the overlapped case) returning
STATUS_PENDING if no character is available.

For COMM ports, a zero bytes read is now returned as success even
in the overlapped case.
---
 dlls/ntdll/file.c |   29 ++++++++++++++---------------
 1 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 972d600..b25049c 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -263,13 +263,15 @@ struct async_fileio
     void               *apc_arg;
 };
 
+typedef enum {AM_ATLEASTONE, AM_UNTILCOUNT, AM_MAYBENONE} AVAIL_MODE;
+
 typedef struct
 {
     struct async_fileio io;
     char*               buffer;
     unsigned int        already;
     unsigned int        count;
-    BOOL                avail_mode;
+    AVAIL_MODE          avail_mode;
 } async_fileio_read;
 
 typedef struct
@@ -368,16 +370,10 @@ static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATU
         else
         {
             fileio->already += result;
-            if (fileio->already >= fileio->count || fileio->avail_mode)
+            if (fileio->already >= fileio->count || fileio->avail_mode != AM_UNTILCOUNT)
                 status = STATUS_SUCCESS;
             else
-            {
-                /* if we only have to read the available data, and none is available,
-                 * simply cancel the request. If data was available, it has been read
-                 * while in by previous call (NtDelayExecution)
-                 */
-                status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING;
-            }
+                status = STATUS_PENDING;
         }
         break;
 
@@ -493,7 +489,7 @@ static inline int get_next_io_timeout( const struct io_timeouts *timeouts, ULONG
 

 /* retrieve the avail_mode flag for async reads */
-static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL *avail_mode )
+static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, AVAIL_MODE *avail_mode )
 {
     NTSTATUS status = STATUS_SUCCESS;
 
@@ -508,19 +504,21 @@ static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL
             status = NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io,
                                             IOCTL_SERIAL_GET_TIMEOUTS, NULL, 0, &st, sizeof(st) );
             if (status) break;
+            /* FIXME: timeout behaviour of COMM ports is *much* more
+               complex! */
             *avail_mode = (!st.ReadTotalTimeoutMultiplier &&
                            !st.ReadTotalTimeoutConstant &&
-                           st.ReadIntervalTimeout == MAXDWORD);
+                           st.ReadIntervalTimeout == MAXDWORD) ? AM_MAYBENONE : AM_UNTILCOUNT;
         }
         break;
     case FD_TYPE_MAILSLOT:
     case FD_TYPE_SOCKET:
     case FD_TYPE_PIPE:
     case FD_TYPE_CHAR:
-        *avail_mode = TRUE;
+        *avail_mode = AM_ATLEASTONE;
         break;
     default:
-        *avail_mode = FALSE;
+        *avail_mode = AM_UNTILCOUNT;
         break;
     }
     return status;
@@ -630,11 +628,12 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
         if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
         {
             async_fileio_read *fileio;
-            BOOL avail_mode;
+            AVAIL_MODE avail_mode;
 
             if ((status = get_io_avail_mode( hFile, type, &avail_mode )))
                 goto err;
-            if (total && avail_mode)
+            if ((total && avail_mode == AM_ATLEASTONE) ||
+                 avail_mode == AM_MAYBENONE)
             {
                 status = STATUS_SUCCESS;
                 goto done;
-- 
1.5.5.1




More information about the wine-patches mailing list