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.
Wrap the "notify_async_direct_result" request in a function named "notify_async", which is no-op if the supplied wait handle is NULL.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- server/async.c | 48 ++++++++++++++++++++++++++++++++++----------- server/protocol.def | 8 ++++++++ 2 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/server/async.c b/server/async.c index 2a67892dbe2..9b08c139929 100644 --- a/server/async.c +++ b/server/async.c @@ -135,11 +135,8 @@ static int async_signaled( struct object *obj, struct wait_queue_entry *entry ) return async->signaled; }
-static void async_satisfied( struct object *obj, struct wait_queue_entry *entry ) +static void async_set_direct_result( struct async *async ) { - struct async *async = (struct async *)obj; - assert( obj->ops == &async_ops ); - /* we only return an async handle for asyncs created via create_request_async() */ assert( async->iosb );
@@ -149,18 +146,26 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry 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; + } +} + +static void async_satisfied( struct object *obj, struct wait_queue_entry *entry ) +{ + struct async *async = (struct async *)obj; + assert( obj->ops == &async_ops ); + + async_set_direct_result( async ); + 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 ); - - /* 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; - } }
static void async_destroy( struct object *obj ) @@ -752,3 +757,24 @@ 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 ); + unsigned int status; + + if (!async) return; + + if (async->iosb) + { + async->iosb->status = req->status; + async->iosb->result = req->information; + async_set_direct_result( async ); + status = req->status; + } + else status = STATUS_ACCESS_DENIED; + + release_object( &async->obj ); + set_error( status ); +} diff --git a/server/protocol.def b/server/protocol.def index db73f0418a9..c4596e0bd58 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2147,6 +2147,14 @@ enum message_type @END
+/* Notify direct completion of async and close the wait handle */ +@REQ(notify_async_direct_result) + obj_handle_t handle; /* wait handle */ + unsigned int status; /* completion status */ + apc_param_t information; /* IO_STATUS_BLOCK Information */ +@END + + /* Perform a read on a file object */ @REQ(read) async_data_t async; /* async I/O parameters */