From: "Erich E. Hoover" Subject: [PATCH 1/3] server: Update stored completion information even after an async IO is queued (try 2). Message-Id: Date: Mon, 14 May 2012 16:12:03 -0600 Real Name: Erich Hoover Description: The completion information for a file handle can be updated after an async IO has been queued and this information will still be valid for the async operation (even if the handle is closed before the async completes!). The attached patch adds a file operation to update the completion information for a queued async operation so that such a change can be properly propagated to the async object. This version of the patch has been rebased to not deal with a stored completion handle. Changelog: server: Update stored completion information even after an async IO is queued. From 777ab1f5de8ed8d7a702197fe824afb3fb0650bd Mon Sep 17 00:00:00 2001 From: Erich Hoover Date: Mon, 14 May 2012 15:31:14 -0600 Subject: server: Update stored completion information even after an async IO is queued. --- server/async.c | 20 +++++++++++++++++++- server/fd.c | 9 +++++++++ server/file.c | 3 ++- server/file.h | 4 ++++ server/mailslot.c | 9 ++++++--- server/mapping.c | 3 ++- server/named_pipe.c | 7 +++++-- server/serial.c | 3 ++- server/signal.c | 3 ++- server/sock.c | 13 ++++++++++++- server/thread.c | 3 ++- 11 files changed, 65 insertions(+), 12 deletions(-) diff --git a/server/async.c b/server/async.c index dd28dff..01d1ca1 100644 --- a/server/async.c +++ b/server/async.c @@ -214,11 +214,12 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co async->timeout = NULL; async->queue = (struct async_queue *)grab_object( queue ); async->completion = NULL; - if (queue->fd) async->completion = fd_get_completion( queue->fd, &async->comp_key ); list_add_tail( &queue->queue, &async->queue_entry ); grab_object( async ); + async_update( async->queue ); + if (queue->fd) set_fd_signaled( queue->fd, 0 ); if (event) reset_event( event ); return async; @@ -330,3 +331,20 @@ void async_wake_up( struct async_queue *queue, unsigned int status ) if (status == STATUS_ALERTED) break; /* only wake up the first one */ } } + +/* update an async to correspond to new file object information */ +void async_update( struct async_queue *queue ) +{ + struct list *ptr, *next; + + if (!queue) return; + + LIST_FOR_EACH_SAFE( ptr, next, &queue->queue ) + { + struct async *async = LIST_ENTRY( ptr, struct async, queue_entry ); + + if (!async->completion && async->queue->fd) + async->completion = fd_get_completion( async->queue->fd, &async->comp_key ); + } +} + diff --git a/server/fd.c b/server/fd.c index a8b3a5f..07db476 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2103,6 +2103,14 @@ void default_fd_cancel_async( struct fd *fd, struct process *process, struct thr set_error( STATUS_NOT_FOUND ); } +/* default update_async() fd routine */ +void default_fd_update_async( struct fd *fd ) +{ + async_update( fd->read_q ); + async_update( fd->write_q ); + async_update( fd->wait_q ); +} + /* default flush() routine */ void no_flush( struct fd *fd, struct event **event ) { @@ -2350,6 +2358,7 @@ DECL_HANDLER(set_completion_info) { fd->completion = get_completion_obj( current->process, req->chandle, IO_COMPLETION_MODIFY_STATE ); fd->comp_key = req->ckey; + fd->fd_ops->update_async( fd ); } else set_error( STATUS_INVALID_PARAMETER ); release_object( fd ); diff --git a/server/file.c b/server/file.c index 02a1e37..83634c5 100644 --- a/server/file.c +++ b/server/file.c @@ -102,7 +102,8 @@ static const struct fd_ops file_fd_ops = default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; static inline int is_overlapped( const struct file *file ) diff --git a/server/file.h b/server/file.h index ead356d..bb3c420 100644 --- a/server/file.h +++ b/server/file.h @@ -48,6 +48,8 @@ struct fd_ops void (*reselect_async)( struct fd *, struct async_queue *queue ); /* cancel an async operation */ void (*cancel_async)(struct fd *, struct process *process, struct thread *thread, client_ptr_t iosb); + /* update an async operation to correspond to changes in the file object */ + void (*update_async)(struct fd *); }; /* file descriptor functions */ @@ -92,6 +94,7 @@ extern void no_fd_queue_async( struct fd *fd, const async_data_t *data, int type extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern void default_fd_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); +extern void default_fd_update_async( struct fd *fd ); extern void no_flush( struct fd *fd, struct event **event ); extern void main_loop(void); extern void remove_process_locks( struct process *process ); @@ -164,6 +167,7 @@ extern void async_terminate( struct async *async, unsigned int status ); extern int async_wake_up_by( struct async_queue *queue, struct process *process, struct thread *thread, client_ptr_t iosb, unsigned int status ); extern void async_wake_up( struct async_queue *queue, unsigned int status ); +extern void async_update( struct async_queue *queue ); extern struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key ); extern void fd_copy_completion( struct fd *src, struct fd *dst ); diff --git a/server/mailslot.c b/server/mailslot.c index 051f0ad..b29c168 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -102,7 +102,8 @@ static const struct fd_ops mailslot_fd_ops = default_fd_ioctl, /* ioctl */ mailslot_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; @@ -152,7 +153,8 @@ static const struct fd_ops mail_writer_fd_ops = default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; @@ -202,7 +204,8 @@ static const struct fd_ops mailslot_device_fd_ops = default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; static void mailslot_destroy( struct object *obj) diff --git a/server/mapping.c b/server/mapping.c index 90956e9..60e9c5f 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -103,7 +103,8 @@ static const struct fd_ops mapping_fd_ops = no_fd_ioctl, /* ioctl */ no_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; static struct list shared_list = LIST_INIT(shared_list); diff --git a/server/named_pipe.c b/server/named_pipe.c index 590adca..2bd3827 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -173,6 +173,7 @@ static const struct fd_ops pipe_server_fd_ops = default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; /* client end functions */ @@ -212,7 +213,8 @@ static const struct fd_ops pipe_client_fd_ops = default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; static void named_pipe_device_dump( struct object *obj, int verbose ); @@ -256,7 +258,8 @@ static const struct fd_ops named_pipe_device_fd_ops = named_pipe_device_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; static void named_pipe_dump( struct object *obj, int verbose ) diff --git a/server/serial.c b/server/serial.c index 587fee1..57ba51c 100644 --- a/server/serial.c +++ b/server/serial.c @@ -112,7 +112,8 @@ static const struct fd_ops serial_fd_ops = default_fd_ioctl, /* ioctl */ serial_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_update_async /* update_async */ }; /* check if the given fd is a serial port */ diff --git a/server/signal.c b/server/signal.c index 5e4fe33..79dee43 100644 --- a/server/signal.c +++ b/server/signal.c @@ -90,7 +90,8 @@ static const struct fd_ops handler_fd_ops = NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ - NULL /* cancel_async */ + NULL, /* cancel_async */ + NULL /* update_async */ }; static struct handler *handler_sighup; diff --git a/server/sock.c b/server/sock.c index 7e4acd8..7d21a1e 100644 --- a/server/sock.c +++ b/server/sock.c @@ -119,6 +119,7 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ); static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); +static void sock_update_async( struct fd *fd ); static int sock_get_ntstatus( int err ); static int sock_get_error( int err ); @@ -153,7 +154,8 @@ static const struct fd_ops sock_fd_ops = default_fd_ioctl, /* ioctl */ sock_queue_async, /* queue_async */ sock_reselect_async, /* reselect_async */ - sock_cancel_async /* cancel_async */ + sock_cancel_async, /* cancel_async */ + sock_update_async /* update_async */ }; @@ -573,6 +575,15 @@ static void sock_cancel_async( struct fd *fd, struct process *process, struct th set_error( STATUS_NOT_FOUND ); } +static void sock_update_async( struct fd *fd ) +{ + struct sock *sock = get_fd_user( fd ); + assert( sock->obj.ops == &sock_ops ); + + async_update( sock->read_q ); + async_update( sock->write_q ); +} + static struct fd *sock_get_fd( struct object *obj ) { struct sock *sock = (struct sock *)obj; diff --git a/server/thread.c b/server/thread.c index f9a575e..3ee9486 100644 --- a/server/thread.c +++ b/server/thread.c @@ -157,7 +157,8 @@ static const struct fd_ops thread_fd_ops = NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ - NULL /* cancel_async */ + NULL, /* cancel_async */ + NULL /* update_async */ }; static struct list thread_list = LIST_INIT(thread_list); -- 1.7.5.4