From: Jacek Caban Subject: [PATCH 07/12] server: Introduce default async queue that's used if async is not explicitly queued in fd op. Message-Id: <47926a5f-1724-3632-b690-e1277919b23b@codeweavers.com> Date: Tue, 13 Jun 2017 16:48:40 +0200 Although (at least now) all read and write implementations always queue async on success, it's not the case for ioctl. I think we should allow simple ioctls without pending results to not care about explicitly handling async objects, but those still need a queued async for proper result reporting. We currently don't set events, queue APCs nor send completion for them. My initial thought was to make async object work better without associated queue, but that leads to problems with references from an async to fd. Signed-off-by: Jacek Caban --- server/async.c | 8 +++++++- server/fd.c | 20 +++++++++++++++----- server/file.h | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/server/async.c b/server/async.c index b693c2867c..c5c09c41a4 100644 --- a/server/async.c +++ b/server/async.c @@ -324,7 +324,7 @@ struct async *create_request_async( struct thread *thread, const async_data_t *d } /* return async object status and wait handle to client */ -obj_handle_t async_handoff( struct async *async, int success, data_size_t *result ) +obj_handle_t async_handoff( struct async *async, int success, struct async_queue *default_queue, data_size_t *result ) { if (!success) { @@ -333,6 +333,12 @@ obj_handle_t async_handoff( struct async *async, int success, data_size_t *resul return 0; } + if (!async->queue) + { + queue_async( default_queue, async ); + if (async->status != STATUS_PENDING) release_object( async ); + } + if (async->iosb->status != STATUS_PENDING) { if (async->iosb->out_data) diff --git a/server/fd.c b/server/fd.c index 0f1a15eebf..1d98108f6d 100644 --- a/server/fd.c +++ b/server/fd.c @@ -192,6 +192,7 @@ struct fd struct async_queue *read_q; /* async readers of this fd */ struct async_queue *write_q; /* async writers of this fd */ struct async_queue *wait_q; /* other async waiters of this fd */ + struct async_queue *default_q; /* asyncs not associated with any queue */ struct completion *completion; /* completion object attached to this fd */ apc_param_t comp_key; /* completion key to set in completion events */ }; @@ -1476,6 +1477,7 @@ static void fd_destroy( struct object *obj ) free_async_queue( fd->read_q ); free_async_queue( fd->write_q ); free_async_queue( fd->wait_q ); + free_async_queue( fd->default_q ); if (fd->completion) release_object( fd->completion ); remove_fd_locks( fd ); @@ -1606,6 +1608,7 @@ static struct fd *alloc_fd_object(void) fd->read_q = NULL; fd->write_q = NULL; fd->wait_q = NULL; + fd->default_q = NULL; fd->completion = NULL; list_init( &fd->inode_entry ); list_init( &fd->locks ); @@ -1641,6 +1644,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->read_q = NULL; fd->write_q = NULL; fd->wait_q = NULL; + fd->default_q = NULL; fd->completion = NULL; fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; list_init( &fd->inode_entry ); @@ -2101,7 +2105,7 @@ void default_fd_queue_async( struct fd *fd, struct async *async, int type, int c /* default reselect_async() fd routine */ void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ) { - if (queue != fd->wait_q) + if (queue != fd->wait_q && queue != fd->default_q) { int poll_events = fd->fd_ops->get_poll_events( fd ); int events = check_fd_events( fd, poll_events ); @@ -2353,6 +2357,12 @@ failed: free( name ); } +static struct async *fd_create_request_async( struct fd *fd, struct thread *thread, const async_data_t *data ) +{ + if (!fd->default_q && !(fd->default_q = create_async_queue( fd ))) return NULL; + return create_request_async( thread, data ); +} + struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key ) { *p_key = fd->comp_key; @@ -2449,9 +2459,9 @@ DECL_HANDLER(read) if (!fd) return; - if ((async = create_request_async( current, &req->async ))) + if ((async = fd_create_request_async( fd, current, &req->async ))) { - reply->wait = async_handoff( async, fd->fd_ops->read( fd, async, req->pos ), NULL ); + reply->wait = async_handoff( async, fd->fd_ops->read( fd, async, req->pos ), fd->default_q, NULL ); reply->options = fd->options; release_object( async ); } @@ -2466,9 +2476,9 @@ DECL_HANDLER(write) if (!fd) return; - if ((async = create_request_async( current, &req->async ))) + if ((async = fd_create_request_async( fd, current, &req->async ))) { - reply->wait = async_handoff( async, fd->fd_ops->write( fd, async, req->pos ), &reply->size ); + reply->wait = async_handoff( async, fd->fd_ops->write( fd, async, req->pos ), fd->default_q, &reply->size ); reply->options = fd->options; release_object( async ); } diff --git a/server/file.h b/server/file.h index 96c1d23471..9b034c8b34 100644 --- a/server/file.h +++ b/server/file.h @@ -177,7 +177,7 @@ extern struct async_queue *create_async_queue( struct fd *fd ); extern void free_async_queue( struct async_queue *queue ); extern struct async *create_async( struct thread *thread, const async_data_t *data, struct iosb *iosb ); extern struct async *create_request_async( struct thread *thread, const async_data_t *data ); -extern obj_handle_t async_handoff( struct async *async, int success, data_size_t *result ); +extern obj_handle_t async_handoff( struct async *async, int success, struct async_queue *default_queue, data_size_t *result ); extern void queue_async( struct async_queue *queue, struct async *async ); extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ); extern void async_set_result( struct object *obj, unsigned int status, apc_param_t total );