Hi Mike, all,
Unfortunately this patch has become big, because i came across so many problems today and I just needed to go forward. I am sorry for this, but it has become very late tonight, and I want people to see this stuff to stop me before it's too late (if I'm on the wrong track). It compiles without warnings, but I have not tested it - may crash wine right away, I don't know. However it should illustrate my ideas well: * Full separation of async handling and file io-specific stuff. * Do not rely on LPOVERLAPPED for status data in generic code, it may be NULL. File IO code may rely on it, here it is required to be non-NULL. * Use GetOverlappedResult() to check for immediate completion (UNTESTED!) Please give me comments telling me which parts you don't like, so that I can adjust for further development. Mike, can you tell me about those apps that were causing trouble in the past ? Where can I obtain them? Do they need special hardware (modem, mouse) for test runs ? Cheers, Martin -- Martin Wilck Phone: +49 5251 8 15113 Fujitsu Siemens Computers Fax: +49 5251 8 20409 Heinz-Nixdorf-Ring 1 mailto:[EMAIL PROTECTED] D-33106 Paderborn http://www.fujitsu-siemens.com/primergy ChangeLog: server/protocol.def: cancel_async(): Define new reqest type. server/async.c: cancel_async(): Implement new reqest type. include/file.h: struct async_ops: 4 methods for async_private: get_status, set_status, get_count, call_completion. struct async_private: contains only those elements which are absolutely necessary for queueing and server interaction struct async_fileio: contains all other fields. scheduler/synchro.c: register_async(): replacement for FILE_StartAsync(). Uses STATUS_USER_APC as (pseudo-) indicator to queue a new request. Hooks new requests in NtCurrentTeb()->pending_list (formerly done in calling functions). Not used by CancelIo() anymore. Finishes requests that are not in PENDING state after scheduling. finish_async(): Assume status is already set correctly. Queue call_completion unconditionally (No completion_func check needed) check_async(): Use register_async() for rescheduling. files/file.c: GetOverlappedResult(): Return ERROR_IO_INCOMPLETE if IO still pending (MSDN docs) FILE_StartAsync(): -> scheduler/synchro.c: register_async CancelIo(): Use new cancel_async server request (I felt former StartAsync() was too overloaded). Skip requests with wrong handle. fileio_call_completion_func(): Now called unconditionally, check if completion_func is non-NULL. FILE_AsyncReadService(): type adjustments according to new API FILE_AsyncWriteService(): dito FILE_ReadFileEx(): use new async API. Call GetOverlappedResult() to check for immediate completion. FILE_WriteFileEx(): dito. Now exactly equivalent to FILE_ReadFileEx() kernel/comm.c: COMM_WaitCommEventService(): Use new async API. diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c --- CVS/wine/dlls/kernel/comm.c Tue Jan 8 18:53:41 2002 +++ MW/wine/dlls/kernel/comm.c Wed Jan 9 21:20:37 2002 @@ -1514,12 +1514,13 @@ */ static void COMM_WaitCommEventService(async_private *ovp) { - LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; + async_fileio *fileio = (async_fileio*) ovp; + LPOVERLAPPED lpOverlapped = fileio->lpOverlapped; TRACE("overlapped %p\n",lpOverlapped); /* FIXME: detect other events */ - *ovp->buffer = EV_RXCHAR; + *fileio->buffer = EV_RXCHAR; lpOverlapped->Internal = STATUS_SUCCESS; } @@ -1536,7 +1537,7 @@ LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */ { int fd,ret; - async_private *ovp; + async_fileio *ovp; if(!lpOverlapped) { @@ -1547,52 +1548,35 @@ if(NtResetEvent(lpOverlapped->hEvent,NULL)) return FALSE; - lpOverlapped->Internal = STATUS_PENDING; - lpOverlapped->InternalHigh = 0; - lpOverlapped->Offset = 0; - lpOverlapped->OffsetHigh = 0; - fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); if(fd<0) return FALSE; - ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); + ovp = (async_fileio *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio)); if(!ovp) { close(fd); return FALSE; } + + ovp->async.ops = &fileio_async_ops; + ovp->async.handle = hFile; + ovp->async.fd = fd; + ovp->async.type = ASYNC_TYPE_WAIT; + ovp->async.func = COMM_WaitCommEventService; + ovp->lpOverlapped = lpOverlapped; - ovp->func = COMM_WaitCommEventService; ovp->buffer = (char *)lpdwEvents; - ovp->fd = fd; ovp->count = 0; ovp->completion_func = 0; - ovp->type = ASYNC_TYPE_WAIT; - ovp->handle = hFile; - - ovp->next = NtCurrentTeb()->pending_list; - ovp->prev = NULL; - if(ovp->next) - ovp->next->prev=ovp; - NtCurrentTeb()->pending_list = ovp; - /* start an ASYNCHRONOUS WaitCommEvent */ - SERVER_START_REQ( register_async ) - { - req->handle = hFile; - req->overlapped = lpOverlapped; - req->type = ASYNC_TYPE_WAIT; - req->count = 0; - req->func = check_async_list; - req->status = STATUS_PENDING; - - ret=wine_server_call_err(req); - } - SERVER_END_REQ; + lpOverlapped->Internal = STATUS_USER_APC; + lpOverlapped->InternalHigh = 0; + lpOverlapped->Offset = 0; + lpOverlapped->OffsetHigh = 0; - if (!ret) - SetLastError(ERROR_IO_PENDING); + if (register_async (&ovp->async)) + SetLastError(ERROR_IO_PENDING); return FALSE; } diff -ruX diffignore CVS/wine/files/file.c MW/wine/files/file.c --- CVS/wine/files/file.c Tue Jan 8 18:57:47 2002 +++ MW/wine/files/file.c Wed Jan 9 20:55:09 2002 @@ -60,6 +60,20 @@ static HANDLE dos_handles[DOS_TABLE_SIZE]; +/* Async operations struct (see file.h) */ + +static DWORD fileio_get_async_status (async_private *ovp); +static DWORD fileio_get_async_count (async_private *ovp); +static void fileio_set_async_status (async_private *ovp, DWORD status); +static void CALLBACK fileio_call_completion_func (ULONG_PTR data); + +async_ops fileio_async_ops = +{ + fileio_get_async_status, /* get_status */ + fileio_set_async_status, /* set_status */ + fileio_get_async_count, /* get_count */ + fileio_call_completion_func /* call_completion */ +}; /*********************************************************************** * FILE_ConvertOFMode @@ -1244,35 +1258,13 @@ if(lpTransferred) *lpTransferred = lpOverlapped->InternalHigh; - SetLastError(lpOverlapped->Internal); + /* This is what the function should return accirding to MSDN specs */ + if ( lpOverlapped->Internal == STATUS_PENDING ) + SetLastError (ERROR_IO_INCOMPLETE); return (r==WAIT_OBJECT_0); } - -/*********************************************************************** - * FILE_StartAsync (INTERNAL) - * - * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation - * lpOverlapped==NULL means all overlappeds match - */ -BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status) -{ - BOOL ret; - SERVER_START_REQ(register_async) - { - req->handle = hFile; - req->overlapped = lpOverlapped; - req->type = type; - req->count = count; - req->func = check_async_list; - req->status = status; - ret = wine_server_call( req ); - } - SERVER_END_REQ; - return !ret; -} - /*********************************************************************** * CancelIo (KERNEL32.@) */ @@ -1282,21 +1274,60 @@ TRACE("handle = %x\n",handle); - ovp = NtCurrentTeb()->pending_list; - while(ovp) + + for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t) { t = ovp->next; - if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED)) + if (ovp->handle != handle) continue; + + SERVER_START_REQ ( cancel_async ) { - TRACE("overlapped = %p\n",ovp->lpOverlapped); - finish_async(ovp, STATUS_CANCELLED); + req->handle = handle; + req->type = ovp->type; + req->overlapped = ovp; + wine_server_call ( req ); + if (reply->cancelled) + { + TRACE ("cancelling request: %p\n", ovp); + ovp->ops->set_status ( ovp, STATUS_CANCELLED ); + finish_async (ovp); + } } - ovp = t; + SERVER_END_REQ; } WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE); return TRUE; } +static DWORD fileio_get_async_status (async_private *ovp) +{ + return ((async_fileio*) ovp)->lpOverlapped->Internal; +} + +static void fileio_set_async_status (async_private *ovp, DWORD status) +{ + ((async_fileio*) ovp)->lpOverlapped->Internal = status; +} + +static DWORD fileio_get_async_count (async_private *ovp) +{ + async_fileio *fileio = (async_fileio*) ovp; + DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh; + return (ret < 0 ? 0 : ret); +} + +static void CALLBACK fileio_call_completion_func (ULONG_PTR data) +{ + async_fileio *ovp = (async_fileio*) data; + TRACE ("data: %p\n", ovp); + + if (ovp->completion_func) + ovp->completion_func(ovp->lpOverlapped->Internal, + ovp->lpOverlapped->InternalHigh, + ovp->lpOverlapped); + HeapFree(GetProcessHeap(), 0, ovp); +} + /*********************************************************************** * FILE_AsyncReadService (INTERNAL) * @@ -1305,18 +1336,19 @@ */ static void FILE_AsyncReadService(async_private *ovp) { - LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; + async_fileio *fileio = (async_fileio*) ovp; + LPOVERLAPPED lpOverlapped = fileio->lpOverlapped; int result, r; int already = lpOverlapped->InternalHigh; - TRACE("%p %p\n", lpOverlapped, ovp->buffer ); + TRACE("%p %p\n", lpOverlapped, fileio->buffer ); /* check to see if the data is ready (non-blocking) */ - result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already, + result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already, OVERLAPPED_OFFSET (lpOverlapped) + already); if ((result < 0) && (errno == ESPIPE)) - result = read (ovp->fd, &ovp->buffer[already], ovp->count - already); + result = read (ovp->fd, &fileio->buffer[already], fileio->count - already); if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR))) { @@ -1334,9 +1366,9 @@ } lpOverlapped->InternalHigh += result; - TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count); + TRACE("read %d more bytes %ld/%d so +far\n",result,lpOverlapped->InternalHigh,fileio->count); - if(lpOverlapped->InternalHigh < ovp->count) + if(lpOverlapped->InternalHigh < fileio->count) r = STATUS_PENDING; else r = STATUS_SUCCESS; @@ -1352,7 +1384,7 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_private *ovp; + async_fileio *ovp; int fd; TRACE("file %d to buf %p num %ld %p func %p\n", @@ -1369,10 +1401,11 @@ if(fd<0) { TRACE("Couldn't get FD\n"); + SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } - ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); + ovp = (async_fileio *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio)); if(!ovp) { TRACE("HeapAlloc Failed\n"); @@ -1380,30 +1413,23 @@ close(fd); return FALSE; } + + ovp->async.ops = &fileio_async_ops; + ovp->async.handle = hFile; + ovp->async.fd = fd; + ovp->async.type = ASYNC_TYPE_READ; + ovp->async.func = FILE_AsyncReadService; + ovp->lpOverlapped = overlapped; - ovp->count = bytesToRead; ovp->completion_func = lpCompletionRoutine; - ovp->func = FILE_AsyncReadService; ovp->buffer = buffer; - ovp->fd = fd; - ovp->type = ASYNC_TYPE_READ; - ovp->handle = hFile; - - /* hook this overlap into the pending async operation list */ - ovp->next = NtCurrentTeb()->pending_list; - ovp->prev = NULL; - if(ovp->next) - ovp->next->prev = ovp; - NtCurrentTeb()->pending_list = ovp; + ovp->count = bytesToRead; - if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) ) - { - /* FIXME: remove async_private and release memory */ - ERR("FILE_StartAsync failed\n"); - return FALSE; - } + /* Tell register_async that this is a new request */ + overlapped->Internal = STATUS_USER_APC; - return TRUE; + /* The request is hooked into the pending list by register_async() */ + return register_async (&ovp->async); } /*********************************************************************** @@ -1413,7 +1439,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0; return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine); } @@ -1470,41 +1495,21 @@ return FALSE; } - /* see if we can read some data already (this shouldn't block) */ - result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) ); - if ((result < 0) && (errno == ESPIPE)) - result = read( unix_handle, buffer, bytesToRead ); close(unix_handle); - - if(result<0) - { - if( (errno!=EAGAIN) && (errno!=EINTR) && - ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) ) - { - FILE_SetDosError(); - return FALSE; - } - else - result = 0; - } + overlapped->InternalHigh = 0; - /* if we read enough to keep the app happy, then return now */ - if(result>=bytesToRead) - { - *bytesRead = result; - return TRUE; - } + if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, +FILE_OverlappedComplete)) + return FALSE; - /* at last resort, do an overlapped read */ - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = result; - if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete)) + if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) ) + { + if ( GetLastError() == ERROR_IO_INCOMPLETE ) + SetLastError ( ERROR_IO_PENDING ); return FALSE; + } - /* fail on return, with ERROR_IO_PENDING */ - SetLastError(ERROR_IO_PENDING); - return FALSE; + return TRUE; } else if ( FD_TYPE (type) == FD_TYPE_CONSOLE ) @@ -1554,18 +1559,19 @@ */ static void FILE_AsyncWriteService(struct async_private *ovp) { - LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; + async_fileio *fileio = (async_fileio *) ovp; + LPOVERLAPPED lpOverlapped = fileio->lpOverlapped; int result, r; int already = lpOverlapped->InternalHigh; - TRACE("(%p %p)\n",lpOverlapped,ovp->buffer); + TRACE("(%p %p)\n",lpOverlapped,fileio->buffer); /* write some data (non-blocking) */ - result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already, + result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already, OVERLAPPED_OFFSET (lpOverlapped) + already); if ((result < 0) && (errno == ESPIPE)) - result = write(ovp->fd, &ovp->buffer[already], ovp->count - already); + result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR))) { @@ -1582,9 +1588,9 @@ lpOverlapped->InternalHigh += result; - TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count); + TRACE("wrote %d more bytes %ld/%d so +far\n",result,lpOverlapped->InternalHigh,fileio->count); - if(lpOverlapped->InternalHigh < ovp->count) + if(lpOverlapped->InternalHigh < fileio->count) r = STATUS_PENDING; else r = STATUS_SUCCESS; @@ -1600,7 +1606,8 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_private *ovp; + async_fileio *ovp; + int fd; TRACE("file %d to buf %p num %ld %p func %p stub\n", hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); @@ -1611,45 +1618,39 @@ return FALSE; } - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING )) + fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); + if(fd<0) { - TRACE("FILE_StartAsync failed\n"); + TRACE("Couldn't get FD\n"); + SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } - ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); + ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio)); if(!ovp) { TRACE("HeapAlloc Failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); + close(fd); return FALSE; } + + ovp->async.ops = &fileio_async_ops; + ovp->async.handle = hFile; + ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); + ovp->async.type = ASYNC_TYPE_WRITE; + ovp->async.func = FILE_AsyncWriteService; + ovp->lpOverlapped = overlapped; - ovp->func = FILE_AsyncWriteService; ovp->buffer = (LPVOID) buffer; - ovp->count = bytesToWrite; ovp->completion_func = lpCompletionRoutine; - ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); - ovp->type = ASYNC_TYPE_WRITE; - ovp->handle = hFile; - - if(ovp->fd <0) - { - HeapFree(GetProcessHeap(), 0, ovp); - return FALSE; - } + ovp->count = bytesToWrite; - /* hook this overlap into the pending async operation list */ - ovp->next = NtCurrentTeb()->pending_list; - ovp->prev = NULL; - if(ovp->next) - ovp->next->prev = ovp; - NtCurrentTeb()->pending_list = ovp; + /* Tell register_async that this is a new request */ + overlapped->Internal = STATUS_USER_APC; - return TRUE; + /* The request is hooked into the pending list by register_async() */ + return register_async (&ovp->async); } /*********************************************************************** @@ -1659,7 +1660,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0; return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); @@ -1693,44 +1693,20 @@ return FALSE; } - /* see if we can write some data already (this shouldn't block) */ - - result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) ); - if ((result < 0) && (errno == ESPIPE)) - result = write( unix_handle, buffer, bytesToWrite ); - close(unix_handle); - - if(result<0) - { - if( (errno!=EAGAIN) && (errno!=EINTR) && - ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) ) - { - FILE_SetDosError(); - return FALSE; - } - else - result = 0; - } - - /* if we wrote enough to keep the app happy, then return now */ - if(result>=bytesToWrite) - { - *bytesWritten = result; - return TRUE; - } - - /* at last resort, do an overlapped read */ - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = result; + overlapped->InternalHigh = 0; - if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete)) + if (!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, +FILE_OverlappedComplete)) return FALSE; + + if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) ) + { + if ( GetLastError() == ERROR_IO_INCOMPLETE ) + SetLastError ( ERROR_IO_PENDING ); + return FALSE; + } - /* fail on return, with ERROR_IO_PENDING */ - SetLastError(ERROR_IO_PENDING); - return FALSE; - + return TRUE; } else if ( FD_TYPE (type) == FD_TYPE_CONSOLE ) diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h --- CVS/wine/include/file.h Wed Jan 9 21:27:50 2002 +++ MW/wine/include/file.h Wed Jan 9 20:25:05 2002 @@ -33,23 +33,46 @@ /* overlapped private structure */ struct async_private; -typedef void (*async_handler)(struct async_private *ovp); + +typedef void (*async_handler) (struct async_private *ovp); +typedef void CALLBACK (*async_call_completion_func) (ULONG_PTR data); +typedef DWORD (*async_get_status) (struct async_private *ovp); +typedef DWORD (*async_get_count) (struct async_private *ovp); +typedef void (*async_set_status) (struct async_private *ovp, DWORD status); + +typedef struct async_ops +{ + async_get_status get_status; + async_set_status set_status; + async_get_count get_count; + async_call_completion_func call_completion; +} async_ops; + +extern async_ops fileio_async_ops; + typedef struct async_private { - LPOVERLAPPED lpOverlapped; - HANDLE handle; - int fd; - char *buffer; - async_handler func; - int count; - int type; - LPOVERLAPPED_COMPLETION_ROUTINE completion_func; - struct async_private *next; - struct async_private *prev; + async_ops *ops; + HANDLE handle; + int fd; + int type; + async_handler func; + struct async_private *next; + struct async_private *prev; } async_private; -extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status); -extern void finish_async(struct async_private *ovp, DWORD status); +typedef struct async_fileio +{ + async_private async; + LPOVERLAPPED lpOverlapped; + LPOVERLAPPED_COMPLETION_ROUTINE completion_func; + char *buffer; + int count; +} async_fileio; + +extern BOOL register_async (async_private *ovp); +extern void WINAPI check_async_list(async_private *ovp, DWORD status); +extern void finish_async(async_private *ovp); /* locale-independent case conversion */ inline static char FILE_tolower( char c ) @@ -83,7 +106,6 @@ DWORD attributes, HANDLE template, BOOL fail_read_only, UINT drive_type ); extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ); -extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status); extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG); diff -ruX diffignore CVS/wine/scheduler/synchro.c MW/wine/scheduler/synchro.c --- CVS/wine/scheduler/synchro.c Tue Jan 8 18:53:41 2002 +++ MW/wine/scheduler/synchro.c Wed Jan 9 20:27:16 2002 @@ -36,27 +36,60 @@ } } -static void CALLBACK call_completion_routine(ULONG_PTR data) +/*********************************************************************** + * register_async (INTERNAL) + * + * Manipulate async request queues. + */ +BOOL register_async (async_private *ovp) { - async_private* ovp = (async_private*)data; + BOOL ret; + DWORD status = ovp->ops->get_status (ovp); - ovp->completion_func(ovp->lpOverlapped->Internal, - ovp->lpOverlapped->InternalHigh, - ovp->lpOverlapped); - ovp->completion_func=NULL; - HeapFree(GetProcessHeap(), 0, ovp); -} + /* STATUS_USER_APC means this is a new request */ + /* STATUS_PENDING means this request is rescheduled (IO incomplete) */ -void finish_async(async_private *ovp, DWORD status) -{ - ovp->lpOverlapped->Internal=status; + if (status == STATUS_USER_APC) + { + status = STATUS_PENDING; + ovp->ops->set_status (ovp, status); + + /* hook this overlap into the pending async operation list */ + ovp->next = NtCurrentTeb()->pending_list; + ovp->prev = NULL; + if (ovp->next) ovp->next->prev = ovp; + NtCurrentTeb()->pending_list = ovp; + } - /* call ReadFileEx/WriteFileEx's overlapped completion function */ - if(ovp->completion_func) + /* The server call will destroy all except PENDING requests */ + SERVER_START_REQ(register_async) { - QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp); + req->handle = ovp->handle; + req->overlapped = ovp; + req->type = ovp->type; + req->count = ovp->ops->get_count (ovp); + req->func = check_async_list; + req->status = status; + ret = wine_server_call( req ); } + SERVER_END_REQ; + + if (ret) ovp->ops->set_status ( ovp, GetLastError() ); + + if ( ovp->ops->get_status (ovp) != STATUS_PENDING ) + finish_async (ovp); + return !ret; +} + +/*********************************************************************** + * finish_async (INTERNAL) + * + * Called after completion or cancellation of an async request. + * Note: The completion status must be set already. + */ +void finish_async(async_private *ovp) +{ /* remove it from the active list */ if(ovp->prev) ovp->prev->next = ovp->next; @@ -70,7 +103,9 @@ ovp->prev=NULL; close(ovp->fd); - if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp); + + /* Queue completion function unconditionally */ + QueueUserAPC(ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp); } /*********************************************************************** @@ -78,30 +113,33 @@ * * Process a status event from the server. */ -void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status) +void WINAPI check_async_list(async_private *asp, DWORD status) { - async_private *ovp; + async_private *ovp = NULL; + DWORD ovp_status; /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */ - for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next) - if(ovp->lpOverlapped == overlapped) - break; + for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next ); - if(!ovp) - return; + if(!ovp) return; if(status != STATUS_ALERTED) - ovp->lpOverlapped->Internal = status; + { + ovp_status = status; + ovp->ops->set_status (ovp, status); + } + else ovp_status = ovp->ops->get_status (ovp); - if(ovp->lpOverlapped->Internal==STATUS_PENDING) - { + if( ovp_status == STATUS_PENDING) + { ovp->func(ovp); - FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal); - } + register_async (ovp); + ovp_status = ovp->ops->get_status (ovp); + } - if(ovp->lpOverlapped->Internal!=STATUS_PENDING) - finish_async(ovp,ovp->lpOverlapped->Internal); + if( ovp_status != STATUS_PENDING ) + finish_async(ovp); } diff -ruX diffignore CVS/wine/server/async.c MW/wine/server/async.c --- CVS/wine/server/async.c Wed Jan 2 12:50:04 2002 +++ MW/wine/server/async.c Wed Jan 9 20:04:53 2002 @@ -177,3 +177,28 @@ release_object(obj); } +DECL_HANDLER(cancel_async) +{ + struct object *obj; + + if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) ) + return; + + if(obj->ops->queue_async) + { + struct async_queue *q = obj->ops->queue_async(obj, NULL, req->type, 0); + struct async *async; + + async = find_async(q, current, req->overlapped); + if (async) + { + destroy_async(async); + reply->cancelled = 1; + set_select_events(obj,obj->ops->get_poll_events(obj)); + } + else reply->cancelled = 0; + } + + release_object(obj); +} + diff -ruX diffignore CVS/wine/server/protocol.def MW/wine/server/protocol.def --- CVS/wine/server/protocol.def Tue Jan 8 18:58:28 2002 +++ MW/wine/server/protocol.def Wed Jan 9 19:52:33 2002 @@ -1535,7 +1535,7 @@ #define SERIALINFO_SET_ERROR 0x04 -/* Create/Destroy an async I/O */ +/* Create / reschedule an async I/O */ @REQ(register_async) handle_t handle; /* handle to comm port, socket or file */ void* func; @@ -1549,6 +1549,14 @@ #define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WAIT 0x03 +/* Cancel an async I/O */ +@REQ(cancel_async) + handle_t handle; + int type; + void* overlapped; +@REPLY + int cancelled; +@END /* Create a named pipe */ @REQ(create_named_pipe)