- 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 commit is contained in:
Martin Wilck 2002-04-05 22:53:57 +00:00 committed by Alexandre Julliard
parent ce73456d80
commit 2b47fb3cee
11 changed files with 317 additions and 225 deletions

View File

@ -80,6 +80,7 @@
#include "winerror.h" #include "winerror.h"
#include "wine/server.h" #include "wine/server.h"
#include "async.h"
#include "file.h" #include "file.h"
#include "heap.h" #include "heap.h"
@ -91,6 +92,52 @@
WINE_DEFAULT_DEBUG_CHANNEL(comm); 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) #if !defined(TIOCINQ) && defined(FIONREAD)
#define TIOCINQ FIONREAD #define TIOCINQ FIONREAD
#endif #endif
@ -1558,12 +1605,13 @@ BOOL WINAPI GetCommModemStatus(
*/ */
static void COMM_WaitCommEventService(async_private *ovp) 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); TRACE("overlapped %p\n",lpOverlapped);
/* FIXME: detect other events */ /* FIXME: detect other events */
*ovp->buffer = EV_RXCHAR; *commio->buffer = EV_RXCHAR;
lpOverlapped->Internal = STATUS_SUCCESS; lpOverlapped->Internal = STATUS_SUCCESS;
} }
@ -1579,8 +1627,8 @@ static BOOL COMM_WaitCommEvent(
LPDWORD lpdwEvents, /* [out] event(s) that were detected */ LPDWORD lpdwEvents, /* [out] event(s) that were detected */
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */ LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
{ {
int fd,ret; int fd;
async_private *ovp; async_commio *ovp;
if(!lpOverlapped) if(!lpOverlapped)
{ {
@ -1591,52 +1639,31 @@ static BOOL COMM_WaitCommEvent(
if(NtResetEvent(lpOverlapped->hEvent,NULL)) if(NtResetEvent(lpOverlapped->hEvent,NULL))
return FALSE; return FALSE;
lpOverlapped->Internal = STATUS_PENDING;
lpOverlapped->InternalHigh = 0;
lpOverlapped->Offset = 0;
lpOverlapped->OffsetHigh = 0;
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE ); fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
if(fd<0) if(fd<0)
return FALSE; return FALSE;
ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
if(!ovp) if(!ovp)
{ {
close(fd); close(fd);
return FALSE; 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->lpOverlapped = lpOverlapped;
ovp->func = COMM_WaitCommEventService;
ovp->buffer = (char *)lpdwEvents; 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; lpOverlapped->InternalHigh = 0;
ovp->prev = NULL; lpOverlapped->Offset = 0;
if(ovp->next) lpOverlapped->OffsetHigh = 0;
ovp->next->prev=ovp;
NtCurrentTeb()->pending_list = ovp;
/* start an ASYNCHRONOUS WaitCommEvent */ if ( !register_new_async (&ovp->async) )
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;
if (!ret)
SetLastError( ERROR_IO_PENDING ); SetLastError( ERROR_IO_PENDING );
return FALSE; return FALSE;

View File

@ -51,8 +51,11 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "wine/winbase16.h" #include "wine/winbase16.h"
#include "wine/server.h"
#include "drive.h" #include "drive.h"
#include "file.h" #include "file.h"
#include "async.h"
#include "heap.h" #include "heap.h"
#include "msdos.h" #include "msdos.h"
#include "wincon.h" #include "wincon.h"
@ -60,8 +63,6 @@
#include "smb.h" #include "smb.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/server.h"
WINE_DEFAULT_DEBUG_CHANNEL(file); WINE_DEFAULT_DEBUG_CHANNEL(file);
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) #if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
@ -80,6 +81,61 @@ mode_t FILE_umask;
extern WINAPI HANDLE FILE_SmbOpen(LPCSTR name); 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 * FILE_ConvertOFMode
* *
@ -1344,30 +1400,6 @@ BOOL WINAPI GetOverlappedResult(
return (r==WAIT_OBJECT_0); 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.@) * CancelIo (KERNEL32.@)
*/ */
@ -1377,16 +1409,11 @@ BOOL WINAPI CancelIo(HANDLE handle)
TRACE("handle = %x\n",handle); TRACE("handle = %x\n",handle);
ovp = NtCurrentTeb()->pending_list; for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
while(ovp)
{ {
t = ovp->next; t = ovp->next;
if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED)) if ( ovp->handle == handle )
{ cancel_async ( ovp );
TRACE("overlapped = %p\n",ovp->lpOverlapped);
finish_async(ovp, STATUS_CANCELLED);
}
ovp = t;
} }
WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE); WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
return TRUE; return TRUE;
@ -1400,18 +1427,19 @@ BOOL WINAPI CancelIo(HANDLE handle)
*/ */
static void FILE_AsyncReadService(async_private *ovp) 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 result, r;
int already = lpOverlapped->InternalHigh; 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) */ /* 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); OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE)) 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))) if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{ {
@ -1429,9 +1457,9 @@ static void FILE_AsyncReadService(async_private *ovp)
} }
lpOverlapped->InternalHigh += result; 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; r = STATUS_PENDING;
else else
r = STATUS_SUCCESS; r = STATUS_SUCCESS;
@ -1448,7 +1476,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
HANDLE hEvent) HANDLE hEvent)
{ {
async_private *ovp; async_fileio *ovp;
int fd; int fd;
TRACE("file %d to buf %p num %ld %p func %p\n", 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; return FALSE;
} }
ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp) if(!ovp)
{ {
TRACE("HeapAlloc Failed\n"); TRACE("HeapAlloc Failed\n");
@ -1476,31 +1504,19 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
close(fd); close(fd);
return FALSE; 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->lpOverlapped = overlapped;
ovp->count = bytesToRead; ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->func = FILE_AsyncReadService;
ovp->buffer = buffer; ovp->buffer = buffer;
ovp->fd = fd;
ovp->type = ASYNC_TYPE_READ;
ovp->handle = hFile;
/* hook this overlap into the pending async operation list */ return !register_new_async (&ovp->async);
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;
} }
/*********************************************************************** /***********************************************************************
@ -1510,7 +1526,6 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
LPOVERLAPPED overlapped, LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0; overlapped->InternalHigh = 0;
return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE); 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 */ /* at last resort, do an overlapped read */
overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = result; overlapped->InternalHigh = result;
if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent)) 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) 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 result, r;
int already = lpOverlapped->InternalHigh; int already = lpOverlapped->InternalHigh;
TRACE("(%p %p)\n",lpOverlapped,ovp->buffer); TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
/* write some data (non-blocking) */ /* 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); OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE)) 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))) if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{ {
@ -1674,9 +1689,9 @@ static void FILE_AsyncWriteService(struct async_private *ovp)
lpOverlapped->InternalHigh += result; 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; r = STATUS_PENDING;
else else
r = STATUS_SUCCESS; r = STATUS_SUCCESS;
@ -1693,7 +1708,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
HANDLE hEvent) HANDLE hEvent)
{ {
async_private *ovp; async_fileio *ovp;
int fd;
TRACE("file %d to buf %p num %ld %p func %p stub\n", TRACE("file %d to buf %p num %ld %p func %p stub\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@ -1704,46 +1720,34 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
return FALSE; return FALSE;
} }
overlapped->Internal = STATUS_PENDING; fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
overlapped->InternalHigh = 0; if ( fd < 0 )
if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
{ {
TRACE("FILE_StartAsync failed\n"); TRACE( "Couldn't get FD\n" );
return FALSE; return FALSE;
} }
ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private)); ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp) if(!ovp)
{ {
TRACE("HeapAlloc Failed\n"); TRACE("HeapAlloc Failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
close (fd);
return FALSE; 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->lpOverlapped = overlapped;
ovp->event = hEvent; ovp->async.event = hEvent;
ovp->func = FILE_AsyncWriteService;
ovp->buffer = (LPVOID) buffer; ovp->buffer = (LPVOID) buffer;
ovp->count = bytesToWrite; ovp->count = bytesToWrite;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
ovp->type = ASYNC_TYPE_WRITE;
ovp->handle = hFile;
if(ovp->fd <0) return !register_new_async (&ovp->async);
{
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;
} }
/*********************************************************************** /***********************************************************************
@ -1753,7 +1757,6 @@ BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
LPOVERLAPPED overlapped, LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{ {
overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0; overlapped->InternalHigh = 0;
return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE); return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);

126
include/async.h Normal file
View File

@ -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 */

