struct async-private - now tested and cleaned up

Martin Wilck Martin.Wilck at fujitsu-siemens.com
Tue Jan 15 13:05:13 CST 2002


PATCH: async-struct.diff

This patch introduces a new API for asynchronous requests, which

- separates cleanly between async scheduling and file IO related issues
- thereby makes the API compatible with other types of async requests (e.g. Winsock2).

It is a polished resubmit of my former posting, without the GetOverlappedResult() stuff
which will follow in a separate patch. It is against clean CVS 2002-01-15.

I would be really grateful if this patch was applied, because it is a prerequisite for me to
get going with Winsock2 overlapped IO.

It was tested for regular file IO and (even 16 bit) serial IO (thanks 2 Lawson Whitney).
No regressions found.

ChangeLog:

server/protocol.def and server/async.c:
        cancel_async(): new reqest type.

include/file.h:
        struct async_ops: introduce "ops" field for different request types.
        struct async_private: only fields necessary for async request scheduling
        struct async_fileio: new struct, contains file IO related fields.

scheduler/synchro.c:
        register_async(): replacement for FILE_StartAsync().
                Hooks new requests in NtCurrentTeb()->pending_list.
        finish_async(): Assume status is already set correctly.
                Queue call_completion unconditionally.
        check_async(): Use register_async() for rescheduling.

files/file.c:
        CancelIo(): Use new cancel_async server request.
        fileio_call_completion_func(): check if completion_func is non-NULL (see finish_async).
        FILE_AsyncReadService(), FILE_AsyncWriteService(): type adjustments according to new API
        FILE_ReadFileEx(), FILE_WriteFileEx(): use new async API.

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

Martin Wilck <Martin.Wilck at Fujitsu-Siemens.com>


diff -ruX diffignore CVS/wine/dlls/kernel/comm.c MW/wine/dlls/kernel/comm.c
--- CVS/wine/dlls/kernel/comm.c	Tue Jan 15 19:37:37 2002
+++ MW/wine/dlls/kernel/comm.c	Tue Jan 15 19:09:42 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	Tue Jan 15 19:37:37 2002
+++ MW/wine/files/file.c	Tue Jan 15 19:34:00 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
@@ -1255,30 +1269,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;
-    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.@)
  */
@@ -1288,21 +1278,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)
  *
@@ -1311,18 +1341,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)))
     {
@@ -1340,9 +1371,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;
@@ -1358,7 +1389,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",
@@ -1375,10 +1406,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");
@@ -1386,30 +1418,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);
 }

 /***********************************************************************
@@ -1419,7 +1441,6 @@
 			 LPOVERLAPPED overlapped,
 			 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
 {
-    overlapped->Internal     = STATUS_PENDING;
     overlapped->InternalHigh = 0;
     return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine);
 }
@@ -1503,7 +1524,6 @@
         }

         /* at last resort, do an overlapped read */
-        overlapped->Internal     = STATUS_PENDING;
         overlapped->InternalHigh = result;

         if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, FILE_OverlappedComplete))
@@ -1559,18 +1579,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)))
     {
@@ -1587,9 +1608,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;
@@ -1605,7 +1626,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);
@@ -1616,45 +1638,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);
 }

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

     return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine);
diff -ruX diffignore CVS/wine/include/file.h MW/wine/include/file.h
--- CVS/wine/include/file.h	Tue Jan 15 19:37:37 2002
+++ MW/wine/include/file.h	Tue Jan 15 19:09:42 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 )
@@ -82,7 +105,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 15 19:37:37 2002
+++ MW/wine/scheduler/synchro.c	Tue Jan 15 19:09:42 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,29 @@
  *
  * 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)
-        {
-        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_async (ovp);
 }


diff -ruX diffignore CVS/wine/server/async.c MW/wine/server/async.c
--- CVS/wine/server/async.c	Tue Jan 15 19:37:37 2002
+++ MW/wine/server/async.c	Tue Jan 15 19:09:42 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	Tue Jan 15 19:37:37 2002
+++ MW/wine/server/protocol.def	Tue Jan 15 19:09:42 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