[PATCH v4 3/8] server: Add async_initial_status_callback.

Jinoh Kang jinoh.kang.kr at gmail.com
Thu Mar 3 07:30:26 CST 2022


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 at 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
    v3 -> v4: no changes

 server/async.c | 39 +++++++++++++++++++++++++++++++++++----
 server/file.h  |  2 ++
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/server/async.c b/server/async.c
index d49fb8b7c04..986e8a1ce24 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,11 +315,18 @@ 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 )
 {
-    async->initial_status = status;
+    set_async_initial_status( async, status );
     async->unknown_status = 0;
 }
 
@@ -359,7 +383,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() ))
     {
@@ -398,7 +422,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;
 }
@@ -757,9 +781,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 );
@@ -773,11 +801,14 @@ DECL_HANDLER(set_async_direct_result)
         async->pending = 1;
     }
 
+    /* Set iosb information field for async_initial_status_callback */
+    async->iosb->result = information;
+
     /* 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 );
+    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 );
-- 
2.34.1




More information about the wine-devel mailing list