Patch: GetOverlappedResult.diff Martin Wilck <Martin.Wilck@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@Fujitsu-Siemens.com D-33106 Paderborn http://www.fujitsu-siemens.com/primergy