[RFC PATCH v5 2/5] server: Add a new server request "set_async_direct_result."

Jinoh Kang jinoh.kang.kr at gmail.com
Fri Feb 4 14:51:56 CST 2022


Some I/O operations need a way to "queue" the async to the target object
first, even if the operation itself is to be completed synchronously.
After synchronous completion, it needs a way to notify the
IO_STATUS_BLOCK values back to the server.

Add a new wineserver request, "set_async_direct_result", which notifies
direct (i.e. synchronous) completion of async from the same thread.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

Notes:
    v1 -> v2: dequeue async after failed completion
    v2 -> v3: rewrite handling of pending/failed asyncs.
    v3 -> v4:
    - add assert( async->iosb );
    - make robust against abrupt transition/cancellation:
      don't return STATUS_ACCESS_DENIED on precondition failure
      (client won't know what to do with STATUS_ACCESS_DENIED anyway)
    - always return wait_handle if possible
    - clarify and rearrange comments
    v4 -> v5:
    - edit comments
    - /notify_async_direct_result/set_async_direct_result/g
    - remove assert( async->iosb );
    - simplify complicated precondition
    - fail early if precondition unmet
    - don't forward status from async
    - don't use async_handoff(); open code relevant parts instead

 server/async.c      | 56 +++++++++++++++++++++++++++++++++++++++++----
 server/protocol.def | 10 ++++++++
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/server/async.c b/server/async.c
index 97b3b9fc10a..01cfa2926a0 100644
--- a/server/async.c
+++ b/server/async.c
@@ -341,10 +341,11 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
     if (get_error() == STATUS_ALERTED)
     {
         /* give the client opportunity to complete synchronously.  after the
-         * client performs the I/O, it reports the result back to the server.
-         * if it turns out that the I/O request is not actually immediately
-         * satiable, the client may then choose to re-queue the async by
-         * reporting STATUS_PENDING instead.
+         * client performs the I/O, it reports the result back to the server
+         * via the set_async_direct_result request.  if it turns out that the
+         * I/O request is not actually immediately satiable, the client may
+         * then choose to re-queue the async by reporting STATUS_PENDING
+         * instead.
          *
          * since we're deferring the initial I/O (to the client), we mark the
          * async as having unknown initial status (unknown_status = 1).  Note
@@ -752,3 +753,50 @@ DECL_HANDLER(get_async_result)
     }
     set_error( iosb->status );
 }
+
+/* notify direct completion of async and close the wait handle if not blocking */
+DECL_HANDLER(set_async_direct_result)
+{
+    struct async *async = (struct async *)get_handle_obj( current->process, req->handle, 0, &async_ops );
+    unsigned int status = req->status;
+
+    if (!async) return;
+
+    if (!async->unknown_status || !async->terminated || !async->alerted)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        release_object( &async->obj );
+        return;
+    }
+
+    async_set_initial_status( async, status );
+
+    if (status == STATUS_PENDING)
+    {
+        async->direct_result = 0;
+        async->pending = 1;
+    }
+
+    /* if the I/O has completed successfully, the client would have already
+     * set the IOSB. therefore, we can skip waiting on wait_handle and do
+     * async_set_result() directly.
+     */
+    async_set_result( &async->obj, status, req->information );
+
+    /* close wait handle here to avoid extra server round trip, if the I/O
+     * either has completed, or is pending and not blocking.
+     */
+    if (status != STATUS_PENDING || !async->blocking)
+    {
+        close_handle( async->thread->process, async->wait_handle );
+        async->wait_handle = 0;
+    }
+
+    /* report back to the client whether the wait handle has been closed.
+     * handle will be 0 if closed by us; otherwise the original value is
+     * retained
+     */
+    reply->handle = async->wait_handle;
+
+    release_object( &async->obj );
+}
diff --git a/server/protocol.def b/server/protocol.def
index 02e73047f9b..28dee7c48f7 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2163,6 +2163,16 @@ enum message_type
 @END
 
 
+/* Notify direct completion of async and close the wait handle if not blocking */
+ at REQ(set_async_direct_result)
+    obj_handle_t   handle;        /* wait handle */
+    unsigned int   status;        /* completion status */
+    apc_param_t    information;   /* IO_STATUS_BLOCK Information */
+ at REPLY
+    obj_handle_t   handle;        /* wait handle, or NULL if closed */
+ at END
+
+
 /* Perform a read on a file object */
 @REQ(read)
     async_data_t   async;         /* async I/O parameters */
-- 
2.34.1




More information about the wine-devel mailing list