Commit 2b47fb3c authored by Martin Wilck's avatar Martin Wilck Committed by Alexandre Julliard

- 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.
parent ce73456d
...@@ -80,6 +80,7 @@ ...@@ -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 @@ ...@@ -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( ...@@ -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( ...@@ -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,53 +1639,32 @@ static BOOL COMM_WaitCommEvent( ...@@ -1591,53 +1639,32 @@ 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;
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); lpOverlapped->InternalHigh = 0;
} lpOverlapped->Offset = 0;
SERVER_END_REQ; lpOverlapped->OffsetHigh = 0;
if (!ret) if ( !register_new_async (&ovp->async) )
SetLastError(ERROR_IO_PENDING); SetLastError( ERROR_IO_PENDING );
return FALSE; return FALSE;
} }
......
/*
* 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 */
...@@ -46,27 +46,6 @@ typedef struct ...@@ -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, ...@@ -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);
......
...@@ -502,7 +502,7 @@ struct get_apc_reply ...@@ -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 ...@@ -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 ...@@ -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 */
...@@ -30,6 +30,7 @@ ...@@ -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 ) ...@@ -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 ) ...@@ -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;
......
...@@ -64,7 +64,7 @@ void async_notify(struct async *async, int status) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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)
{ {
......
...@@ -30,7 +30,6 @@ struct async ...@@ -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); ...@@ -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)
{ {
......
...@@ -412,7 +412,7 @@ typedef struct ...@@ -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 ...@@ -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;
......
...@@ -959,8 +959,9 @@ DECL_HANDLER(get_apc) ...@@ -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]);
......
...@@ -1846,7 +1846,6 @@ static void dump_set_serial_info_request( const struct set_serial_info_request * ...@@ -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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment