Patch: async-file.diff
Some improvements to the async IO API.
- Need a "cleanup" method.
- calling the "call_completion" method unconditionally in finish_async
(introduced by me) was wrong, because the thread may never be in an
alertable wait state -> call it only if user completion function is present.
- We need two constant "ops" objects, one with and one without call_completion
method (the event field may NOT be used to determine whether the completion
must be called or not).
- STATUS_CANCELLED is correct for cancelled requests
( corresponds to ERROR_OPERATION_ABORTED ).
Modified files:
dlls/kernel: comm.c
files: file.c
include: async.h
server: async.c
diff -ruNX ignore TMP/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c
--- TMP/wine/dlls/kernel/comm.c Fri Apr 12 11:47:48 2002
+++ MW/wine/dlls/kernel/comm.c Fri Apr 12 12:27:07 2002
@@ -99,14 +99,15 @@
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 void commio_async_cleanup (async_private *ovp);
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 */
+ NULL, /* call_completion */
+ commio_async_cleanup /* cleanup */
};
typedef struct async_commio
@@ -131,9 +132,9 @@
return 0;
}
-static void CALLBACK commio_call_completion_func (ULONG_PTR data)
+static void commio_async_cleanup (async_private *ovp)
{
- HeapFree(GetProcessHeap(), 0, (void*) data);
+ HeapFree(GetProcessHeap(), 0, ovp );
}
/***********************************************************************/
diff -ruNX ignore TMP/wine/files/file.c MW/wine/files/file.c
--- TMP/wine/files/file.c Fri Apr 12 11:59:51 2002
+++ MW/wine/files/file.c Fri Apr 12 12:28:22 2002
@@ -88,13 +88,24 @@
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 void fileio_async_cleanup (async_private *ovp);
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 */
+ fileio_call_completion_func, /* call_completion */
+ fileio_async_cleanup /* cleanup */
+};
+
+static async_ops fileio_nocomp_async_ops =
+{
+ fileio_get_async_status, /* get_status */
+ fileio_set_async_status, /* set_status */
+ fileio_get_async_count, /* get_count */
+ NULL, /* call_completion */
+ fileio_async_cleanup /* cleanup */
};
typedef struct async_fileio
@@ -128,12 +139,16 @@
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);
+ ovp->completion_func( ovp->lpOverlapped->Internal,
+ ovp->lpOverlapped->InternalHigh,
+ ovp->lpOverlapped );
+
+ fileio_async_cleanup ( &ovp->async );
+}
- HeapFree(GetProcessHeap(), 0, ovp);
+static void fileio_async_cleanup ( struct async_private *ovp )
+{
+ HeapFree ( GetProcessHeap(), 0, ovp );
}
/***********************************************************************
@@ -1479,6 +1494,8 @@
{
async_fileio *ovp;
int fd;
+ int flags;
+ enum fd_type type;
TRACE("file %d to buf %p num %ld %p func %p\n",
hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine);
@@ -1490,10 +1507,11 @@
return FALSE;
}
- fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
- if(fd<0)
+ fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags);
+ if ( fd < 0 )
{
- TRACE("Couldn't get FD\n");
+ WARN ( "Couldn't get FD\n" );
+ SetLastError ( ERROR_INVALID_PARAMETER );
return FALSE;
}
@@ -1502,11 +1520,10 @@
{
TRACE("HeapAlloc Failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- close(fd);
- return FALSE;
+ goto error;
}
- ovp->async.ops = &fileio_async_ops;
+ ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops );
ovp->async.handle = hFile;
ovp->async.fd = fd;
ovp->async.type = ASYNC_TYPE_READ;
@@ -1518,6 +1535,11 @@
ovp->buffer = buffer;
return !register_new_async (&ovp->async);
+
+error:
+ close (fd);
+ return FALSE;
+
}
/***********************************************************************
@@ -1691,6 +1713,8 @@
{
async_fileio *ovp;
int fd;
+ int flags;
+ enum fd_type type;
TRACE("file %d to buf %p num %ld %p func %p stub\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1701,7 +1725,7 @@
return FALSE;
}
- fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
+ fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags );
if ( fd < 0 )
{
TRACE( "Couldn't get FD\n" );
@@ -1713,8 +1737,7 @@
{
TRACE("HeapAlloc Failed\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- close (fd);
- return FALSE;
+ goto error;
}
ovp->async.ops = &fileio_async_ops;
@@ -1729,6 +1752,10 @@
ovp->completion_func = lpCompletionRoutine;
return !register_new_async (&ovp->async);
+
+error:
+ close (fd);
+ return FALSE;
}
/***********************************************************************
diff -ruNX ignore TMP/wine/include/async.h MW/wine/include/async.h
--- TMP/wine/include/async.h Fri Apr 12 11:47:48 2002
+++ MW/wine/include/async.h Fri Apr 12 12:25:30 2002
@@ -35,6 +35,7 @@
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 void (*async_cleanup)(struct async_private *ovp);
typedef struct async_ops
{
@@ -42,6 +43,7 @@
async_set_status set_status;
async_get_count get_count;
async_call_completion_func call_completion;
+ async_cleanup cleanup;
} async_ops;
typedef struct async_private
@@ -74,7 +76,10 @@
if( ovp->event != INVALID_HANDLE_VALUE )
NtSetEvent( ovp->event, NULL );
- QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
+ if ( ovp->ops->call_completion )
+ QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
+ else
+ ovp->ops->cleanup ( ovp );
}
inline static BOOL __register_async( async_private *ovp, const DWORD status )
@@ -92,7 +97,11 @@
}
SERVER_END_REQ;
- if ( ret ) ovp->ops->set_status ( ovp, GetLastError() );
+ if ( ret ) {
+ SetLastError( RtlNtStatusToDosError(ret) );
+ ovp->ops->set_status ( ovp, ret );
+ }
+
if ( ovp->ops->get_status (ovp) != STATUS_PENDING )
finish_async (ovp);
diff -ruNX ignore TMP/wine/server/async.c MW/wine/server/async.c
--- TMP/wine/server/async.c Fri Apr 12 11:47:48 2002
+++ MW/wine/server/async.c Fri Apr 12 12:23:56 2002
@@ -71,7 +71,7 @@
{
while(q->head)
{
- async_notify(q->head, STATUS_HANDLES_CLOSED);
+ async_notify(q->head, STATUS_CANCELLED);
destroy_async(q->head);
}
}