async_private + ReadFile() etc. immediate completion

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Thu Jan 10 15:40:54 CST 2002


Hi,

The patch below is a reworked version of the one posted yesterday
to wine-devel.

I received only one rather positive comment from Mike, so I assume
everybody is d'accord :-)

The patch is still long but actually adds only 50 lines. I find it very
hard to split it into seperate smaller ones.

There were a few bugs, but now the patch runs fine with my regular file
IO test code. The code tests ReadFileEx() (always asynchronous)
ReadFile() (synchronous if possible, i.e. always synchronous on regular
files), and CancelIo().

In particular, the GetOverlappedResult() call in ReadFile() seems to work
as expected.

I cannot test the serial comm code and must kindly ask somebody else
to try that.

Martin

-- 
Martin Wilck                Phone: +49 5251 8 15113
Fujitsu Siemens Computers   Fax:   +49 5251 8 20409
Heinz-Nixdorf-Ring 1	    mailto:Martin.Wilck at Fujitsu-Siemens.com
D-33106 Paderborn           http://www.fujitsu-siemens.com/primergy


ChangeLog:

server/protocol.def:
        cancel_async(): Define new reqest type.

server/async.c:
        cancel_async(): Implement new reqest type.

include/file.h:
        struct async_ops: 4 methods for async_private: get_status, set_status,
                get_count, call_completion.
        struct async_private: contains only those elements which are absolutely
                necessary for queueing and server interaction
        struct async_fileio: contains all other fields.

scheduler/synchro.c:
        register_async(): replacement for FILE_StartAsync(). Uses STATUS_USER_APC as (pseudo-) indicator
                to queue a new request. Hooks new requests in NtCurrentTeb()->pending_list (formerly done
                in calling functions). Not used by CancelIo() anymore. Finishes requests that are not in
                PENDING state after scheduling.
        finish_async(): Assume status is already set correctly. Queue call_completion unconditionally
                (No completion_func check needed)
        check_async(): Use register_async() for rescheduling.

files/file.c:
        GetOverlappedResult(): Return ERROR_IO_INCOMPLETE if IO still pending (MSDN docs)
        FILE_StartAsync(): -> scheduler/synchro.c: register_async
        CancelIo(): Use new cancel_async server request (I felt former StartAsync() was too overloaded).
                Skip requests with wrong handle.
        fileio_call_completion_func(): Now called unconditionally, check if completion_func is non-NULL.
        FILE_AsyncReadService(): type adjustments according to new API
        FILE_AsyncWriteService(): dito
        FILE_ReadFileEx(): use new async API.
                Call GetOverlappedResult() to check for immediate completion.
        FILE_WriteFileEx(): dito. Made exactly equivalent to FILE_ReadFileEx()

kernel/comm.c:
        COMM_WaitCommEventService(): Use new async API.

diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c
--- CVS/wine/dlls/kernel/comm.c	Tue Jan  8 18:53:41 2002
+++ MW/wine/dlls/kernel/comm.c	Thu Jan 10 13:24:54 2002
@@ -1514,12 +1514,13 @@
  */
 static void COMM_WaitCommEventService(async_private *ovp)
 {
-    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    async_fileio *fileio = (async_fileio*) ovp;
+    LPOVERLAPPED lpOverlapped = fileio->lpOverlapped;

     TRACE("overlapped %p\n",lpOverlapped);

     /* FIXME: detect other events */
-            *ovp->buffer = EV_RXCHAR;
+    *fileio->buffer = EV_RXCHAR;

     lpOverlapped->Internal = STATUS_SUCCESS;
 }
@@ -1536,7 +1537,7 @@
     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
 {
     int fd,ret;
-    async_private *ovp;
+    async_fileio *ovp;

     if(!lpOverlapped)
     {
@@ -1547,52 +1548,34 @@
     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_fileio *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio));
     if(!ovp)
     {
         close(fd);
         return FALSE;
     }
+
+    ovp->async.ops = &fileio_async_ops;
+    ovp->async.handle = hFile;
+    ovp->async.fd = fd;
+    ovp->async.type = ASYNC_TYPE_WAIT;
+    ovp->async.func = COMM_WaitCommEventService;
     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->Internal = STATUS_USER_APC;
+    lpOverlapped->InternalHigh = 0;
+    lpOverlapped->Offset = 0;
+    lpOverlapped->OffsetHigh = 0;

-    if (!ret)
-    SetLastError(ERROR_IO_PENDING);
+    if ( register_async (&ovp->async) )
+        SetLastError( ERROR_IO_PENDING );

     return FALSE;
 }
