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 @@
#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;
if (!ret)
SetLastError(ERROR_IO_PENDING);
lpOverlapped->InternalHigh = 0;
lpOverlapped->Offset = 0;
lpOverlapped->OffsetHigh = 0;
if ( !register_new_async (&ovp->async) )
SetLastError( ERROR_IO_PENDING );
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
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);
......
......@@ -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 */
......@@ -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;
......
......@@ -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)
{
......
......@@ -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)
{
......
......@@ -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;
......
......@@ -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]);
......
......@@ -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 );
......
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