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@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 */ +@REQ(set_async_direct_result) + obj_handle_t handle; /* wait handle */ + unsigned int status; /* completion status */ + apc_param_t information; /* IO_STATUS_BLOCK Information */ +@REPLY + obj_handle_t handle; /* wait handle, or NULL if closed */ +@END + + /* Perform a read on a file object */ @REQ(read) async_data_t async; /* async I/O parameters */