async->initial_status_callback is called whenever the initial_status is set. This can be used to do the post-processing after the initial I/O has been performed by the client, but before the async is actually completed or queued.
Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com ---
Notes: v1 -> v2: - add spacing around initial_status_callback call arguments - add async and fd arguments to async_initial_status_callback v2 -> v3: no changes
server/async.c | 40 +++++++++++++++++++++++++++++++++++----- server/file.h | 2 ++ 2 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/server/async.c b/server/async.c index f078f42f34c..d597eb71f12 100644 --- a/server/async.c +++ b/server/async.c @@ -62,6 +62,8 @@ struct async unsigned int comp_flags; /* completion flags */ async_completion_callback completion_callback; /* callback to be called on completion */ void *completion_callback_private; /* argument to completion_callback */ + async_initial_status_callback initial_status_callback; /* callback to be called on initial status set */ + void *initial_status_callback_private; /* argument to initial_status_callback */ };
static void async_dump( struct object *obj, int verbose ); @@ -139,11 +141,24 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry } }
+static void set_async_initial_status( struct async *async, unsigned int status ) +{ + async->initial_status = status; + if (async->initial_status_callback) + { + async->initial_status_callback( async->initial_status_callback_private, async, async->fd, status ); + async->initial_status_callback = NULL; + } +} + static void async_destroy( struct object *obj ) { struct async *async = (struct async *)obj; assert( obj->ops == &async_ops );
+ /* ensure initial_status_callback has been called */ + set_async_initial_status( async, async->initial_status ); + list_remove( &async->process_entry );
if (async->queue) @@ -281,6 +296,8 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da async->comp_flags = 0; async->completion_callback = NULL; async->completion_callback_private = NULL; + async->initial_status_callback = NULL; + async->initial_status_callback_private = NULL;
if (iosb) async->iosb = (struct iosb *)grab_object( iosb ); else async->iosb = NULL; @@ -298,6 +315,13 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da return async; }
+/* set a callback to be notified when the async initial status is set */ +void async_set_initial_status_callback( struct async *async, async_initial_status_callback func, void *private ) +{ + async->initial_status_callback = func; + async->initial_status_callback_private = private; +} + /* set the initial status of an async whose status was previously unknown * the initial status may be STATUS_PENDING */ void async_set_initial_status( struct async *async, unsigned int status ) @@ -305,7 +329,7 @@ void async_set_initial_status( struct async *async, unsigned int status ) assert( async->unknown_status ); if (!async->terminated) { - async->initial_status = status; + set_async_initial_status( async, status ); async->unknown_status = 0; } } @@ -363,7 +387,7 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ return async->wait_handle; }
- async->initial_status = get_error(); + set_async_initial_status( async, get_error() );
if (!async->pending && NT_ERROR( get_error() )) { @@ -402,7 +426,7 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ async->wait_handle = 0; } } - async->initial_status = async->iosb->status; + set_async_initial_status( async, async->iosb->status ); set_error( async->iosb->status ); return async->wait_handle; } @@ -759,9 +783,13 @@ 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; + apc_param_t information = req->information;
if (!async) return;
+ /* we only return an async handle for asyncs created via create_request_async() */ + assert( async->iosb ); + if (!async->unknown_status || !async->terminated || !async->alerted) { set_error( STATUS_INVALID_PARAMETER ); @@ -769,7 +797,9 @@ DECL_HANDLER(set_async_direct_result) return; }
- async->initial_status = status; + /* Set iosb information field for async_initial_status_callback */ + async->iosb->result = information; + set_async_initial_status( async, status ); async->unknown_status = 0;
if (status == STATUS_PENDING) @@ -782,7 +812,7 @@ DECL_HANDLER(set_async_direct_result) * 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 ); + async_set_result( &async->obj, status, information );
/* close wait handle here to avoid extra server round trip, if the I/O * either has completed, or is pending and not blocking. diff --git a/server/file.h b/server/file.h index 9f9d4cd4e1a..893d4ac6411 100644 --- a/server/file.h +++ b/server/file.h @@ -219,6 +219,7 @@ extern struct object *create_serial( struct fd *fd ); /* async I/O functions */
typedef void (*async_completion_callback)( void *private ); +typedef void (*async_initial_status_callback)( void *private, struct async *async, struct fd *fd, unsigned int status );
extern void free_async_queue( struct async_queue *queue ); extern struct async *create_async( struct fd *fd, struct thread *thread, const async_data_t *data, struct iosb *iosb ); @@ -230,6 +231,7 @@ extern void async_set_result( struct object *obj, unsigned int status, apc_param extern void async_set_completion_callback( struct async *async, async_completion_callback func, void *private ); extern void async_set_unknown_status( struct async *async ); extern void set_async_pending( struct async *async ); +extern void async_set_initial_status_callback( struct async *async, async_initial_status_callback func, void *private ); extern void async_set_initial_status( struct async *async, unsigned int status ); extern void async_wake_obj( struct async *async ); extern int async_waiting( struct async_queue *queue );