diff -ruX diffignore CVS/wine/files/file.c MW/wine/files/file.c
--- CVS/wine/files/file.c	Thu Jan 10 09:24:50 2002
+++ MW/wine/files/file.c	Thu Jan 10 13:25:09 2002
@@ -60,6 +60,20 @@

 static HANDLE dos_handles[DOS_TABLE_SIZE];

+/* Async operations struct (see file.h) */
+
+static DWORD fileio_get_async_status (async_private *ovp);
+static DWORD fileio_get_async_count (async_private *ovp);
+static void fileio_set_async_status (async_private *ovp, DWORD status);
+static void CALLBACK fileio_call_completion_func (ULONG_PTR data);
+
+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 */
+};

 /***********************************************************************
  *              FILE_ConvertOFMode
@@ -1245,35 +1259,13 @@
     if(lpTransferred)
         *lpTransferred = lpOverlapped->InternalHigh;

-    SetLastError(lpOverlapped->Internal);
+    /* This is what the function should return according to MSDN specs */
+    if ( lpOverlapped->Internal == STATUS_PENDING )
+        SetLastError ( ERROR_IO_INCOMPLETE );

     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;
-    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.@)
  */
@@ -1283,21 +1275,61 @@

     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))
+        if (ovp->handle != handle) continue;
+
+        SERVER_START_REQ ( cancel_async )
         {
-            TRACE("overlapped = %p\n",ovp->lpOverlapped);
-            finish_async(ovp, STATUS_CANCELLED);
+            req->handle = handle;
+            req->type = ovp->type;
+            req->overlapped = ovp;
+            wine_server_call ( req );
+            if (reply->cancelled)
+            {
+                TRACE ("cancelling request: %p\n", ovp);
+                ovp->ops->set_status ( ovp, STATUS_CANCELLED );
+                finish_async (ovp);
+            }
         }
-        ovp = t;
+        SERVER_END_REQ;
     }
     WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
     return TRUE;
 }

+static DWORD fileio_get_async_status (async_private *ovp)
+{
+    return ((async_fileio*) ovp)->lpOverlapped->Internal;
+}
+
+static void fileio_set_async_status (async_private *ovp, DWORD status)
+{
+    ((async_fileio*) ovp)->lpOverlapped->Internal = status;
+}
+
+static DWORD fileio_get_async_count (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);
+}
+
 /***********************************************************************
  *             FILE_AsyncReadService      (INTERNAL)
  *
@@ -1306,18 +1338,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)))
     {
@@ -1335,9 +1368,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;
@@ -1353,7 +1386,7 @@
 			 LPOVERLAPPED overlapped,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    async_private *ovp;
+    async_fileio *ovp;
     int fd;

     TRACE("file %d to buf %p num %ld %p func %p\n",
@@ -1370,10 +1403,11 @@
     if(fd<0)
     {
         TRACE("Couldn't get FD\n");
+        SetLastError( ERROR_INVALID_HANDLE );
         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");
@@ -1381,30 +1415,20 @@
         close(fd);
         return FALSE;
     }
+
+    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->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;
-    }
+    ovp->count = bytesToRead;

-    return TRUE;
+    /* Tell register_async that this is a new request */
+    overlapped->Internal = STATUS_USER_APC;
+    return register_async (&ovp->async);
 }

 /***********************************************************************
@@ -1414,7 +1438,6 @@
 			 LPOVERLAPPED overlapped,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    overlapped->Internal     = STATUS_PENDING;
     overlapped->InternalHigh = 0;
     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine);
 }
@@ -1472,41 +1495,20 @@
             return FALSE;
         }

-        /* see if we can read some data already (this shouldn't block) */
-        result = pread( unix_handle, buffer, bytesToRead, OVERLAPPED_OFFSET(overlapped) );
-        if ((result < 0) && (errno == ESPIPE))
-            result = read( unix_handle, buffer, bytesToRead );
         close(unix_handle);
-
-        if(result<0)
-        {
-            if( (errno!=EAGAIN) && (errno!=EINTR) &&
-                ((errno != EFAULT) || IsBadWritePtr( buffer, bytesToRead )) )
-            {
-                FILE_SetDosError();
-                return FALSE;
-            }
-            else
-                result = 0;
-        }
-
-        /* if we read enough to keep the app happy, then return now */
-        if(result>=bytesToRead)
-        {
-            *bytesRead = result;
-            return TRUE;
-        }
-
-        /* at last resort, do an overlapped read */
-        overlapped->Internal     = STATUS_PENDING;
-        overlapped->InternalHigh = result;
+        overlapped->InternalHigh = 0;

         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete))
             return FALSE;

