[RFC PATCH 1/6] server: Allow calling async_handoff() with status code STATUS_ALERTED.

Jinoh Kang jinoh.kang.kr at gmail.com
Sun Jan 23 11:29:43 CST 2022


If the server detects that an I/O request could be completed immediately
(e.g. the socket to read from already has incoming data), it can now
return STATUS_ALERTED to allow opportunistic synchronous I/O.
The Unix side will then attempt to perform I/O in nonblocking mode and
report back the I/O status to the server with signal_wait_async().
If the operation returns e.g. EAGAIN or EWOULDBLOCK, the client can opt
to either abandon the request (by specifying an error status) or poll
for it in the server as usual (by waiting on the wait handle).

Without such mechanism in place, the client cannot safely perform
immediately satiable I/O operations synchronously, since it can
potentially conflict with other pending I/O operations that have already
been queued.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 server/async.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/server/async.c b/server/async.c
index 7aef28355f0..2a67892dbe2 100644
--- a/server/async.c
+++ b/server/async.c
@@ -65,6 +65,7 @@ struct async
 };
 
 static void async_dump( struct object *obj, int verbose );
+static int async_add_queue( struct object *obj, struct wait_queue_entry *entry );
 static int async_signaled( struct object *obj, struct wait_queue_entry *entry );
 static void async_satisfied( struct object * obj, struct wait_queue_entry *entry );
 static void async_destroy( struct object *obj );
@@ -74,7 +75,7 @@ static const struct object_ops async_ops =
     sizeof(struct async),      /* size */
     &no_type,                  /* type */
     async_dump,                /* dump */
-    add_queue,                 /* add_queue */
+    async_add_queue,           /* add_queue */
     remove_queue,              /* remove_queue */
     async_signaled,            /* signaled */
     async_satisfied,           /* satisfied */
@@ -105,6 +106,28 @@ static void async_dump( struct object *obj, int verbose )
     fprintf( stderr, "Async thread=%p\n", async->thread );
 }
 
+static int async_add_queue( struct object *obj, struct wait_queue_entry *entry )
+{
+    struct async *async = (struct async *)obj;
+    assert( obj->ops == &async_ops );
+
+    if (!async->pending && async->terminated && async->alerted)
+    {
+        /* The client has failed to complete synchronously (e.g. EWOULDBLOCK).
+         * Restart the async as fully fledged asynchronous I/O, where
+         * the completion port notification and APC call will be triggered
+         * appropriately. */
+        async->pending = 1;
+
+        /* Unset the signaled flag if the client wants to block on this async. */
+        if (async->blocking) async->signaled = 0;
+
+        async_set_result( obj, STATUS_PENDING, 0 );  /* kick it off */
+    }
+
+    return add_queue( obj, entry );
+}
+
 static int async_signaled( struct object *obj, struct wait_queue_entry *entry )
 {
     struct async *async = (struct async *)obj;
@@ -126,7 +149,8 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry
         async->direct_result = 0;
     }
 
-    if (async->initial_status == STATUS_PENDING && async->blocking)
+    if ((async->initial_status == STATUS_PENDING && async->blocking) ||
+        async->initial_status == STATUS_ALERTED)
         set_wait_status( entry, async->iosb->status );
     else
         set_wait_status( entry, async->initial_status );
-- 
2.31.1




More information about the wine-devel mailing list