View File

@ -46,27 +46,6 @@ typedef struct
int flags; int flags;
} DOS_DEVICE; } 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 */ /* locale-independent case conversion */
inline static char FILE_tolower( char c ) 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, DWORD attributes, HANDLE template, BOOL fail_read_only,
UINT drive_type ); UINT drive_type );
extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa ); 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); extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);

View File

@ -502,7 +502,7 @@ struct get_apc_reply
int type; int type;
/* VARARG(args,ptrs); */ /* 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; struct request_header __header;
handle_t handle; handle_t handle;
void* func;
int type; int type;
void* overlapped; void* overlapped;
int count; int count;
@ -3184,6 +3183,6 @@ union generic_reply
struct get_window_properties_reply get_window_properties_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 */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -30,6 +30,7 @@
#include "thread.h" #include "thread.h"
#include "winerror.h" #include "winerror.h"
#include "wine/server.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 * check_async_list
* *
* Process a status event from the server. * 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; 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; return;
if( status != STATUS_ALERTED ) if( status != STATUS_ALERTED )
ovp->lpOverlapped->Internal = status;
if(ovp->lpOverlapped->Internal==STATUS_PENDING)
{ {
ovp->func(ovp); ovp_status = status;
FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal); ovp->ops->set_status (ovp, status);
} }
else ovp_status = ovp->ops->get_status (ovp);
if(ovp->lpOverlapped->Internal!=STATUS_PENDING) if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
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 ); DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime ); proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
break; break;
case APC_ASYNC_IO:
check_async_list ( args[0], (DWORD) args[1]);
break;
default: default:
server_protocol_error( "get_apc_request: bad type %d\n", type ); server_protocol_error( "get_apc_request: bad type %d\n", type );
break; break;