-        /* fail on return, with ERROR_IO_PENDING */
-        SetLastError(ERROR_IO_PENDING);
-        return FALSE;
+        if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) )
+        {
+            if ( GetLastError() == ERROR_IO_INCOMPLETE )
+                SetLastError ( ERROR_IO_PENDING );
+            return FALSE;
+        }
+
+        return TRUE;
     }
     if (flags & FD_FLAG_TIMEOUT)
     {
@@ -1554,18 +1556,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)))
     {
@@ -1582,9 +1585,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;
@@ -1600,7 +1603,8 @@
 			 LPOVERLAPPED overlapped,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    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);
@@ -1611,45 +1615,36 @@
         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");
+        SetLastError( ERROR_INVALID_HANDLE );
         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->func = FILE_AsyncWriteService;
     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;
+    ovp->count = bytesToWrite;

-    return TRUE;
+    /* Tell register_async that this is a new request */
+    overlapped->Internal = STATUS_USER_APC;
+    return register_async (&ovp->async);
 }

 /***********************************************************************
@@ -1659,7 +1654,6 @@
 			 LPOVERLAPPED overlapped,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    overlapped->Internal     = STATUS_PENDING;
     overlapped->InternalHigh = 0;

     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
@@ -1694,43 +1688,20 @@
             return FALSE;
         }

-        /* see if we can write some data already (this shouldn't block) */
-
-        result = pwrite( unix_handle, buffer, bytesToWrite, OVERLAPPED_OFFSET (overlapped) );
-        if ((result < 0) && (errno == ESPIPE))
-            result = write( unix_handle, buffer, bytesToWrite );
-
         close(unix_handle);
+        overlapped->InternalHigh = 0;

-        if(result<0)
-        {
-            if( (errno!=EAGAIN) && (errno!=EINTR) &&
-                ((errno != EFAULT) || IsBadReadPtr( buffer, bytesToWrite )) )
-            {
-                FILE_SetDosError();
-                return FALSE;
-            }
-            else
-                result = 0;
-        }
+        if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete))
+            return FALSE;

-        /* if we wrote enough to keep the app happy, then return now */
-        if(result>=bytesToWrite)
+        if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) )
         {
-            *bytesWritten = result;
-            return TRUE;
+            if ( GetLastError() == ERROR_IO_INCOMPLETE )
+                 SetLastError ( ERROR_IO_PENDING );
+            return FALSE;
         }
-
-        /* at last resort, do an overlapped read */
-        overlapped->Internal     = STATUS_PENDING;
-        overlapped->InternalHigh = result;

-        if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, FILE_OverlappedComplete))
-            return FALSE;
-
-        /* fail on return, with ERROR_IO_PENDING */
-        SetLastError(ERROR_IO_PENDING);
-        return FALSE;
+        return TRUE;
     }

     switch(type)
diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h
--- CVS/wine/include/file.h	Thu Jan 10 12:12:57 2002
+++ MW/wine/include/file.h	Thu Jan 10 12:52:44 2002
@@ -33,23 +33,46 @@

 /* overlapped private structure */
 struct async_private;
-typedef void (*async_handler)(struct async_private *ovp);
+
+typedef void (*async_handler) (struct async_private *ovp);
+typedef void CALLBACK (*async_call_completion_func) (ULONG_PTR data);
+typedef DWORD (*async_get_status) (struct async_private *ovp);
+typedef DWORD (*async_get_count) (struct async_private *ovp);
+typedef void (*async_set_status) (struct async_private *ovp, 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;
+
+extern async_ops fileio_async_ops;
+
 typedef struct async_private
 {
-     LPOVERLAPPED  lpOverlapped;
-     HANDLE        handle;
-     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_ops                        *ops;
+    HANDLE                           handle;
+    int                              fd;
+    int                              type;
+    async_handler                    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);
+typedef struct async_fileio
+{
+    async_private                    async;
+    LPOVERLAPPED                     lpOverlapped;
+    LPOVERLAPPED_COMPLETION_ROUTINE  completion_func;
+    char                             *buffer;
+    int                              count;
+} async_fileio;
+
+extern BOOL register_async (async_private *ovp);
+extern void WINAPI check_async_list(async_private *ovp, DWORD status);
+extern void finish_async(async_private *ovp);

 /* locale-independent case conversion */
 inline static char FILE_tolower( char c )
@@ -83,7 +106,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 -ruX diffignore CVS/wine/scheduler/synchro.c MW/wine/scheduler/synchro.c
--- CVS/wine/scheduler/synchro.c	Tue Jan  8 18:53:41 2002
+++ MW/wine/scheduler/synchro.c	Thu Jan 10 13:17:31 2002
@@ -36,27 +36,60 @@
     }
 }

