PATCH: async-struct.diff This patch introduces a new API for asynchronous requests, which - separates cleanly between async scheduling and file IO related issues - thereby makes the API compatible with other types of async requests (e.g. Winsock2). It is a polished resubmit of my former posting, without the GetOverlappedResult() stuff which will follow in a separate patch. It is against clean CVS 2002-01-15. I would be really grateful if this patch was applied, because it is a prerequisite for me to get going with Winsock2 overlapped IO. It was tested for regular file IO and (even 16 bit) serial IO (thanks 2 Lawson Whitney). No regressions found. ChangeLog: server/protocol.def and server/async.c: cancel_async(): new reqest type. include/file.h: struct async_ops: introduce "ops" field for different request types. struct async_private: only fields necessary for async request scheduling struct async_fileio: new struct, contains file IO related fields. scheduler/synchro.c: register_async(): replacement for FILE_StartAsync(). Hooks new requests in NtCurrentTeb()->pending_list. finish_async(): Assume status is already set correctly. Queue call_completion unconditionally. check_async(): Use register_async() for rescheduling. files/file.c: CancelIo(): Use new cancel_async server request. fileio_call_completion_func(): check if completion_func is non-NULL (see finish_async). FILE_AsyncReadService(), FILE_AsyncWriteService(): type adjustments according to new API FILE_ReadFileEx(), FILE_WriteFileEx(): use new async API. kernel/comm.c: COMM_WaitCommEventService(): Use new async API. Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com> diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c --- CVS/wine/dlls/kernel/comm.c Tue Jan 15 19:37:37 2002 +++ MW/wine/dlls/kernel/comm.c Tue Jan 15 19:09:42 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,34 @@ 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 15 19:37:37 2002 +++ MW/wine/files/file.c Tue Jan 15 19:34:00 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 @@ -1255,30 +1269,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.@) */ @@ -1288,21 +1278,61 @@ 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) * @@ -1311,18 +1341,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))) { @@ -1340,9 +1371,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; @@ -1358,7 +1389,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", @@ -1375,10 +1406,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"); @@ -1386,30 +1418,20 @@ 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; - - 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; - } + ovp->count = bytesToRead; - return TRUE; + /* Tell register_async that this is a new request */ + overlapped->Internal = STATUS_USER_APC; + return register_async (&ovp->async); } /*********************************************************************** @@ -1419,7 +1441,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0; return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine); } @@ -1503,7 +1524,6 @@ } /* at last resort, do an overlapped read */ - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = result; if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete)) @@ -1559,18 +1579,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))) { @@ -1587,9 +1608,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; @@ -1605,7 +1626,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); @@ -1616,45 +1638,36 @@ 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; - } - - /* 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 = bytesToWrite; - return TRUE; + /* Tell register_async that this is a new request */ + overlapped->Internal = STATUS_USER_APC; + return register_async (&ovp->async); } /*********************************************************************** @@ -1664,7 +1677,6 @@ LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->Internal = STATUS_PENDING; overlapped->InternalHigh = 0; return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h --- CVS/wine/include/file.h Tue Jan 15 19:37:37 2002 +++ MW/wine/include/file.h Tue Jan 15 19:09:42 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 ) @@ -82,7 +105,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 15 19:37:37 2002 +++ MW/wine/scheduler/synchro.c Tue Jan 15 19:09:42 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,29 @@ * * 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) + 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) - { - ovp->func(ovp); - FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal); - } + if( ovp_status == STATUS_PENDING ) ovp->func(ovp); - if(ovp->lpOverlapped->Internal!=STATUS_PENDING) - finish_async(ovp,ovp->lpOverlapped->Internal); + /* This will destroy all but PENDING requests */ + register_async (ovp); } diff -ruX diffignore CVS/wine/server/async.c MW/wine/server/async.c --- CVS/wine/server/async.c Tue Jan 15 19:37:37 2002 +++ MW/wine/server/async.c Tue Jan 15 19:09:42 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 15 19:37:37 2002 +++ MW/wine/server/protocol.def Tue Jan 15 19:09:42 2002 @@ -1534,7 +1534,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; @@ -1548,6 +1548,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)