Fix the behavior of GetOverlappedResult() and WSAGetOverlappedResult()
with non-manual-reset (auto-reset) events in the OVERLAPPED structures.
diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c
index 81e8d00..12f38a9 100644
--- a/dlls/winsock/socket.c
+++ b/dlls/winsock/socket.c
@@ -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;
+ }
}
diff --git a/files/file.c b/files/file.c
index 831a7c4..9cf0996 100644
--- a/files/file.c
+++ b/files/file.c
@@ -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;
+ }
}
/***********************************************************************