[RFC PATCH v2 2/5] server: Add a new server request "notify_async_direct_result."
Jinoh Kang
jinoh.kang.kr at gmail.com
Thu Jan 27 13:05:45 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, "notify_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
server/async.c | 84 ++++++++++++++++++++++++++++++++++++++++-----
server/protocol.def | 10 ++++++
2 files changed, 86 insertions(+), 8 deletions(-)
diff --git a/server/async.c b/server/async.c
index 6373e8c1ae4..714e82362c6 100644
--- a/server/async.c
+++ b/server/async.c
@@ -473,6 +473,17 @@ static void add_async_completion( struct async *async, apc_param_t cvalue, unsig
if (async->completion) add_completion( async->completion, async->comp_key, cvalue, status, information );
}
+static void async_dequeue( struct async *async )
+{
+ if (!async->queue) return;
+
+ list_remove( &async->queue_entry );
+ async_reselect( async );
+ async->fd = NULL;
+ async->queue = NULL;
+ release_object( async );
+}
+
/* store the result of the client-side async callback */
void async_set_result( struct object *obj, unsigned int status, apc_param_t total )
{
@@ -531,14 +542,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
async->completion_callback( async->completion_callback_private );
async->completion_callback = NULL;
- if (async->queue)
- {
- list_remove( &async->queue_entry );
- async_reselect( async );
- async->fd = NULL;
- async->queue = NULL;
- release_object( async );
- }
+ async_dequeue( async );
}
}
@@ -750,3 +754,67 @@ DECL_HANDLER(get_async_result)
}
set_error( iosb->status );
}
+
+/* Notify direct completion of async and close the wait handle */
+DECL_HANDLER(notify_async_direct_result)
+{
+ struct async *async = (struct async *)get_handle_obj( current->process, req->handle, 0, &async_ops );
+
+ if (!async) return;
+
+ if (async->iosb && async->unknown_status && !async->pending && async->terminated)
+ {
+ /* Reactivate async. We call async_reselect() later. */
+ async->terminated = 0;
+
+ /* Set result for async_handoff(). */
+ set_error( req->status );
+ async->iosb->result = req->information;
+
+ /* The async_handoff() call prior to the current server request was
+ * effectively a no-op since async->unknown_status is 1. Calling it
+ * again with async->unknown_status = 0 will do the remaining steps.
+ */
+ async->unknown_status = 0;
+ async_handoff( async, NULL, 0 );
+
+ if (get_error() == STATUS_PENDING)
+ {
+ async_reselect( async );
+ }
+ else if (NT_ERROR( get_error() ))
+ {
+ /* synchronous I/O failure: don't invoke callbacks, only dequeue it. */
+ async_dequeue( async );
+ }
+ else
+ {
+ /* I/O completed successfully. The client has already set the IOSB,
+ * so we can skip waiting on wait_handle and do async_set_result()
+ * directly.
+ *
+ * If !async->direct_result, an APC_ASYNC_IO has been fired.
+ * async_set_result() will be called when the APC returns.
+ */
+ if (async->direct_result)
+ {
+ async_set_result( &async->obj, async->iosb->status, async->iosb->result );
+ async->direct_result = 0;
+ }
+
+ /* close wait handle here to avoid extra server round trip */
+ if (async->wait_handle)
+ {
+ close_handle( async->thread->process, async->wait_handle );
+ async->wait_handle = 0;
+ }
+ }
+
+ /* The wait handle is preserved only when the status is STATUS_PENDING
+ * and async->blocking is set (i.e. we're going to block on it). */
+ reply->handle = async->wait_handle;
+ }
+ else set_error( STATUS_ACCESS_DENIED );
+
+ release_object( &async->obj );
+}
diff --git a/server/protocol.def b/server/protocol.def
index 02e73047f9b..2c3b8dbc619 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 */
+ at REQ(notify_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