From 2b47fb3cee8625ef5b1265060570bde7633b2e5d Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 5 Apr 2002 22:53:57 +0000 Subject: [PATCH] - 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. --- dlls/kernel/comm.c | 103 ++++++++++------- files/file.c | 197 +++++++++++++++++---------------- include/async.h | 126 +++++++++++++++++++++ include/file.h | 22 ---- include/wine/server_protocol.h | 5 +- scheduler/synchro.c | 70 +++--------- server/async.c | 7 +- server/async.h | 3 +- server/protocol.def | 5 +- server/thread.c | 3 +- server/trace.c | 1 - 11 files changed, 317 insertions(+), 225 deletions(-) create mode 100644 include/async.h diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c index b81c50dec96..53da53cf95f 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -80,6 +80,7 @@ #include "winerror.h" #include "wine/server.h" +#include "async.h" #include "file.h" #include "heap.h" @@ -91,6 +92,52 @@ WINE_DEFAULT_DEBUG_CHANNEL(comm); +/*********************************************************************** + * Asynchronous I/O for asynchronous wait requests * + */ + +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 @@ BOOL WINAPI GetCommModemStatus( */ 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 @@ static BOOL COMM_WaitCommEvent( 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 @@ static BOOL COMM_WaitCommEvent( 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 --git a/files/file.c b/files/file.c index 7d23c6c6c6f..dbae5f2a57b 100644 --- a/files/file.c +++ b/files/file.c @@ -51,8 +51,11 @@ #include "windef.h" #include "winbase.h" #include "wine/winbase16.h" +#include "wine/server.h" + #include "drive.h" #include "file.h" +#include "async.h" #include "heap.h" #include "msdos.h" #include "wincon.h" @@ -60,8 +63,6 @@ #include "smb.h" #include "wine/debug.h" -#include "wine/server.h" - WINE_DEFAULT_DEBUG_CHANNEL(file); #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) @@ -80,6 +81,61 @@ mode_t FILE_umask; extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name); +/*********************************************************************** + * Asynchronous file I/O * + */ +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); +} + /*********************************************************************** * FILE_ConvertOFMode * @@ -1344,30 +1400,6 @@ BOOL WINAPI GetOverlappedResult( 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 +1409,11 @@ BOOL WINAPI CancelIo(HANDLE handle) 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 +1427,19 @@ BOOL WINAPI CancelIo(HANDLE handle) */ 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 +1457,9 @@ static void FILE_AsyncReadService(async_private *ovp) } 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 +1476,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, 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 +1496,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, 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 +1504,19 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, 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 +1526,6 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, 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 +1603,6 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, } /* 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 +1660,19 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, */ 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 +1689,9 @@ static void FILE_AsyncWriteService(struct async_private *ovp) 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 +1708,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, 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 +1720,34 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, 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 +1757,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, 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 --git a/include/async.h b/include/async.h new file mode 100644 index 00000000000..26774d38dfb --- /dev/null +++ b/include/async.h @@ -0,0 +1,126 @@ +/* + * 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 + +#include "wine/server.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 --git a/include/file.h b/include/file.h index e061f4c2766..a986d4ecad7 100644 --- a/include/file.h +++ b/include/file.h @@ -46,27 +46,6 @@ typedef struct 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 @@ extern HANDLE FILE_CreateFile( LPCSTR filename, DWORD access, DWORD sharing, 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 --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 3d4e5a15c5c..5f778d3e2b6 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -502,7 +502,7 @@ struct get_apc_reply 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 register_async_request { struct request_header __header; handle_t handle; - void* func; int type; void* overlapped; int count; @@ -3184,6 +3183,6 @@ union generic_reply 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 --git a/scheduler/synchro.c b/scheduler/synchro.c index 4343c34e82c..41788dc6315 100644 --- a/scheduler/synchro.c +++ b/scheduler/synchro.c @@ -30,6 +30,7 @@ #include "thread.h" #include "winerror.h" #include "wine/server.h" +#include "async.h" /*********************************************************************** @@ -50,74 +51,32 @@ inline static void get_timeout( struct timeval *when, int timeout ) } } -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 = ovp->next) - if(ovp->lpOverlapped == overlapped) - break; + for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next ); 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 ); } @@ -201,6 +160,9 @@ static void call_apcs( BOOL alertable ) 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 ); break; diff --git a/server/async.c b/server/async.c index 5cbbcc59791..ad13eb47ab5 100644 --- a/server/async.c +++ b/server/async.c @@ -64,7 +64,7 @@ void async_notify(struct async *async, int status) { /* 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 @@ static void async_callback(void *private) 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 @@ struct async *create_async(struct object *obj, struct thread *thread, void *func async->obj = obj; async->thread = thread; - async->func = func; async->overlapped = overlapped; async->next = NULL; async->prev = NULL; @@ -165,7 +164,7 @@ DECL_HANDLER(register_async) 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 --git a/server/async.h b/server/async.h index ec752b5cb22..37b528f82f3 100644 --- a/server/async.h +++ b/server/async.h @@ -30,7 +30,6 @@ struct async { struct object *obj; struct thread *thread; - void *func; void *overlapped; unsigned int status; struct timeval when; @@ -51,7 +50,7 @@ void async_notify(struct async *async, int status); 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 --git a/server/protocol.def b/server/protocol.def index a13fcc7a8b7..ba96ea7f660 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -412,7 +412,7 @@ typedef struct 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 @@ enum message_type #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 --git a/server/thread.c b/server/thread.c index 7e019fabbd0..a43db32749d 100644 --- a/server/thread.c +++ b/server/thread.c @@ -959,8 +959,9 @@ DECL_HANDLER(get_apc) } /* 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 --git a/server/trace.c b/server/trace.c index cb2f19f03b3..00eb57d0d1c 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1846,7 +1846,6 @@ static void dump_set_serial_info_request( const struct set_serial_info_request * 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 );