[RFC PATCH v4 2/5] server: Add a new server request "notify_async_direct_result."
Jinoh Kang
jinoh.kang.kr at gmail.com
Sat Jan 29 01:47:07 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
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
server/async.c | 62 +++++++++++++++++++++++++++++++++++++++++++++
server/protocol.def | 10 ++++++++
2 files changed, 72 insertions(+)
diff --git a/server/async.c b/server/async.c
index e169bb23225..8852ff1c6d5 100644
--- a/server/async.c
+++ b/server/async.c
@@ -752,3 +752,65 @@ DECL_HANDLER(get_async_result)
}
set_error( iosb->status );
}
+
+/* Notify direct completion of async and close the wait handle if not blocking */
+DECL_HANDLER(notify_async_direct_result)
+{
+ struct async *async = (struct async *)get_handle_obj( current->process, req->handle, 0, &async_ops );
+
+ if (!async) return;
+
+ /* we only return an async handle for asyncs created via create_request_async() */
+ assert( async->iosb );
+
+ if (async->unknown_status && !async->pending &&
+ async->terminated && async->alerted &&
+ async->iosb->status == STATUS_PENDING)
+ {
+ /* async->terminated is 1, so async_terminate() won't do anything.
+ * We need to set the status and result for ourselves.
+ */
+ async->iosb->status = req->status;
+ async->iosb->result = req->information;
+
+ /* Set status for async_handoff(). */
+ set_error( async->iosb->status );
+
+ /* 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.
+ *
+ * NOTE: async_handoff() is being called with async->terminated = 1.
+ */
+ async->unknown_status = 0;
+ async_handoff( async, NULL, 0 );
+
+ /* 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, async->iosb->status, async->iosb->result );
+
+ /* Close wait handle here to avoid extra server round trip if the I/O
+ * has completed successfully.
+ *
+ * - If STATUS_PENDING, async_handoff() decides whether to close
+ * the wait handle for us. The wait handle is kept open if
+ * async->blocking is set (i.e. we're going to block on it).
+ *
+ * - If failed (NT_ERROR), async_handoff() always closes
+ * the wait_handle, which means async->wait_handle == 0.
+ */
+ if (async->wait_handle && async->iosb->status != STATUS_PENDING)
+ {
+ close_handle( async->thread->process, async->wait_handle );
+ async->wait_handle = 0;
+ }
+ } /* Otherwise, async have been abruptly transitioned (cancelled?). */
+
+ /* async_set_result() may have overriden the error value. Reset it. */
+ set_error( async->iosb->status );
+ reply->handle = async->wait_handle;
+
+ release_object( &async->obj );
+}
diff --git a/server/protocol.def b/server/protocol.def
index 02e73047f9b..d79eca074a0 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(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