-static void CALLBACK call_completion_routine(ULONG_PTR data)
+/***********************************************************************
+ *           register_async  (INTERNAL)
+ *
+ * Manipulate async request queues.
+ */
+BOOL register_async (async_private *ovp)
 {
-    async_private* ovp = (async_private*)data;
+    BOOL ret;
+    DWORD status = ovp->ops->get_status (ovp);

-    ovp->completion_func(ovp->lpOverlapped->Internal,
-                         ovp->lpOverlapped->InternalHigh,
-                         ovp->lpOverlapped);
-    ovp->completion_func=NULL;
-    HeapFree(GetProcessHeap(), 0, ovp);
-}
+    /* STATUS_USER_APC means this is a new request */
+    /* STATUS_PENDING means this request is rescheduled (IO incomplete) */

-void finish_async(async_private *ovp, DWORD status)
-{
-    ovp->lpOverlapped->Internal=status;
+    if ( status == STATUS_USER_APC )
+    {
+        status = STATUS_PENDING;
+        ovp->ops->set_status (ovp, status);
+
+        /* 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;
+    }

-    /* call ReadFileEx/WriteFileEx's overlapped completion function */
-    if(ovp->completion_func)
+    /* The server call will destroy all except PENDING requests */
+    SERVER_START_REQ( register_async )
     {
-        QueueUserAPC(call_completion_routine,GetCurrentThread(),(ULONG_PTR)ovp);
+        req->handle = ovp->handle;
+        req->overlapped = ovp;
+        req->type = ovp->type;
+        req->count = ovp->ops->get_count (ovp);
+        req->func = check_async_list;
+        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;
+}
+
+/***********************************************************************
+ *           finish_async  (INTERNAL)
+ *
+ * Called after completion or cancellation of an async request.
+ * Note: The completion status must be set already.
+ */
+void finish_async(async_private *ovp)
+{
     /* remove it from the active list */
     if(ovp->prev)
         ovp->prev->next = ovp->next;
@@ -70,7 +103,9 @@
     ovp->prev=NULL;

     close(ovp->fd);
-    if(!ovp->completion_func) HeapFree(GetProcessHeap(), 0, ovp);
+
+    /* Queue completion function unconditionally */
+    QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp );
 }

 /***********************************************************************
@@ -78,30 +113,34 @@
  *
  * Process a status event from the server.
  */
-void WINAPI check_async_list(LPOVERLAPPED overlapped, DWORD status)
+void WINAPI check_async_list(async_private *asp, DWORD status)
 {
-    async_private *ovp;
+    async_private *ovp = NULL;
+    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)
+    if(!ovp)
             return;

     if(status != STATUS_ALERTED)
-        ovp->lpOverlapped->Internal = status;
+    {
+        ovp_status = status;
+        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);
-        FILE_StartAsync(ovp->handle, ovp->lpOverlapped, ovp->type, 0, ovp->lpOverlapped->Internal);
-        }
+        register_async (ovp);
+        ovp_status = ovp->ops->get_status (ovp);
+    }

-    if(ovp->lpOverlapped->Internal!=STATUS_PENDING)
-        finish_async(ovp,ovp->lpOverlapped->Internal);
+    if( ovp_status != STATUS_PENDING )
+        finish_async(ovp);
 }


diff -ruX diffignore CVS/wine/server/async.c MW/wine/server/async.c
--- CVS/wine/server/async.c	Wed Jan  2 12:50:04 2002
+++ MW/wine/server/async.c	Thu Jan 10 12:52:44 2002
@@ -177,3 +177,28 @@
     release_object(obj);
 }

+DECL_HANDLER(cancel_async)
+{
+    struct object *obj;
+
+    if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) )
+        return;
+
+    if(obj->ops->queue_async)
+    {
+        struct async_queue *q = obj->ops->queue_async(obj, NULL, req->type, 0);
+        struct async *async;
+
+        async = find_async(q, current, req->overlapped);
+        if (async)
+        {
+            destroy_async(async);
+            reply->cancelled = 1;
+            set_select_events(obj,obj->ops->get_poll_events(obj));
+        }
+        else reply->cancelled = 0;
+    }
+
+    release_object(obj);
+}
+
diff -ruX diffignore CVS/wine/server/protocol.def MW/wine/server/protocol.def
--- CVS/wine/server/protocol.def	Thu Jan 10 09:24:53 2002
+++ MW/wine/server/protocol.def	Thu Jan 10 12:52:44 2002
@@ -1534,7 +1534,7 @@
 #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;
@@ -1548,6 +1548,14 @@
 #define ASYNC_TYPE_WRITE 0x02
 #define ASYNC_TYPE_WAIT  0x03

+/* Cancel an async I/O */
+ at REQ(cancel_async)
+    handle_t     handle;
+    int          type;
+    void*        overlapped;
+ at REPLY
+    int          cancelled;
+ at END

 /* Create a named pipe */
 @REQ(create_named_pipe)







More information about the wine-patches mailing list