[PATCH] async IO API, reworked
Martin Wilck
Martin.Wilck at fujitsu-siemens.com
Fri Apr 5 05:32:32 CST 2002
Hi,
Here is a reworked version of the async API patch which I hope is now
ready for being applied. Details see below.
Regards, Martin
PATCH: async-struct.diff
Purpose: Modified API for asynchronous IO requests.
- separate cleanly between async scheduling and file IO related issues,
- make the API compatible with other types of async requests (e.g. for sockets),
- remove exports of async IO related functions for DLL separation.
** This patch OBSOLETES these two patches I submitted: **
http://www.winehq.com/hypermail/wine-patches/2002/04/0020.html
http://www.winehq.com/hypermail/wine-patches/2002/04/0034.html
Note: the cancel_async server request that was in the previous patch
(0020.html) was removed (unnecessary).
Patch against: Wine CVS 2002/04/05
Test status: Compiles (no errors/warnings).
Tested regular file async IO with ReadFile and ReadFileEx (ok).
Added files:
include : async.h (structs and inline functions for async requests)
Modified files:
server : protocol.def (add APC type APC_ASYNC_IO,
remove func element of register_async request)
async.h (remove func element in async struct)
async.c (remove references to func element in async struct)
thread.c (allow NULL function pointer for APC_ASYNC_IO requests)
dlls/kernel : comm.c (use modified API)
files : file.c (use modified API)
include : file.h (move async stuff to async.h)
scheduler : synchro.c (remove functions now inlined through async.h,
call_apcs() calls check_async_list() for APC_ASYNC_IO APCs)
diff -ruNX ignore CVS/wine/dlls/kernel/comm.c TMP/wine/dlls/kernel/comm.c
--- CVS/wine/dlls/kernel/comm.c Wed Apr 3 19:32:56 2002
+++ TMP/wine/dlls/kernel/comm.c Fri Apr 5 11:19:40 2002
@@ -91,6 +91,53 @@
WINE_DEFAULT_DEBUG_CHANNEL(comm);
+/***********************************************************************
+ * Asynchronous I/O for asynchronous wait requests *
+ */
+#include "async.h"
+
+static DWORD commio_get_async_status (const async_private *ovp);
+static DWORD commio_get_async_count (const async_private *ovp);
+static void commio_set_async_status (async_private *ovp, const DWORD status);
+static void CALLBACK commio_call_completion_func (ULONG_PTR data);
+
+static async_ops commio_async_ops =
+{
+ commio_get_async_status, /* get_status */
+ commio_set_async_status, /* set_status */
+ commio_get_async_count, /* get_count */
+ commio_call_completion_func /* call_completion */
+};
+
+typedef struct async_commio
+{
+ struct async_private async;
+ LPOVERLAPPED lpOverlapped;
+ char *buffer;
+} async_commio;
+
+static DWORD commio_get_async_status (const struct async_private *ovp)
+{
+ return ((async_commio*) ovp)->lpOverlapped->Internal;
+}
+
+static void commio_set_async_status (async_private *ovp, const DWORD status)
+{
+ ((async_commio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD commio_get_async_count (const struct async_private *ovp)
+{
+ return 0;
+}
+
+static void CALLBACK commio_call_completion_func (ULONG_PTR data)
+{
+ HeapFree(GetProcessHeap(), 0, (void*) data);
+}
+
+/***********************************************************************/
+
#if !defined(TIOCINQ) && defined(FIONREAD)
#define TIOCINQ FIONREAD
#endif
@@ -1558,12 +1605,13 @@
*/
static void COMM_WaitCommEventService(async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_commio *commio = (async_commio*) ovp;
+ LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
TRACE("overlapped %p\n",lpOverlapped);
/* FIXME: detect other events */
- *ovp->buffer = EV_RXCHAR;
+ *commio->buffer = EV_RXCHAR;
lpOverlapped->Internal = STATUS_SUCCESS;
}
@@ -1579,8 +1627,8 @@
LPDWORD lpdwEvents, /* [out] event(s) that were detected */
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
{
- int fd,ret;
- async_private *ovp;
+ int fd;
+ async_commio *ovp;
if(!lpOverlapped)
{
@@ -1591,53 +1639,32 @@
if(NtResetEvent(lpOverlapped->hEvent,NULL))
return FALSE;
- lpOverlapped->Internal = STATUS_PENDING;
- lpOverlapped->InternalHigh = 0;
- lpOverlapped->Offset = 0;
- lpOverlapped->OffsetHigh = 0;
-
fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
if(fd<0)
return FALSE;
- ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
if(!ovp)
{
close(fd);
return FALSE;
}
- ovp->event = lpOverlapped->hEvent;
+
+ ovp->async.ops = &commio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = fd;
+ ovp->async.type = ASYNC_TYPE_WAIT;
+ ovp->async.func = COMM_WaitCommEventService;
+ ovp->async.event = lpOverlapped->hEvent;
ovp->lpOverlapped = lpOverlapped;
- ovp->func = COMM_WaitCommEventService;
ovp->buffer = (char *)lpdwEvents;
- ovp->fd = fd;
- ovp->count = 0;
/- ovp->completion_func = 0;
- ovp->type = ASYNC_TYPE_WAIT;
- ovp->handle = hFile;
-
- ovp->next = NtCurrentTeb()->pending_list;
- ovp->prev = NULL;
- if(ovp->next)
- ovp->next->prev=ovp;
- NtCurrentTeb()->pending_list = ovp;
-
- /* start an ASYNCHRONOUS WaitCommEvent */
- SERVER_START_REQ( register_async )
- {
- req->handle = hFile;
- req->overlapped = lpOverlapped;
- req->type = ASYNC_TYPE_WAIT;
- req->count = 0;
- req->func = check_async_list;
- req->status = STATUS_PENDING;
- ret=wine_server_call_err(req);
- }
- SERVER_END_REQ;
+ lpOverlapped->InternalHigh = 0;
+ lpOverlapped->Offset = 0;
+ lpOverlapped->OffsetHigh = 0;
- if (!ret)
- SetLastError(ERROR_IO_PENDING);
+ if ( !register_new_async (&ovp->async) )
+ SetLastError( ERROR_IO_PENDING );
return FALSE;
}
diff -ruNX ignore CVS/wine/files/file.c TMP/wine/files/file.c
--- CVS/wine/files/file.c Wed Apr 3 19:32:56 2002
+++ TMP/wine/files/file.c Fri Apr 5 12:15:58 2002
@@ -64,6 +64,65 @@
WINE_DEFAULT_DEBUG_CHANNEL(file);
+/***********************************************************************
+ * Asynchronous file I/O *
+ */
+#include "async.h"
+
+static DWORD fileio_get_async_status (const async_private *ovp);
+static DWORD fileio_get_async_count (const async_private *ovp);
+static void fileio_set_async_status (async_private *ovp, const DWORD status);
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
+
+static async_ops fileio_async_ops =
+{
+ fileio_get_async_status, /* get_status */
+ fileio_set_async_status, /* set_status */
+ fileio_get_async_count, /* get_count */
+ fileio_call_completion_func /* call_completion */
+};
+
+typedef struct async_fileio
+{
+ struct async_private async;
+ LPOVERLAPPED lpOverlapped;
+ LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
+ char *buffer;
+ int count;
+} async_fileio;
+
+static DWORD fileio_get_async_status (const struct async_private *ovp)
+{
+ return ((async_fileio*) ovp)->lpOverlapped->Internal;
+}
+
+static void fileio_set_async_status (async_private *ovp, const DWORD status)
+{
+ ((async_fileio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD fileio_get_async_count (const struct async_private *ovp)
+{
+ async_fileio *fileio = (async_fileio*) ovp;
+ DWORD ret = fileio->count - fileio->lpOverlapped->InternalHigh;
+ return (ret < 0 ? 0 : ret);
+}
+
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data)
+{
+ async_fileio *ovp = (async_fileio*) data;
+ TRACE ("data: %p\n", ovp);
+
+ if (ovp->completion_func)
+ ovp->completion_func(ovp->lpOverlapped->Internal,
+ ovp->lpOverlapped->InternalHigh,
+ ovp->lpOverlapped);
+
+ HeapFree(GetProcessHeap(), 0, ovp);
+}
+
+/***********************************************************************/
+
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
#define MAP_ANON MAP_ANONYMOUS
#endif
@@ -1344,30 +1403,6 @@
return (r==WAIT_OBJECT_0);
}
-
-/***********************************************************************
- * FILE_StartAsync (INTERNAL)
- *
- * type==ASYNC_TYPE_NONE means cancel the indicated overlapped operation
- * lpOverlapped==NULL means all overlappeds match
- */
-BOOL FILE_StartAsync(HANDLE hFile, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status)
-{
- BOOL ret;
w- SERVER_START_REQ(register_async)
- {
- req->handle = hFile;
- req->overlapped = lpOverlapped;
- req->type = type;
- req->count = count;
- req->func = check_async_list;
- req->status = status;
- ret = wine_server_call( req );
- }
- SERVER_END_REQ;
- return !ret;
-}
-
/***********************************************************************
* CancelIo (KERNEL32.@)
*/
@@ -1377,16 +1412,11 @@
TRACE("handle = %x\n",handle);
- ovp = NtCurrentTeb()->pending_list;
- while(ovp)
+ for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t)
{
t = ovp->next;
- if(FILE_StartAsync(handle, ovp->lpOverlapped, ovp->type, 0, STATUS_CANCELLED))
- {
- TRACE("overlapped = %p\n",ovp->lpOverlapped);
- finish_async(ovp, STATUS_CANCELLED);
- }
- ovp = t;
+ if ( ovp->handle == handle )
+ cancel_async ( ovp );
}
WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
return TRUE;
@@ -1400,18 +1430,19 @@
*/
static void FILE_AsyncReadService(async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_fileio *fileio = (async_fileio*) ovp;
+ LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
int result, r;
int already = lpOverlapped->InternalHigh;
- TRACE("%p %p\n", lpOverlapped, ovp->buffer );
+ TRACE("%p %p\n", lpOverlapped, fileio->buffer );
/* check to see if the data is ready (non-blocking) */
- result = pread (ovp->fd, &ovp->buffer[already], ovp->count - already,
+ result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already,
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
- result = read (ovp->fd, &ovp->buffer[already], ovp->count - already);
+ result = read (ovp->fd, &fileio->buffer[already], fileio->count - already);
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{
@@ -1429,9 +1460,9 @@
}
lpOverlapped->InternalHigh += result;
- TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+ TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
- if(lpOverlapped->InternalHigh < ovp->count)
+ if(lpOverlapped->InternalHigh < fileio->count)
r = STATUS_PENDING;
else
r = STATUS_SUCCESS;
@@ -1448,7 +1479,7 @@
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
HANDLE hEvent)
{
- async_private *ovp;
+ async_fileio *ovp;
int fd;
TRACE("file %d to buf %p num %ld %p func %p\n",
@@ -1468,7 +1499,7 @@
return FALSE;
}
- ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
{
TRACE("HeapAlloc Failed\n");
@@ -1476,31 +1507,19 @@
close(fd);
return FALSE;
}
- ovp->event = hEvent;
+
+ ovp->async.ops = &fileio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = fd;
+ ovp->async.type = ASYNC_TYPE_READ;
+ ovp->async.func = FILE_AsyncReadService;
+ ovp->async.event = hEvent;
ovp->lpOverlapped = overlapped;
ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine;
- ovp->func = FILE_AsyncReadService;
ovp->buffer = buffer;
- ovp->fd = fd;
- ovp->type = ASYNC_TYPE_READ;
- ovp->handle = hFile;
-
- /* hook this overlap into the pending async operation list */
- ovp->next = NtCurrentTeb()->pending_list;
- ovp->prev = NULL;
- if(ovp->next)
- ovp->next->prev = ovp;
- NtCurrentTeb()->pending_list = ovp;
- if ( !FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_READ, bytesToRead, STATUS_PENDING) )
- {
- /* FIXME: remove async_private and release memory */
- ERR("FILE_StartAsync failed\n");
- return FALSE;
- }
-
- return TRUE;
+ return !register_new_async (&ovp->async);
}
/***********************************************************************
@@ -1510,7 +1529,6 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0;
return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE);
}
@@ -1588,7 +1606,6 @@
}
/* at last resort, do an overlapped read */
- overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = result;
if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent))
@@ -1646,18 +1663,19 @@
*/
static void FILE_AsyncWriteService(struct async_private *ovp)
{
- LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+ async_fileio *fileio = (async_fileio *) ovp;
+ LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;
int result, r;
int already = lpOverlapped->InternalHigh;
- TRACE("(%p %p)\n",lpOverlapped,ovp->buffer);
+ TRACE("(%p %p)\n",lpOverlapped,fileio->buffer);
/* write some data (non-blocking) */
- result = pwrite(ovp->fd, &ovp->buffer[already], ovp->count - already,
+ result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already,
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
- result = write(ovp->fd, &ovp->buffer[already], ovp->count - already);
+ result = write(ovp->fd, &fileio->buffer[already], fileio->count - already);
if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR)))
{
@@ -1674,9 +1692,9 @@
lpOverlapped->InternalHigh += result;
- TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,ovp->count);
+ TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
- if(lpOverlapped->InternalHigh < ovp->count)
+ if(lpOverlapped->InternalHigh < fileio->count)
r = STATUS_PENDING;
else
r = STATUS_SUCCESS;
@@ -1693,7 +1711,8 @@
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
HANDLE hEvent)
{
- async_private *ovp;
+ async_fileio *ovp;
+ int fd;
TRACE("file %d to buf %p num %ld %p func %p stub\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1704,46 +1723,34 @@
return FALSE;
}
- overlapped->Internal = STATUS_PENDING;
- overlapped->InternalHigh = 0;
-
- if (!FILE_StartAsync(hFile, overlapped, ASYNC_TYPE_WRITE, bytesToWrite, STATUS_PENDING ))
+ fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+ if ( fd < 0 )
{
- TRACE("FILE_StartAsync failed\n");
+ TRACE( "Couldn't get FD\n" );
return FALSE;
}
- ovp = (async_private*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
+ ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
if(!ovp)
{
TRACE("HeapAlloc Failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ close (fd);
return FALSE;
}
+
+ ovp->async.ops = &fileio_async_ops;
+ ovp->async.handle = hFile;
+ ovp->async.fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+ ovp->async.type = ASYNC_TYPE_WRITE;
+ ovp->async.func = FILE_AsyncWriteService;
ovp->lpOverlapped = overlapped;
- ovp->event = hEvent;
- ovp->func = FILE_AsyncWriteService;
+ ovp->async.event = hEvent;
ovp->buffer = (LPVOID) buffer;
ovp->count = bytesToWrite;
ovp->completion_func = lpCompletionRoutine;
- ovp->fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
- ovp->type = ASYNC_TYPE_WRITE;
- ovp->handle = hFile;
- if(ovp->fd <0)
- {
- HeapFree(GetProcessHeap(), 0, ovp);
- return FALSE;
- }
-
- /* hook this overlap into the pending async operation list */
- ovp->next = NtCurrentTeb()->pending_list;
- ovp->prev = NULL;
- if(ovp->next)
- ovp->next->prev = ovp;
- NtCurrentTeb()->pending_list = ovp;
-
- return TRUE;
+ return !register_new_async (&ovp->async);
}
/***********************************************************************
@@ -1753,7 +1760,6 @@
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
- overlapped->Internal = STATUS_PENDING;
overlapped->InternalHigh = 0;
return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE);
diff -ruNX ignore CVS/wine/include/async.h TMP/wine/include/async.h
--- CVS/wine/include/async.h Thu Jan 1 01:00:00 1970
+++ TMP/wine/include/async.h Fri Apr 5 12:24:13 2002
@@ -0,0 +1,124 @@
+/*
+ * Structures and static functions for handling asynchronous I/O.
+ *
+ * Copyright (C) 2002 Mike McCormack, Martin Wilck
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This file declares static functions.
+ * It should only be included by those source files that implement async I/O requests.
+ */
+
+#ifndef __WINE_ASYNC_H
+#define __WINE_ASYNC_H
+
+struct async_private;
+
+typedef void (*async_handler)(struct async_private *ovp);
+typedef void CALLBACK (*async_call_completion_func)(ULONG_PTR data);
+typedef DWORD (*async_get_status)(const struct async_private *ovp);
+typedef DWORD (*async_get_count)(const struct async_private *ovp);
+typedef void (*async_set_status)(struct async_private *ovp, const DWORD status);
+
+typedef struct async_ops
+{
+ async_get_status get_status;
+ async_set_status set_status;
+ async_get_count get_count;
+ async_call_completion_func call_completion;
+} async_ops;
+
+typedef struct async_private
+{
+ struct async_ops *ops;
+ HANDLE handle;
+ HANDLE event;
+ int fd;
+ async_handler func;
+ int type;
+ struct async_private *next;
+ struct async_private *prev;
+} async_private;
+
+/* All functions declared static for Dll separation purposes */
+
+inline static void finish_async( async_private *ovp )
+{
+ if(ovp->prev)
+ ovp->prev->next = ovp->next;
+ else
+ NtCurrentTeb()->pending_list = ovp->next;
+
+ if(ovp->next)
+ ovp->next->prev = ovp->prev;
+
+ ovp->next = ovp->prev = NULL;
+
+ close( ovp->fd );
+ if( ovp->event != INVALID_HANDLE_VALUE )
+ NtSetEvent( ovp->event, NULL );
+
+ QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
+}
+
+inline static BOOL __register_async( async_private *ovp, const DWORD status )
+{
+ BOOL ret;
+
+ SERVER_START_REQ( register_async )
+ {
+ req->handle = ovp->handle;
+ req->overlapped = ovp;
+ req->type = ovp->type;
+ req->count = ovp->ops->get_count( ovp );
+ req->status = status;
+ ret = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+
+ if ( ret ) ovp->ops->set_status ( ovp, GetLastError() );
+ if ( ovp->ops->get_status (ovp) != STATUS_PENDING )
+ finish_async (ovp);
+
+ return ret;
+}
+
+#define register_old_async(ovp) \
+ __register_async (ovp, ovp->ops->get_status( ovp ));
+
+inline static BOOL register_new_async( async_private *ovp )
+{
+ ovp->ops->set_status ( ovp, STATUS_PENDING );
+
+ ovp->next = NtCurrentTeb()->pending_list;
+ ovp->prev = NULL;
+ if ( ovp->next ) ovp->next->prev = ovp;
+ NtCurrentTeb()->pending_list = ovp;
+
+ return __register_async( ovp, STATUS_PENDING );
+}
+
+inline static BOOL cancel_async ( async_private *ovp )
+{
+ /* avoid multiple cancellations */
+ if ( ovp->ops->get_status( ovp ) != STATUS_PENDING )
+ return 0;
+ ovp->ops->set_status ( ovp, STATUS_CANCELLED );
+ return __register_async ( ovp, STATUS_CANCELLED );
+}
+
+#endif /* __WINE_ASYNC_H */
diff -ruNX ignore CVS/wine/include/file.h TMP/wine/include/file.h
--- CVS/wine/include/file.h Wed Apr 3 19:32:56 2002
+++ TMP/wine/include/file.h Fri Apr 5 11:19:40 2002
@@ -46,27 +46,6 @@
int flags;
} DOS_DEVICE;
-/* overlapped private structure */
-struct async_private;
-typedef void (*async_handler)(struct async_private *ovp);
-typedef struct async_private
-{
- LPOVERLAPPED lpOverlapped;
- HANDLE handle;
- HANDLE event;
- int fd;
- char *buffer;
- async_handler func;
- int count;
- int type;
- LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
- struct async_private *next;
- struct async_private *prev;
-} async_private;
-
-extern void WINAPI check_async_list(LPOVERLAPPED ov, DWORD status);
-extern void finish_async(struct async_private *ovp, DWORD status);
-
/* locale-independent case conversion */
inline static char FILE_tolower( char c )
{
@@ -99,7 +78,6 @@
DWORD attributes, HANDLE template, BOOL fail_read_only,
UINT drive_type );
extern HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa );
-extern BOOL FILE_StartAsync(HANDLE handle, LPOVERLAPPED lpOverlapped, DWORD type, DWORD count, DWORD status);
extern LONG WINAPI WIN16_hread(HFILE16,SEGPTR,LONG);
diff -ruNX ignore CVS/wine/include/wine/server_protocol.h TMP/wine/include/wine/server_protocol.h
--- CVS/wine/include/wine/server_protocol.h Tue Apr 2 15:39:35 2002
+++ TMP/wine/include/wine/server_protocol.h Fri Apr 5 12:21:25 2002
@@ -502,7 +502,7 @@
int type;
/* VARARG(args,ptrs); */
};
-enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
+enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
@@ -2278,7 +2278,6 @@
{
struct request_header __header;
handle_t handle;
- void* func;
int type;
void* overlapped;
int count;
@@ -3184,6 +3183,6 @@
struct get_window_properties_reply get_window_properties_reply;
};
-#define SERVER_PROTOCOL_VERSION 77
+#define SERVER_PROTOCOL_VERSION 78
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff -ruNX ignore CVS/wine/scheduler/synchro.c TMP/wine/scheduler/synchro.c
--- CVS/wine/scheduler/synchro.c Wed Apr 3 19:32:56 2002
+++ TMP/wine/scheduler/synchro.c Fri Apr 5 12:35:35 2002
@@ -30,6 +30,7 @@
#include "thread.h"
#include "winerror.h"
#include "wine/server.h"
+#include "async.h"
/***********************************************************************
@@ -50,74 +51,32 @@
}
}
-static void CALLBACK call_completion_routine(ULONG_PTR data)
-{
- async_private* ovp = (async_private*)data;
-
- ovp->completion_func(ovp->lpOverlapped->Internal,
- ovp->lpOverlapped->InternalHigh,
- ovp->lpOverlapped);
- ovp->completion_func=NULL;
- HeapFree(GetProcessHeap(), 0, ovp);
-}
-
-void finish_async(async_private *ovp, DWORD status)
-{
- ovp->lpOverlapped->Internal=status;
-
- /* call ReadFileEx/WriteFileEx's overlapped completion function */
- if(ovp->completion_func)
- {
- QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp);
- }
-
- /* remove it from the active list */
- if(ovp->prev)
- ovp->prev->next = ovp->next;
- else
- NtCurrentTeb()->pending_list = ovp->next;
-
- if(ovp->next)
- ovp->next->prev = ovp->prev;
-
- ovp->next=NULL;
- ovp->prev=NULL;
-
- close(ovp->fd);
- if(ovp->event!=INVALID_HANDLE_VALUE)
- NtSetEvent(ovp->event,NULL);
- if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp);
-}
-
/***********************************************************************
* check_async_list
*
* Process a status event from the server.
*/
-void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status)
+static void WINAPI check_async_list(async_private *asp, DWORD status)
{
async_private *ovp;
+ DWORD ovp_status;
- /* fprintf(stderr,"overlapped %p status %x\n",overlapped,status); */
+ for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
- for(ovp = NtCurrentTeb()->pending_list; ovp; ovp = ovp->next)
- if(ovp->lpOverlapped == overlapped)
- break;
-
- if(!ovp)
+ if(!ovp)
return;
- if(status != STATUS_ALERTED)
- ovp->lpOverlapped->Internal = status;
+ if( status != STATUS_ALERTED )
+ {
+ ovp_status = status;
+ ovp->ops->set_status (ovp, status);
+ }
+ else ovp_status = ovp->ops->get_status (ovp);
- if(ovp->lpOverlapped->Internal==STATUS_PENDING)
- {
- ovp->func(ovp);
- FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
- }
+ if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
- if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
- finish_async(ovp,ovp->lpOverlapped->Internal);
+ /* This will destroy all but PENDING requests */
+ register_old_async( ovp );
}
@@ -200,6 +159,9 @@
/* convert sec/usec to NT time */
DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
+ break;
+ case APC_ASYNC_IO:
+ check_async_list ( args[0], (DWORD) args[1]);
break;
default:
server_protocol_error( "get_apc_request: bad type %d\n", type );
diff -ruNX ignore CVS/wine/server/async.c TMP/wine/server/async.c
--- CVS/wine/server/async.c Wed Apr 3 19:32:56 2002
+++ TMP/wine/server/async.c Fri Apr 5 12:22:32 2002
@@ -64,7 +64,7 @@
{
/* fprintf(stderr,"notifying %p!\n",async->overlapped); */
async->status = status;
- thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status);
+ thread_queue_apc(async->thread, NULL, NULL, APC_ASYNC_IO, 1, 2, async->overlapped, status);
}
void destroy_async_queue( struct async_queue *q )
@@ -116,7 +116,7 @@
destroy_async(async);
}
-struct async *create_async(struct object *obj, struct thread *thread, void *func,
+struct async *create_async(struct object *obj, struct thread *thread,
void *overlapped)
{
struct async *async = (struct async *) malloc(sizeof(struct async));
@@ -128,7 +128,6 @@
async->obj = obj;
async->thread = thread;
- async->func = func;
async->overlapped = overlapped;
async->next = NULL;
async->prev = NULL;
@@ -165,7 +164,7 @@
if(req->status==STATUS_PENDING)
{
if(!async)
- async = create_async(obj, current, req->func, req->overlapped);
+ async = create_async(obj, current, req->overlapped);
if(async)
{
diff -ruNX ignore CVS/wine/server/async.h TMP/wine/server/async.h
--- CVS/wine/server/async.h Tue Apr 2 15:39:41 2002
+++ TMP/wine/server/async.h Fri Apr 5 11:19:45 2002
@@ -30,7 +30,6 @@
{
struct object *obj;
struct thread *thread;
- void *func;
void *overlapped;
unsigned int status;
struct timeval when;
@@ -51,7 +50,7 @@
struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped);
void async_insert(struct async_queue *q, struct async *async);
struct async *create_async(struct object *obj, struct thread *thread,
- void *func, void *overlapped);
+ void *overlapped);
void async_add_timeout(struct async *async, int timeout);
static inline void init_async_queue(struct async_queue *q)
{
diff -ruNX ignore CVS/wine/server/protocol.def TMP/wine/server/protocol.def
--- CVS/wine/server/protocol.def Wed Apr 3 19:32:56 2002
+++ TMP/wine/server/protocol.def Fri Apr 5 12:17:37 2002
@@ -412,7 +412,7 @@
int type; /* function type */
VARARG(args,ptrs); /* function arguments */
@END
-enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC };
+enum apc_type { APC_NONE, APC_USER, APC_TIMER, APC_ASYNC, APC_ASYNC_IO };
/* Close a handle for the current process */
@@ -1615,10 +1615,9 @@
#define SERIALINFO_SET_ERROR 0x04
-/* Create/Destroy an async I/O */
+/* Create / reschedule an async I/O */
@REQ(register_async)
handle_t handle; /* handle to comm port, socket or file */
- void* func;
int type;
void* overlapped;
int count;
diff -ruNX ignore CVS/wine/server/thread.c TMP/wine/server/thread.c
--- CVS/wine/server/thread.c Tue Apr 2 15:39:42 2002
+++ TMP/wine/server/thread.c Fri Apr 5 11:19:45 2002
@@ -959,8 +959,9 @@
}
/* Optimization: ignore APCs that have a NULL func; they are only used
* to wake up a thread, but since we got here the thread woke up already.
+ * Exception: for APC_ASYNC_IO, func == NULL is legal.
*/
- if (apc->func) break;
+ if (apc->func || apc->type == APC_ASYNC_IO) break;
free( apc );
}
size = apc->nb_args * sizeof(apc->args[0]);
diff -ruNX ignore CVS/wine/server/trace.c TMP/wine/server/trace.c
--- CVS/wine/server/trace.c Wed Apr 3 19:32:56 2002
+++ TMP/wine/server/trace.c Fri Apr 5 12:21:25 2002
@@ -1846,7 +1846,6 @@
static void dump_register_async_request( const struct register_async_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
- fprintf( stderr, " func=%p,", req->func );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " overlapped=%p,", req->overlapped );
fprintf( stderr, " count=%d,", req->count );
More information about the wine-patches
mailing list