View File

@ -64,7 +64,7 @@ void async_notify(struct async *async, int status)
{ {
/* fprintf(stderr,"notifying %p!\n",async->overlapped); */ /* fprintf(stderr,"notifying %p!\n",async->overlapped); */
async->status = status; 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 ) void destroy_async_queue( struct async_queue *q )
@ -116,7 +116,7 @@ static void async_callback(void *private)
destroy_async(async); 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) void *overlapped)
{ {
struct async *async = (struct async *) malloc(sizeof(struct async)); 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->obj = obj;
async->thread = thread; async->thread = thread;
async->func = func;
async->overlapped = overlapped; async->overlapped = overlapped;
async->next = NULL; async->next = NULL;
async->prev = NULL; async->prev = NULL;
@ -165,7 +164,7 @@ DECL_HANDLER(register_async)
if(req->status==STATUS_PENDING) if(req->status==STATUS_PENDING)
{ {
if(!async) if(!async)
async = create_async(obj, current, req->func, req->overlapped); async = create_async(obj, current, req->overlapped);
if(async) if(async)
{ {

View File

@ -30,7 +30,6 @@ struct async
{ {
struct object *obj; struct object *obj;
struct thread *thread; struct thread *thread;
void *func;
void *overlapped; void *overlapped;
unsigned int status; unsigned int status;
struct timeval when; 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); struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped);
void async_insert(struct async_queue *q, struct async *async); void async_insert(struct async_queue *q, struct async *async);
struct async *create_async(struct object *obj, struct thread *thread, 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); void async_add_timeout(struct async *async, int timeout);
static inline void init_async_queue(struct async_queue *q) static inline void init_async_queue(struct async_queue *q)
{ {

View File

@ -412,7 +412,7 @@ typedef struct
int type; /* function type */ int type; /* function type */
VARARG(args,ptrs); /* function arguments */ VARARG(args,ptrs); /* function arguments */
@END @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 */ /* Close a handle for the current process */
@ -1615,10 +1615,9 @@ enum message_type
#define SERIALINFO_SET_ERROR 0x04 #define SERIALINFO_SET_ERROR 0x04
/* Create/Destroy an async I/O */ /* Create / reschedule an async I/O */
@REQ(register_async) @REQ(register_async)
handle_t handle; /* handle to comm port, socket or file */ handle_t handle; /* handle to comm port, socket or file */
void* func;
int type; int type;
void* overlapped; void* overlapped;
int count; int count;

View File

@ -959,8 +959,9 @@ DECL_HANDLER(get_apc)
} }
/* Optimization: ignore APCs that have a NULL func; they are only used /* 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. * 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 ); free( apc );
} }
size = apc->nb_args * sizeof(apc->args[0]); size = apc->nb_args * sizeof(apc->args[0]);

View File

@ -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 ) static void dump_register_async_request( const struct register_async_request *req )
{ {
fprintf( stderr, " handle=%d,", req->handle ); fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " func=%p,", req->func );
fprintf( stderr, " type=%d,", req->type ); fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " overlapped=%p,", req->overlapped ); fprintf( stderr, " overlapped=%p,", req->overlapped );
fprintf( stderr, " count=%d,", req->count ); fprintf( stderr, " count=%d,", req->count );