Hi,
Here is a reworked version of the async API patch which I hope is now ready for being applied. Details see below.
Regards, Martin
PATCH: async-struct.diff
Purpose: Modified API for asynchronous IO requests.
- separate cleanly between async scheduling and file IO related issues, - make the API compatible with other types of async requests (e.g. for sockets), - remove exports of async IO related functions for DLL separation.
** This patch OBSOLETES these two patches I submitted: ** http://www.winehq.com/hypermail/wine-patches/2002/04/0020.html http://www.winehq.com/hypermail/wine-patches/2002/04/0034.html
Note: the cancel_async server request that was in the previous patch (0020.html) was removed (unnecessary).
Patch against: Wine CVS 2002/04/05
Test status: Compiles (no errors/warnings). Tested regular file async IO with ReadFile and ReadFileEx (ok).
Added files: include : async.h (structs and inline functions for async requests)
Modified files: server : protocol.def (add APC type APC_ASYNC_IO, remove func element of register_async request) async.h (remove func element in async struct) async.c (remove references to func element in async struct) thread.c (allow NULL function pointer for APC_ASYNC_IO requests) dlls/kernel : comm.c (use modified API) files : file.c (use modified API) include : file.h (move async stuff to async.h) scheduler : synchro.c (remove functions now inlined through async.h, call_apcs() calls check_async_list() for APC_ASYNC_IO APCs)
diff -ruNX ignore CVS/wine/dlls/kernel/comm.c TMP/wine/dlls/kernel/comm.c --- CVS/wine/dlls/kernel/comm.c Wed Apr 3 19:32:56 2002 +++ TMP/wine/dlls/kernel/comm.c Fri Apr 5 11:19:40 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 ignore CVS/wine/files/file.c TMP/wine/files/file.c --- CVS/wine/files/file.c Wed Apr 3 19:32:56 2002 +++ TMP/wine/files/file.c Fri Apr 5 12:15:58 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; w- 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,11 @@
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)) - { - TRACE("overlapped = %p\n",ovp->lpOverlapped); - finish_async(ovp, STATUS_CANCELLED); - } - ovp = t; + if ( ovp->handle == handle ) + cancel_async ( ovp ); } WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE); return TRUE; @@ -1400,18 +1430,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 +1460,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 +1479,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 +1499,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 +1507,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 +1529,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 +1606,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 +1663,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 +1692,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 +1711,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 +1723,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 +1760,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 ignore CVS/wine/include/async.h TMP/wine/include/async.h --- CVS/wine/include/async.h Thu Jan 1 01:00:00 1970 +++ TMP/wine/include/async.h Fri Apr 5 12:24:13 2002 @@ -0,0 +1,124 @@ +/* + * 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 */ + +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->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 ) +{ + ovp->ops->set_status ( ovp, STATUS_PENDING ); + + ovp->next = NtCurrentTeb()->pending_list; + ovp->prev = NULL; + if ( ovp->next ) ovp->next->prev = ovp; + NtCurrentTeb()->pending_list = ovp; + + return __register_async( ovp, STATUS_PENDING ); +} + +inline static BOOL cancel_async ( async_private *ovp ) +{ + /* avoid multiple cancellations */ + if ( ovp->ops->get_status( ovp ) != STATUS_PENDING ) + return 0; + ovp->ops->set_status ( ovp, STATUS_CANCELLED ); + return __register_async ( ovp, STATUS_CANCELLED ); +} + +#endif /* __WINE_ASYNC_H */ diff -ruNX ignore CVS/wine/include/file.h TMP/wine/include/file.h --- CVS/wine/include/file.h Wed Apr 3 19:32:56 2002 +++ TMP/wine/include/file.h Fri Apr 5 11:19:40 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 ignore CVS/wine/include/wine/server_protocol.h TMP/wine/include/wine/server_protocol.h --- CVS/wine/include/wine/server_protocol.h Tue Apr 2 15:39:35 2002 +++ TMP/wine/include/wine/server_protocol.h Fri Apr 5 12:21:25 2002 @@ -502,7 +502,7 @@ int type; /* VARARG(args,ptrs); */ }; -enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC }; +enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
@@ -2278,7 +2278,6 @@ { struct request_header __header; handle_t handle; - void* func; int type; void* overlapped; int count; @@ -3184,6 +3183,6 @@ struct get_window_properties_reply get_window_properties_reply; };
-#define SERVER_PROTOCOL_VERSION 77 +#define SERVER_PROTOCOL_VERSION 78
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff -ruNX ignore CVS/wine/scheduler/synchro.c TMP/wine/scheduler/synchro.c --- CVS/wine/scheduler/synchro.c Wed Apr 3 19:32:56 2002 +++ TMP/wine/scheduler/synchro.c Fri Apr 5 12:35:35 2002 @@ -30,6 +30,7 @@ #include "thread.h" #include "winerror.h" #include "wine/server.h" +#include "async.h"
/*********************************************************************** @@ -50,74 +51,32 @@ } }
-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) +static void WINAPI check_async_list(async_private *asp, DWORD status) { async_private *ovp; + DWORD ovp_status;
- /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */ + for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
- for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next) - if(ovp->lpOverlapped == overlapped) - break; - - if(!ovp) + if(!ovp) return;
- if(status != STATUS_ALERTED) - ovp->lpOverlapped->Internal = status; + if( status != STATUS_ALERTED ) + { + 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_old_async( ovp ); }
@@ -200,6 +159,9 @@ /* convert sec/usec to NT time */ DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 ); proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime ); + break; + case APC_ASYNC_IO: + check_async_list ( args[0], (DWORD) args[1]); break; default: server_protocol_error( "get_apc_request: bad type %d\n", type ); diff -ruNX ignore CVS/wine/server/async.c TMP/wine/server/async.c --- CVS/wine/server/async.c Wed Apr 3 19:32:56 2002 +++ TMP/wine/server/async.c Fri Apr 5 12:22:32 2002 @@ -64,7 +64,7 @@ { /* fprintf(stderr,"notifying %p!\n",async->overlapped); */ async->status = status; - thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status); + thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1, 2, async->overlapped, status); }
void destroy_async_queue( struct async_queue *q ) @@ -116,7 +116,7 @@ destroy_async(async); }
-struct async *create_async(struct object *obj, struct thread *thread, void *func, +struct async *create_async(struct object *obj, struct thread *thread, void *overlapped) { struct async *async = (struct async *) malloc(sizeof(struct async)); @@ -128,7 +128,6 @@
async->obj = obj; async->thread = thread; - async->func = func; async->overlapped = overlapped; async->next = NULL; async->prev = NULL; @@ -165,7 +164,7 @@ if(req->status==STATUS_PENDING) { if(!async) - async = create_async(obj, current, req->func, req->overlapped); + async = create_async(obj, current, req->overlapped);
if(async) { diff -ruNX ignore CVS/wine/server/async.h TMP/wine/server/async.h --- CVS/wine/server/async.h Tue Apr 2 15:39:41 2002 +++ TMP/wine/server/async.h Fri Apr 5 11:19:45 2002 @@ -30,7 +30,6 @@ { struct object *obj; struct thread *thread; - void *func; void *overlapped; unsigned int status; struct timeval when; @@ -51,7 +50,7 @@ struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped); void async_insert(struct async_queue *q, struct async *async); struct async *create_async(struct object *obj, struct thread *thread, - void *func, void *overlapped); + void *overlapped); void async_add_timeout(struct async *async, int timeout); static inline void init_async_queue(struct async_queue *q) { diff -ruNX ignore CVS/wine/server/protocol.def TMP/wine/server/protocol.def --- CVS/wine/server/protocol.def Wed Apr 3 19:32:56 2002 +++ TMP/wine/server/protocol.def Fri Apr 5 12:17:37 2002 @@ -412,7 +412,7 @@ int type; /* function type */ VARARG(args,ptrs); /* function arguments */ @END -enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC }; +enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
/* Close a handle for the current process */ @@ -1615,10 +1615,9 @@ #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; int type; void* overlapped; int count; diff -ruNX ignore CVS/wine/server/thread.c TMP/wine/server/thread.c --- CVS/wine/server/thread.c Tue Apr 2 15:39:42 2002 +++ TMP/wine/server/thread.c Fri Apr 5 11:19:45 2002 @@ -959,8 +959,9 @@ } /* Optimization: ignore APCs that have a NULL func; they are only used * to wake up a thread, but since we got here the thread woke up already. + * Exception: for APC_ASYNC_IO, func == NULL is legal. */ - if (apc->func) break; + if (apc->func || apc->type == APC_ASYNC_IO) break; free( apc ); } size = apc->nb_args * sizeof(apc->args[0]); diff -ruNX ignore CVS/wine/server/trace.c TMP/wine/server/trace.c --- CVS/wine/server/trace.c Wed Apr 3 19:32:56 2002 +++ TMP/wine/server/trace.c Fri Apr 5 12:21:25 2002 @@ -1846,7 +1846,6 @@ static void dump_register_async_request( const struct register_async_request *req ) { fprintf( stderr, " handle=%d,", req->handle ); - fprintf( stderr, " func=%p,", req->func ); fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " overlapped=%p,", req->overlapped ); fprintf( stderr, " count=%d,", req->count );
On April 5, 2002 06:32 am, Martin Wilck wrote:
Added files: include : async.h (structs and inline functions for
^^^^^^^
Shouldn't this file be added to include/wine dir, as it seems to be an internal Wine header.
Martin Wilck Martin.Wilck@fujitsu-siemens.com writes:
Purpose: Modified API for asynchronous IO requests.
- separate cleanly between async scheduling and file IO related issues,
- make the API compatible with other types of async requests (e.g. for sockets),
- remove exports of async IO related functions for DLL separation.
You cannot add private headers to work around the dll separation restrictions, this only hides the dependencies between dlls it doesn't solve them... I have applied the patch for now, but the async.h file will have to go away eventually (or the functionality will need to be "officially" exported from ntdll).
Dear Alexandre,
- separate cleanly between async scheduling and file IO related issues,
- make the API compatible with other types of async requests (e.g. for sockets),
- remove exports of async IO related functions for DLL separation.
You cannot add private headers to work around the dll separation restrictions, this only hides the dependencies between dlls it doesn't solve them... I have applied the patch for now, but the async.h file will have to go away eventually (or the functionality will need to be "officially" exported from ntdll).
What would be the correct solution, then? If I understand you right, each DLL that uses async IO must have its own implementation of async calls, i.e. not rely on anything implemented in ntdll except for the officially exported windows functions.
To achieve that, we can put functionally equivalent code into each DLL's sources, or we can provide a header that defines only static functions - as the first version of my patch did. That approach has the advantage that we won't have to repeat the same code in source files of different DLLs. What would be wrong with that?
The second version I sent (with check_async_list called automatically from call_apcs) re-introduces a hidden dependency on ntdll - obviously async calls from other DLLs won't work anymore if a native ntdll is used. That may be a step back. Still I cannot see a problem with the "static-only" header I used in the first version - can you explain that to me?
Martin
PS does anybody have an idea how Windows itself handles this, i.e. if the async calls in e.g. the Winsock API call ntdll functions internally? After all, it seems to be legitimate to mix ReadFile() and WSARecv() calls on sockets, although it would certainly be bad programming style. If we could only conceive of a way to implement async calls only on top of "official" windows functions...
Martin Wilck Martin.Wilck@fujitsu-siemens.com writes:
To achieve that, we can put functionally equivalent code into each DLL's sources, or we can provide a header that defines only static functions - as the first version of my patch did. That approach has the advantage that we won't have to repeat the same code in source files of different DLLs. What would be wrong with that?
One thing is that it introduces a header that doesn't exist under Windows. That can be acceptable, we have a few internal headers already; but it must be avoided as much as possible. The bigger problem is that you not only share static functions, but also data structures; and this is a big problem when trying to remain compatible between different versions of the various dlls.
Ultimately we may need to formalize this as part of the wine server interface, and we may not be able to avoid data structures completely. I do think that it should be possible to make the dlls more independent by doing more work in the server; but we should probably finish the implementation first and then we can start cleaning things up.