diff --git a/dlls/kernel/file.c b/dlls/kernel/file.c index 44176b3d19e..fefe71506eb 100644 --- a/dlls/kernel/file.c +++ b/dlls/kernel/file.c @@ -497,56 +497,64 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpTransferred, BOOL bWait) { - DWORD r; + DWORD r = WAIT_OBJECT_0; - TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait); + TRACE( "(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait ); - if (lpOverlapped==NULL) + if ( lpOverlapped == NULL ) { ERR("lpOverlapped was null\n"); return FALSE; } - if (!lpOverlapped->hEvent) - { - ERR("lpOverlapped->hEvent was null\n"); - return FALSE; - } - 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); + if ( lpOverlapped->hEvent ) + { + do + { + TRACE( "waiting on %p\n", lpOverlapped ); + r = WaitForSingleObjectEx( lpOverlapped->hEvent, INFINITE, TRUE ); + TRACE( "wait on %p returned %ld\n", lpOverlapped, r ); + } while ( r == WAIT_IO_COMPLETION ); + } + else + { + /* busy loop */ + while ( (volatile DWORD)lpOverlapped->Internal == STATUS_PENDING ) + Sleep( 10 ); + } } 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, 0, TRUE); - TRACE("wait on %p returned %ld\n",lpOverlapped,r); - } while (r==STATUS_USER_APC); - if ( r == WAIT_OBJECT_0 ) - NtSetEvent ( lpOverlapped->hEvent, NULL ); + do + { + TRACE( "waiting on %p\n", lpOverlapped ); + r = WaitForSingleObjectEx( lpOverlapped->hEvent, 0, TRUE ); + TRACE( "wait on %p returned %ld\n", lpOverlapped, r ); + } while ( r == WAIT_IO_COMPLETION ); + if ( r == WAIT_OBJECT_0 && lpOverlapped->hEvent ) + NtSetEvent( lpOverlapped->hEvent, NULL ); } - - if(lpTransferred) - *lpTransferred = lpOverlapped->InternalHigh; + if ( r == WAIT_FAILED ) + { + ERR("wait operation failed\n"); + return FALSE; + } + if (lpTransferred) *lpTransferred = lpOverlapped->InternalHigh; switch ( lpOverlapped->Internal ) { case STATUS_SUCCESS: return TRUE; case STATUS_PENDING: - SetLastError ( ERROR_IO_INCOMPLETE ); - if ( bWait ) ERR ("PENDING status after waiting!\n"); + SetLastError( ERROR_IO_INCOMPLETE ); + if ( bWait ) ERR("PENDING status after waiting!\n"); return FALSE; default: - SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) ); + SetLastError( RtlNtStatusToDosError( lpOverlapped->Internal ) ); return FALSE; } } @@ -640,7 +648,6 @@ HFILE WINAPI _lopen( LPCSTR path, INT mode ) return (HFILE)create_file_OF( path, mode & ~OF_CREATE ); } - /*********************************************************************** * _lread (KERNEL32.@) */ diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 0d4bdec917c..4d253fc43d5 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -247,13 +247,13 @@ typedef struct async_fileio void* apc_user; char *buffer; unsigned int count; - unsigned long offset; - enum fd_type fd_type; + off_t offset; + BOOL avail_mode; } async_fileio; static DWORD fileio_get_async_count(const struct async_private *ovp) { - async_fileio *fileio = (async_fileio*) ovp; + const async_fileio *fileio = (const async_fileio*) ovp; if (fileio->count < fileio->async.iosb->Information) return 0; @@ -334,7 +334,7 @@ static void FILE_AsyncReadService(async_private *ovp) /* check to see if the data is ready (non-blocking) */ - if ( fileio->fd_type == FD_TYPE_SOCKET ) + if ( fileio->avail_mode ) result = read(ovp->fd, &fileio->buffer[already], fileio->count - already); else { @@ -363,14 +363,15 @@ static void FILE_AsyncReadService(async_private *ovp) return; } + TRACE("status before: %s\n", (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending"); io_status->Information += result; - if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET ) + if (io_status->Information >= fileio->count || fileio->avail_mode ) io_status->u.Status = STATUS_SUCCESS; else io_status->u.Status = STATUS_PENDING; - TRACE("read %d more bytes %ld/%d so far\n", - result, io_status->Information, fileio->count); + TRACE("read %d more bytes %ld/%d so far (%s)\n", + result, io_status->Information, fileio->count, (io_status->u.Status == STATUS_SUCCESS) ? "success" : "pending"); } @@ -402,13 +403,12 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, PLARGE_INTEGER offset, PULONG key) { int unix_handle, flags; - enum fd_type type; TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n", hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); io_status->Information = 0; - io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, &type, &flags ); + io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_READ, &unix_handle, NULL, &flags ); if (io_status->u.Status) return io_status->u.Status; if (flags & FD_FLAG_RECV_SHUTDOWN) @@ -442,6 +442,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, if (!(ovp = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(async_fileio)))) { wine_server_release_fd( hFile, unix_handle ); + if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent); return STATUS_NO_MEMORY; } ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops ); @@ -456,18 +457,24 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, ovp->offset = 0; else { - ovp->offset = offset->u.LowPart; - if (offset->u.HighPart) FIXME("NIY-high part\n"); + ovp->offset = offset->QuadPart; + if (offset->u.HighPart && ovp->offset == offset->u.LowPart) + FIXME("High part of offset is lost\n"); } ovp->apc = apc; ovp->apc_user = apc_user; ovp->buffer = buffer; - ovp->fd_type = type; + ovp->avail_mode = (flags & FD_FLAG_AVAILABLE); + NtResetEvent(hEvent, NULL); - io_status->Information = 0; ret = register_new_async(&ovp->async); if (ret != STATUS_SUCCESS) + { + wine_server_release_fd( hFile, unix_handle ); + if (flags & FD_FLAG_TIMEOUT) NtClose(hEvent); + RtlFreeHeap(GetProcessHeap(), 0, ovp); return ret; + } if (flags & FD_FLAG_TIMEOUT) { NtWaitForSingleObject(hEvent, TRUE, NULL); @@ -480,6 +487,15 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, /* let some APC be run, this will read some already pending data */ timeout.u.LowPart = timeout.u.HighPart = 0; NtDelayExecution( TRUE, &timeout ); + /* 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) + */ + if ((flags & FD_FLAG_AVAILABLE) && io_status->u.Status == STATUS_PENDING) + { + io_status->u.Status = STATUS_SUCCESS; + register_old_async(&ovp->async); + } } return io_status->u.Status; } @@ -526,7 +542,7 @@ static void FILE_AsyncWriteService(struct async_private *ovp) /* write some data (non-blocking) */ - if ( fileio->fd_type == FD_TYPE_SOCKET ) + if ( fileio->avail_mode ) result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); else { @@ -583,16 +599,12 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, PLARGE_INTEGER offset, PULONG key) { int unix_handle, flags; - enum fd_type type; TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n", hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); - TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n", - hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); - io_status->Information = 0; - io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, &type, &flags ); + io_status->u.Status = wine_server_handle_to_fd( hFile, GENERIC_WRITE, &unix_handle, NULL, &flags ); if (io_status->u.Status) return io_status->u.Status; if (flags & FD_FLAG_SEND_SHUTDOWN) @@ -620,15 +632,17 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, ovp->async.iosb = io_status; ovp->count = length; if (offset) { - ovp->offset = offset->u.LowPart; - if (offset->u.HighPart) FIXME("NIY-high part\n"); + ovp->offset = offset->QuadPart; + if (offset->u.HighPart && ovp->offset == offset->u.LowPart) + FIXME("High part of offset is lost\n"); } else { ovp->offset = 0; } ovp->apc = apc; ovp->apc_user = apc_user; ovp->buffer = (void*)buffer; - ovp->fd_type = type; + ovp->avail_mode = (flags & FD_FLAG_AVAILABLE); + NtResetEvent(hEvent, NULL); io_status->Information = 0; ret = register_new_async(&ovp->async); diff --git a/include/async.h b/include/async.h index 4bc71914b0a..eae7ee7e9c8 100644 --- a/include/async.h +++ b/include/async.h @@ -111,8 +111,10 @@ inline static NTSTATUS __register_async( async_private *ovp, const DWORD status return ret; } -#define register_old_async(ovp) \ - __register_async(ovp, ovp->iosb->u.Status); +inline static NTSTATUS register_old_async( async_private *ovp ) +{ + return __register_async(ovp, ovp->iosb->u.Status); +} inline static NTSTATUS register_new_async( async_private *ovp ) { diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 76fa6bed8b2..40810a91eec 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -805,6 +805,8 @@ enum fd_type #define FD_FLAG_TIMEOUT 0x02 #define FD_FLAG_RECV_SHUTDOWN 0x04 #define FD_FLAG_SEND_SHUTDOWN 0x08 +#define FD_FLAG_AVAILABLE 0x10 /* in overlap read/write operation, + * only handle available data (don't wait) */ @@ -3647,6 +3649,6 @@ union generic_reply struct set_global_windows_reply set_global_windows_reply; }; -#define SERVER_PROTOCOL_VERSION 147 +#define SERVER_PROTOCOL_VERSION 148 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index a2864be0bc4..38595338f03 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -612,10 +612,12 @@ enum fd_type FD_TYPE_DEFAULT, FD_TYPE_SOCKET }; -#define FD_FLAG_OVERLAPPED 0x01 -#define FD_FLAG_TIMEOUT 0x02 +#define FD_FLAG_OVERLAPPED 0x01 /* fd opened in overlapped mode */ +#define FD_FLAG_TIMEOUT 0x02 /* read/write is synchronous */ #define FD_FLAG_RECV_SHUTDOWN 0x04 #define FD_FLAG_SEND_SHUTDOWN 0x08 +#define FD_FLAG_AVAILABLE 0x10 /* in overlap read/write operation, + * only handle available data (don't wait) */ /* Flush a file buffers */ diff --git a/server/serial.c b/server/serial.c index 5dd55d76fc5..de0e373b733 100644 --- a/server/serial.c +++ b/server/serial.c @@ -209,9 +209,12 @@ static int serial_get_info( struct fd *fd, int *flags ) *flags = 0; if (!(serial->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))) *flags |= FD_FLAG_OVERLAPPED; - else if(!((serial->readinterval == MAXDWORD) && - (serial->readmult == 0) && (serial->readconst == 0)) ) + else if (!(serial->readinterval == MAXDWORD && + serial->readmult == 0 && serial->readconst == 0)) *flags |= FD_FLAG_TIMEOUT; + if (serial->readinterval == MAXDWORD && + serial->readmult == 0 && serial->readconst == 0) + *flags |= FD_FLAG_AVAILABLE; return FD_TYPE_DEFAULT; } @@ -292,7 +295,7 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in else if ( async ) destroy_async ( async ); else set_error ( STATUS_INVALID_PARAMETER ); - set_fd_events ( fd, serial_get_poll_events( fd )); + set_fd_events ( fd, serial_get_poll_events( fd ) ); } static int serial_flush( struct fd *fd, struct event **event ) diff --git a/server/sock.c b/server/sock.c index 2b1a1267f89..059bdba3326 100644 --- a/server/sock.c +++ b/server/sock.c @@ -234,7 +234,7 @@ static void sock_wake_up( struct sock *sock, int pollev ) int i; int async_active = 0; - if ( sock->flags & FD_FLAG_OVERLAPPED ) + if ( sock->flags & WSA_FLAG_OVERLAPPED ) { if( pollev & (POLLIN|POLLPRI) && IS_READY( sock->read_q ) ) { @@ -425,7 +425,7 @@ static void sock_poll_event( struct fd *fd, int event ) sock_reselect( sock ); /* wake up anyone waiting for whatever just happened */ - if ( sock->pmask & sock->mask || sock->flags & FD_FLAG_OVERLAPPED ) sock_wake_up( sock, event ); + if ( sock->pmask & sock->mask || sock->flags & WSA_FLAG_OVERLAPPED ) sock_wake_up( sock, event ); /* if anyone is stupid enough to wait on the socket object itself, * maybe we should wake them up too, just in case? */ @@ -480,7 +480,7 @@ static int sock_get_info( struct fd *fd, int *flags ) struct sock *sock = get_fd_user( fd ); assert ( sock->obj.ops == &sock_ops ); - *flags = 0; + *flags = FD_FLAG_AVAILABLE; if (sock->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED; if ( sock->type != SOCK_STREAM || sock->state & FD_WINE_CONNECTED ) {