From 08867f7149f82446f8df9e3ebfa85563db5adbf2 Mon Sep 17 00:00:00 2001
From: Martin Wilck <Martin.Wilck@fujitsu-siemens.com>
Date: Sun, 14 Apr 2002 19:34:57 +0000
Subject: [PATCH] - 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).

---
 dlls/kernel/comm.c |  9 ++++----
 files/file.c       | 57 ++++++++++++++++++++++++++++++++++------------
 include/async.h    | 13 +++++++++--
 3 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index 53da53cf95f..ac477e93403 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -99,14 +99,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(comm);
 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 @@ static DWORD commio_get_async_count (const struct async_private *ovp)
     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 --git a/files/file.c b/files/file.c
index d698bf676cb..582ef8f39f8 100644
--- a/files/file.c
+++ b/files/file.c
@@ -88,13 +88,24 @@ 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 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 @@ 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);
+    ovp->completion_func( ovp->lpOverlapped->Internal,
+                          ovp->lpOverlapped->InternalHigh,
+                          ovp->lpOverlapped );
 
-    HeapFree(GetProcessHeap(), 0, ovp);
+    fileio_async_cleanup ( &ovp->async );
+}
+
+static void fileio_async_cleanup ( struct async_private *ovp )
+{
+    HeapFree ( GetProcessHeap(), 0, ovp );
 }
 
 /***********************************************************************
@@ -1478,6 +1493,8 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
 {
     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);
@@ -1489,10 +1506,11 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
         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;
     }
 
@@ -1501,11 +1519,10 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
     {
         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;
@@ -1517,6 +1534,11 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
     ovp->buffer = buffer;
 
     return !register_new_async (&ovp->async);
+
+error:
+    close (fd);
+    return FALSE;
+
 }
 
 /***********************************************************************
@@ -1710,6 +1732,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
 {
     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);
@@ -1720,7 +1744,7 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
         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" );
@@ -1732,8 +1756,7 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
     {
         TRACE("HeapAlloc Failed\n");
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        close (fd);
-        return FALSE;
+        goto error;
     }
 
     ovp->async.ops = &fileio_async_ops;
@@ -1748,6 +1771,10 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
     ovp->completion_func = lpCompletionRoutine;
 
     return !register_new_async (&ovp->async);
+
+error:
+    close (fd);
+    return FALSE;
 }
 
 /***********************************************************************
diff --git a/include/async.h b/include/async.h
index 26774d38dfb..6b6359a41a8 100644
--- a/include/async.h
+++ b/include/async.h
@@ -35,6 +35,7 @@ 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 void (*async_cleanup)(struct async_private *ovp);
 
 typedef struct async_ops
 {
@@ -42,6 +43,7 @@ typedef struct async_ops
     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 @@ inline static void finish_async( async_private *ovp )
     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 @@ inline static BOOL __register_async( async_private *ovp, const DWORD status )
     }
     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);
 
-- 
GitLab