PATCH: async-struct.diff
This patch introduces a new API for asynchronous requests, which
1) separates cleanly between async scheduling and file IO related issues, 2) thereby makes the API compatible with other types of async requests, 3) makes all async IO handling functions static for better DLL separation.
This a a reworked version of my patch as of 2002/01/15, with modifications to achieve 3).
Patch against: Wine CVS 2002/04/03 Test status: Compiles (no errors/warnings), tested regular file async IO (ok).
Added files: include : async.h
Modified files: server : protocol.def async.c dlls/kernel : comm.c files : file.c include : file.h scheduler : synchro.c
Log message: Martin Wilck Martin.Wilck@Fujitsu-Siemens.com - new server call: cancel_async - move async IO API from include/file.h, scheduler/synchro.c to new header file include/async.h - differentiate generic async API from IO-type specific fields
diff -ruNX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c --- CVS/wine/dlls/kernel/comm.c Tue Apr 2 15:39:18 2002 +++ MW/wine/dlls/kernel/comm.c Wed Apr 3 14:48:39 2002 @@ -91,6 +91,53 @@
WINE_DEFAULT_DEBUG_CHANNEL(comm);
+/*********************************************************************** + * Asynchronous I/O for asynchronous wait requests * + */ +#include "async.h" + +static DWORD commio_get_async_status (const async_private *ovp); +static DWORD commio_get_async_count (const async_private *ovp); +static void commio_set_async_status (async_private *ovp, const DWORD status); +static void CALLBACK commio_call_completion_func (ULONG_PTR data); + +static async_ops commio_async_ops = +{ + commio_get_async_status, /* get_status */ + commio_set_async_status, /* set_status */ + commio_get_async_count, /* get_count */ + commio_call_completion_func /* call_completion */ +}; + +typedef struct async_commio +{ + struct async_private async; + LPOVERLAPPED lpOverlapped; + char *buffer; +} async_commio; + +static DWORD commio_get_async_status (const struct async_private *ovp) +{ + return ((async_commio*) ovp)->lpOverlapped->Internal; +} + +static void commio_set_async_status (async_private *ovp, const DWORD status) +{ + ((async_commio*) ovp)->lpOverlapped->Internal = status; +} + +static DWORD commio_get_async_count (const struct async_private *ovp) +{ + return 0; +} + +static void CALLBACK commio_call_completion_func (ULONG_PTR data) +{ + HeapFree(GetProcessHeap(), 0, (void*) data); +} + +/***********************************************************************/ + #if !defined(TIOCINQ) && defined(FIONREAD) #define TIOCINQ FIONREAD #endif @@ -1558,12 +1605,13 @@ */ static void COMM_WaitCommEventService(async_private *ovp) { - LPOVERLAPPED lpOverlapped = ovp->lpOverlapped; + async_commio *commio = (async_commio*) ovp; + LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
TRACE("overlapped %p\n",lpOverlapped);
/* FIXME: detect other events */ - *ovp->buffer = EV_RXCHAR; + *commio->buffer = EV_RXCHAR;
lpOverlapped->Internal = STATUS_SUCCESS; } @@ -1579,8 +1627,8 @@ LPDWORD lpdwEvents, /* [out] event(s) that were detected */ LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */ { - int fd,ret; - async_private *ovp; + int fd; + async_commio *ovp;
if(!lpOverlapped) { @@ -1591,53 +1639,32 @@ 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_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio)); if(!ovp) { close(fd); return FALSE; } - ovp->event = lpOverlapped->hEvent; + + ovp->async.ops = &commio_async_ops; + ovp->async.handle = hFile; + ovp->async.fd = fd; + ovp->async.type = ASYNC_TYPE_WAIT; + ovp->async.func = COMM_WaitCommEventService; + ovp->async.event = lpOverlapped->hEvent; 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->InternalHigh = 0; + lpOverlapped->Offset = 0; + lpOverlapped->OffsetHigh = 0;
- if (!ret) - SetLastError(ERROR_IO_PENDING); + if ( !register_new_async (&ovp->async) ) + SetLastError( ERROR_IO_PENDING );
return FALSE; } diff -ruNX diffignore CVS/wine/files/file.c MW/wine/files/file.c --- CVS/wine/files/file.c Tue Apr 2 15:39:31 2002 +++ MW/wine/files/file.c Wed Apr 3 16:00:38 2002 @@ -64,6 +64,65 @@
WINE_DEFAULT_DEBUG_CHANNEL(file);
+/*********************************************************************** + * Asynchronous file I/O * + */ +#include "async.h" + +static DWORD fileio_get_async_status (const async_private *ovp); +static DWORD fileio_get_async_count (const async_private *ovp); +static void fileio_set_async_status (async_private *ovp, const DWORD status); +static void CALLBACK fileio_call_completion_func (ULONG_PTR data); + +static 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 */ +}; + +typedef struct async_fileio +{ + struct async_private async; + LPOVERLAPPED lpOverlapped; + LPOVERLAPPED_COMPLETION_ROUTINE completion_func; + char *buffer; + int count; +} async_fileio; + +static DWORD fileio_get_async_status (const struct async_private *ovp) +{ + return ((async_fileio*) ovp)->lpOverlapped->Internal; +} + +static void fileio_set_async_status (async_private *ovp, const DWORD status) +{ + ((async_fileio*) ovp)->lpOverlapped->Internal = status; +} + +static DWORD fileio_get_async_count (const struct 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); +} + +/***********************************************************************/ + #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) #define MAP_ANON MAP_ANONYMOUS #endif @@ -1344,30 +1403,6 @@ 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.@) */ @@ -1377,16 +1412,25 @@
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; @@ -1400,18 +1444,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))) { @@ -1429,9 +1474,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; @@ -1448,7 +1493,7 @@ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, HANDLE hEvent) { - async_private *ovp; + async_fileio *ovp; int fd;
TRACE("file %d to buf %p num %ld %p func %p\n", @@ -1468,7 +1513,7 @@ 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"); @@ -1476,31 +1521,19 @@ close(fd); return FALSE; } - ovp->event = hEvent; + + 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->async.event = hEvent; 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; - - 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; - }
- return TRUE; + return !register_new_async (&ovp->async); }
/*********************************************************************** @@ -1510,7 +1543,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0; return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE); } @@ -1588,7 +1620,6 @@ }
/* at last resort, do an overlapped read */ - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = result;
if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent)) @@ -1646,18 +1677,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))) { @@ -1674,9 +1706,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; @@ -1693,7 +1725,8 @@ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, HANDLE hEvent) { - 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); @@ -1704,46 +1737,34 @@ 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" ); 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->event = hEvent; - ovp->func = FILE_AsyncWriteService; + ovp->async.event = hEvent; 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; - } - - /* 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; - - return TRUE; + return !register_new_async (&ovp->async); }
/*********************************************************************** @@ -1753,7 +1774,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0;
return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE); diff -ruNX diffignore CVS/wine/include/async.h MW/wine/include/async.h --- CVS/wine/include/async.h Thu Jan 1 01:00:00 1970 +++ MW/wine/include/async.h Wed Apr 3 15:41:18 2002 @@ -0,0 +1,143 @@ +/* + * Structures and static functions for handling asynchronous I/O. + * + * Copyright (C) 2002 Mike McCormack, Martin Wilck + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This file declares static functions. + * It should only be included by those source files that implement async I/O requests. + */ + +#ifndef __WINE_ASYNC_H +#define __WINE_ASYNC_H + +struct async_private; + +typedef void (*async_handler)(struct async_private *ovp); +typedef void CALLBACK (*async_call_completion_func)(ULONG_PTR data); +typedef DWORD (*async_get_status)(const struct async_private *ovp); +typedef DWORD (*async_get_count)(const struct async_private *ovp); +typedef void (*async_set_status)(struct async_private *ovp, const 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; + +typedef struct async_private +{ + struct async_ops *ops; + HANDLE handle; + HANDLE event; + int fd; + async_handler func; + int type; + struct async_private *next; + struct async_private *prev; +} async_private; + +/* All functions declared static for Dll separation purposes */ + +static void WINAPI check_async_list(async_private *asp, DWORD status); + +inline static void finish_async( async_private *ovp ) +{ + if(ovp->prev) + ovp->prev->next = ovp->next; + else + NtCurrentTeb()->pending_list = ovp->next; + + if(ovp->next) + ovp->next->prev = ovp->prev; + + ovp->next = ovp->prev = NULL; + + close( ovp->fd ); + if( ovp->event!=INVALID_HANDLE_VALUE ) + NtSetEvent( ovp->event, NULL ); + + QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp ); +} + +inline static BOOL __register_async( async_private *ovp, const DWORD status ) +{ + BOOL ret; + + SERVER_START_REQ( register_async ) + { + 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; +} + +#define register_old_async(ovp) \ + __register_async (ovp, ovp->ops->get_status( ovp )); + +inline static BOOL register_new_async( async_private *ovp ) +{ + const DWORD status = STATUS_PENDING; + + ovp->ops->set_status (ovp, status); + + ovp->next = NtCurrentTeb()->pending_list; + ovp->prev = NULL; + if (ovp->next) ovp->next->prev = ovp; + NtCurrentTeb()->pending_list = ovp; + + return __register_async( ovp, status ); +} + +static void WINAPI check_async_list(async_private *asp, DWORD status) +{ + async_private *ovp; + DWORD ovp_status; + + for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next ); + + if(!ovp) + return; + + if( status != STATUS_ALERTED ) + { + ovp_status = status; + ovp->ops->set_status (ovp, status); + } + else ovp_status = ovp->ops->get_status (ovp); + + if( ovp_status == STATUS_PENDING ) ovp->func( ovp ); /* ovp->func may change status */ + + /* This will destroy all but PENDING requests */ + register_old_async( ovp ); +} + +#endif /* __WINE_ASYNC_H */ diff -ruNX diffignore CVS/wine/include/file.h MW/wine/include/file.h --- CVS/wine/include/file.h Tue Apr 2 15:39:33 2002 +++ MW/wine/include/file.h Wed Apr 3 13:07:35 2002 @@ -46,27 +46,6 @@ int flags; } DOS_DEVICE;
-/* overlapped private structure */ -struct async_private; -typedef void (*async_handler)(struct async_private *ovp); -typedef struct async_private -{ - LPOVERLAPPED lpOverlapped; - HANDLE handle; - HANDLE event; - 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_private; - -extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status); -extern void finish_async(struct async_private *ovp, DWORD status); - /* locale-independent case conversion */ inline static char FILE_tolower( char c ) { @@ -99,7 +78,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 -ruNX diffignore CVS/wine/scheduler/synchro.c MW/wine/scheduler/synchro.c --- CVS/wine/scheduler/synchro.c Tue Apr 2 15:39:41 2002 +++ MW/wine/scheduler/synchro.c Wed Apr 3 16:01:36 2002 @@ -50,77 +50,6 @@ } }
-static void CALLBACK call_completion_routine(ULONG_PTR data) -{ - async_private* ovp = (async_private*)data; - - ovp->completion_func(ovp->lpOverlapped->Internal, - ovp->lpOverlapped->InternalHigh, - ovp->lpOverlapped); - ovp->completion_func=NULL; - HeapFree(GetProcessHeap(), 0, ovp); -} - -void finish_async(async_private *ovp, DWORD status) -{ - ovp->lpOverlapped->Internal=status; - - /* call ReadFileEx/WriteFileEx's overlapped completion function */ - if(ovp->completion_func) - { - QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp); - } - - /* remove it from the active list */ - if(ovp->prev) - ovp->prev->next = ovp->next; - else - NtCurrentTeb()->pending_list = ovp->next; - - if(ovp->next) - ovp->next->prev = ovp->prev; - - ovp->next=NULL; - ovp->prev=NULL; - - close(ovp->fd); - if(ovp->event!=INVALID_HANDLE_VALUE) - NtSetEvent(ovp->event,NULL); - if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp); -} - -/*********************************************************************** - * check_async_list - * - * Process a status event from the server. - */ -void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status) -{ - async_private *ovp; - - /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */ - - for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next) - if(ovp->lpOverlapped == overlapped) - break; - - if(!ovp) - return; - - if(status != STATUS_ALERTED) - ovp->lpOverlapped->Internal = status; - - if(ovp->lpOverlapped->Internal==STATUS_PENDING) - { - ovp->func(ovp); - FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal); - } - - if(ovp->lpOverlapped->Internal!=STATUS_PENDING) - finish_async(ovp,ovp->lpOverlapped->Internal); -} - - /*********************************************************************** * wait_reply * diff -ruNX diffignore CVS/wine/server/async.c MW/wine/server/async.c --- CVS/wine/server/async.c Tue Apr 2 15:39:41 2002 +++ MW/wine/server/async.c Tue Apr 2 17:17:00 2002 @@ -190,3 +190,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 -ruNX diffignore CVS/wine/server/protocol.def MW/wine/server/protocol.def --- CVS/wine/server/protocol.def Tue Apr 2 15:39:41 2002 +++ MW/wine/server/protocol.def Tue Apr 2 17:17:00 2002 @@ -1615,7 +1615,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; @@ -1629,6 +1629,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) diff -ruNX diffignore CVS/wine/server/request.h MW/wine/server/request.h --- CVS/wine/server/request.h Tue Apr 2 15:39:41 2002 +++ MW/wine/server/request.h Wed Apr 3 13:06:02 2002 @@ -228,6 +228,7 @@ DECL_HANDLER(get_serial_info); DECL_HANDLER(set_serial_info); DECL_HANDLER(register_async); +DECL_HANDLER(cancel_async); DECL_HANDLER(create_named_pipe); DECL_HANDLER(open_named_pipe); DECL_HANDLER(connect_named_pipe); @@ -388,6 +389,7 @@ (req_handler)req_get_serial_info, (req_handler)req_set_serial_info, (req_handler)req_register_async, + (req_handler)req_cancel_async, (req_handler)req_create_named_pipe, (req_handler)req_open_named_pipe, (req_handler)req_connect_named_pipe, diff -ruNX diffignore CVS/wine/server/trace.c MW/wine/server/trace.c --- CVS/wine/server/trace.c Tue Apr 2 15:39:42 2002 +++ MW/wine/server/trace.c Wed Apr 3 13:06:02 2002 @@ -1853,6 +1853,18 @@ fprintf( stderr, " status=%08x", req->status ); }
+static void dump_cancel_async_request( const struct cancel_async_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " type=%d,", req->type ); + fprintf( stderr, " overlapped=%p", req->overlapped ); +} + +static void dump_cancel_async_reply( const struct cancel_async_reply *req ) +{ + fprintf( stderr, " cancelled=%d", req->cancelled ); +} + static void dump_create_named_pipe_request( const struct create_named_pipe_request *req ) { fprintf( stderr, " openmode=%08x,", req->openmode ); @@ -2292,6 +2304,7 @@ (dump_func)dump_get_serial_info_request, (dump_func)dump_set_serial_info_request, (dump_func)dump_register_async_request, + (dump_func)dump_cancel_async_request, (dump_func)dump_create_named_pipe_request, (dump_func)dump_open_named_pipe_request, (dump_func)dump_connect_named_pipe_request, @@ -2449,6 +2462,7 @@ (dump_func)dump_get_serial_info_reply, (dump_func)0, (dump_func)0, + (dump_func)dump_cancel_async_reply, (dump_func)dump_create_named_pipe_reply, (dump_func)dump_open_named_pipe_reply, (dump_func)0, @@ -2606,6 +2620,7 @@ "get_serial_info", "set_serial_info", "register_async", + "cancel_async", "create_named_pipe", "open_named_pipe", "connect_named_pipe",