[WSA]GetOverlappedResult() with auto-reset events

Martin Wilck Martin.Wilck at Fujitsu-Siemens.com
Thu Sep 12 11:52:07 CDT 2002


Patch: GetOverlappedResult.diff

Martin Wilck <Martin.Wilck at fujitsu-siemens.com>
Patch against: CVS 2002-09-12

Modified files:
        - wine/dlls/winsock:    socket.c
        - wine/files:           file.c

Fix the behavior of GetOverlappedResult() and WSAGetOverlappedResult()
with non-manual-reset (auto-reset) Events in the OVERLAPPED structures.

If called with the wait parameter FALSE, these functions actually should
not call a wait function at all, but only check the condition of the
overlapped request. In wine, we _must_ wait because some apps never call
a wait function directly, causing the async request(s) to linger forever.
However if an auto-reset event is being used (and the request is complete), 
the call to the wait function will cause it to be reset, thus we must set it
again because the app doesn't know we have waited. This is particularly
necessary because we call GetOverlappedResult() in ReadFile(), WriteFile(),
WSASend(), etc., in order to check for immediate request completion.

Finally, if the wait parameter is FALSE and the request is already completed,
waiting for it again may hang the process forever if the app proceeds like this:

if ( (n = WaitForMultipleObjects (...)) == WAIT_OBJECT_0 )
        GetOverlappedResult (file, overlapped[n], NULL, FALSE);

because the first wait has caused the event to be reset already.

Index: dlls/winsock/socket.c
===================================================================
RCS file: /home/wine/wine/dlls/winsock/socket.c,v
retrieving revision 1.105
diff -u -r1.105 socket.c
--- dlls/winsock/socket.c	6 Sep 2002 20:40:42 -0000	1.105
+++ dlls/winsock/socket.c	12 Sep 2002 16:28:00 -0000
@@ -3266,22 +3266,38 @@
         return FALSE;
     }
 
-    do {
-        r = WaitForSingleObjectEx (lpOverlapped->hEvent, fWait ? INFINITE : 0, TRUE);
-    } while (r == STATUS_USER_APC);
-
+    if ( fWait )
+    {
+        while ( WaitForSingleObjectEx (lpOverlapped->hEvent, INFINITE, TRUE) == STATUS_USER_APC );
+    }
+    else if ( lpOverlapped->Internal == STATUS_PENDING )
+    {
+        /* Wait in order to give APCs a chance to run. */
+        /* This is cheating, so we must set the event again in case of success -
+           it may be a non-manual reset event. */
+        while ( (r = WaitForSingleObjectEx (lpOverlapped->hEvent, 0, TRUE)) == STATUS_USER_APC );
+        if ( r == WAIT_OBJECT_0 )
+            NtSetEvent ( lpOverlapped->hEvent, NULL );
+    }
+    
     if ( lpcbTransfer )
         *lpcbTransfer = lpOverlapped->InternalHigh;
 
     if ( lpdwFlags )
         *lpdwFlags = lpOverlapped->Offset;
 
-    if ( r == WAIT_OBJECT_0 )
+    switch ( lpOverlapped->Internal )
+    {
+    case STATUS_SUCCESS:
         return TRUE;
-
-    WSASetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
-                      WSA_IO_INCOMPLETE : NtStatusToWSAError ( lpOverlapped->Internal ) );
-    return FALSE;
+    case STATUS_PENDING:
+        WSASetLastError ( WSA_IO_INCOMPLETE );
+        if (fWait) ERR ("PENDING status after waiting!\n");
+        return FALSE;
+    default:
+        WSASetLastError ( NtStatusToWSAError ( lpOverlapped->Internal ));
+        return FALSE;
+    }
 }
 

Index: files/file.c
===================================================================
RCS file: /home/wine/wine/files/file.c,v
retrieving revision 1.157
diff -u -r1.157 file.c
--- files/file.c	27 Aug 2002 01:29:07 -0000	1.157
+++ files/file.c	12 Sep 2002 16:28:00 -0000
@@ -1554,19 +1554,43 @@
         return FALSE;
     }
 
-    do {
-        TRACE("waiting on %p\n",lpOverlapped);
-        r = WaitForSingleObjectEx(lpOverlapped->hEvent, bWait?INFINITE:0, TRUE);
-        TRACE("wait on %p returned %ld\n",lpOverlapped,r);
-    } while (r==STATUS_USER_APC);
+    if ( bWait )
+    {
+        do {
+            TRACE("waiting on %p\n",lpOverlapped);
+            r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
+            TRACE("wait on %p returned %ld\n",lpOverlapped,r);
+        } while (r==STATUS_USER_APC);
+    }
+    else if ( lpOverlapped->Internal == STATUS_PENDING )
+    {
+        /* Wait in order to give APCs a chance to run. */
+        /* This is cheating, so we must set the event again in case of success -
+           it may be a non-manual reset event. */
+        do {
+            TRACE("waiting on %p\n",lpOverlapped);
+            r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE);
+            TRACE("wait on %p returned %ld\n",lpOverlapped,r);
+        } while (r==STATUS_USER_APC);
+        if ( r == WAIT_OBJECT_0 )
+            NtSetEvent ( lpOverlapped->hEvent, NULL );
+    }
 
     if(lpTransferred)
         *lpTransferred = lpOverlapped->InternalHigh;
 
-    SetLastError ( lpOverlapped->Internal == STATUS_PENDING ?
-                   ERROR_IO_INCOMPLETE : RtlNtStatusToDosError ( lpOverlapped->Internal ) );
-
-    return (r==WAIT_OBJECT_0);
+    switch ( lpOverlapped->Internal )
+    {
+    case STATUS_SUCCESS:
+        return TRUE;
+    case STATUS_PENDING:
+        SetLastError ( ERROR_IO_INCOMPLETE );
+        if ( bWait ) ERR ("PENDING status after waiting!\n");
+        return FALSE;
+    default:
+        SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) );
+        return FALSE;
+    }
 }
 
 /***********************************************************************
-- 
Martin Wilck                Phone: +49 5251 8 15113
Fujitsu Siemens Computers   Fax:   +49 5251 8 20409
Heinz-Nixdorf-Ring 1	    mailto:Martin.Wilck at Fujitsu-Siemens.com
D-33106 Paderborn           http://www.fujitsu-siemens.com/primergy








More information about the wine-patches mailing list