From: Jacek Caban Subject: [PATCH 03/10] server: Use async object to transfer IRP result to client. Message-Id: <97b8512b-e314-aaf4-6a30-f5c3e0f6ab13@codeweavers.com> Date: Wed, 19 Oct 2016 19:05:13 +0200 Signed-off-by: Jacek Caban --- dlls/ntdll/file.c | 2 +- server/async.c | 21 +++++++++++++++++++ server/change.c | 3 ++- server/console.c | 3 ++- server/device.c | 58 ++++++----------------------------------------------- server/fd.c | 43 +++++++++++++++++++++++++++++++++++++++ server/file.c | 3 ++- server/file.h | 5 +++++ server/mailslot.c | 9 ++++++--- server/mapping.c | 3 ++- server/protocol.def | 19 +++++++++--------- server/serial.c | 3 ++- server/sock.c | 6 ++++-- 13 files changed, 105 insertions(+), 73 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index cefc1dd..ac8b765 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -420,7 +420,7 @@ static NTSTATUS irp_completion( void *user, IO_STATUS_BLOCK *io, NTSTATUS status if (status == STATUS_ALERTED) { - SERVER_START_REQ( get_irp_result ) + SERVER_START_REQ( get_async_result ) { req->handle = wine_server_obj_handle( async->io.handle ); req->user_arg = wine_server_client_ptr( async ); diff --git a/server/async.c b/server/async.c index 733558d..707bab5 100644 --- a/server/async.c +++ b/server/async.c @@ -170,6 +170,7 @@ void async_terminate( struct async *async, unsigned int status ) } async->status = status; + if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; if (async->data.callback) { @@ -426,3 +427,23 @@ void release_iosb( struct iosb *iosb ) free( iosb->out_data ); free( iosb ); } + +/* get iosb from async */ +struct iosb *async_get_iosb( struct async *async ) +{ + return grab_iosb(async->iosb); +} + +/* find async associated with client-side async */ +struct async *find_async( struct async_queue *queue, struct process *process, client_ptr_t client_async ) +{ + struct async *async; + + if (!queue) return NULL; + + LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry ) + if (async->thread->process == process && async->data.arg == client_async) + return async; + + return NULL; +} diff --git a/server/change.c b/server/change.c index 23d4ac8..7df4dd9 100644 --- a/server/change.c +++ b/server/change.c @@ -190,7 +190,8 @@ static const struct fd_ops dir_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_find_async /* find_async */ }; static struct list change_list = LIST_INIT(change_list); diff --git a/server/console.c b/server/console.c index 32d3137..62ab93f 100644 --- a/server/console.c +++ b/server/console.c @@ -194,7 +194,8 @@ static const struct fd_ops console_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_find_async /* find_async */ }; static struct list screen_buffer_list = LIST_INIT(screen_buffer_list); diff --git a/server/device.c b/server/device.c index 6a05c06..132457c 100644 --- a/server/device.c +++ b/server/device.c @@ -216,7 +216,8 @@ static const struct fd_ops device_file_fd_ops = device_file_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_find_async /* find_async */ }; @@ -281,6 +282,7 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, struct iosb *iosb = irp->iosb; if (!file) return; /* already finished */ + irp->file = NULL; /* FIXME: handle the STATUS_PENDING case */ iosb->status = status; @@ -288,7 +290,6 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, iosb->out_size = min( iosb->out_size, out_size ); if (iosb->out_size && !(iosb->out_data = memdup( out_data, iosb->out_size ))) iosb->out_size = 0; - irp->file = NULL; if (irp->async) { if (result) status = STATUS_ALERTED; @@ -298,13 +299,9 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, } wake_up( &irp->obj, 0 ); - if (status != STATUS_ALERTED) - { - /* remove it from the device queue */ - /* (for STATUS_ALERTED this will be done in get_irp_result) */ - list_remove( &irp->dev_entry ); - release_object( irp ); /* no longer on the device queue */ - } + /* remove it from the device queue */ + list_remove( &irp->dev_entry ); + release_object( irp ); /* no longer on the device queue */ release_object( file ); } @@ -444,18 +441,6 @@ static void device_file_destroy( struct object *obj ) release_object( file->device ); } -static struct irp_call *find_irp_call( struct device_file *file, struct thread *thread, - client_ptr_t user_arg ) -{ - struct irp_call *irp; - - LIST_FOR_EACH_ENTRY( irp, &file->requests, struct irp_call, dev_entry ) - if (irp->thread == thread && irp->user_arg == user_arg) return irp; - - set_error( STATUS_INVALID_PARAMETER ); - return NULL; -} - static void set_file_user_ptr( struct device_file *file, client_ptr_t ptr ) { struct irp_call *irp; @@ -809,34 +794,3 @@ DECL_HANDLER(set_irp_result) release_object( irp ); } } - - -/* retrieve results of an async irp */ -DECL_HANDLER(get_irp_result) -{ - struct device_file *file; - struct irp_call *irp; - - if (!(file = (struct device_file *)get_handle_obj( current->process, req->handle, - 0, &device_file_ops ))) - return; - - if ((irp = find_irp_call( file, current, req->user_arg ))) - { - struct iosb *iosb = irp->iosb; - if (iosb->out_data) - { - data_size_t size = min( iosb->out_size, get_reply_max_size() ); - if (size) - { - set_reply_data_ptr( iosb->out_data, size ); - iosb->out_data = NULL; - } - } - reply->size = iosb->result; - set_error( iosb->status ); - list_remove( &irp->dev_entry ); - release_object( irp ); /* no longer on the device queue */ - } - release_object( file ); -} diff --git a/server/fd.c b/server/fd.c index 0e54206..b66936e 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2126,6 +2126,17 @@ int default_fd_cancel_async( struct fd *fd, struct process *process, struct thre return n; } +/* default find_async() fd routine */ +struct async *default_fd_find_async( struct fd *fd, struct process *process, client_ptr_t client_async ) +{ + struct async *async; + + async = find_async( fd->wait_q, process, client_async); + if (!async) async = find_async( fd->read_q, process, client_async ); + if (!async) async = find_async( fd->write_q, process, client_async ); + return async; +} + static inline int is_valid_mounted_device( struct stat *st ) { #if defined(linux) || defined(__sun__) @@ -2533,6 +2544,38 @@ DECL_HANDLER(cancel_async) } } +/* get async result from associated iosb */ +DECL_HANDLER(get_async_result) +{ + struct iosb *iosb = NULL; + struct async *async; + struct fd *fd; + + if (!(fd = get_handle_fd_obj( current->process, req->handle, 0 ))) return; + + async = fd->fd_ops->find_async( fd, current->process, req->user_arg ); + if (async) iosb = async_get_iosb( async ); + + if (iosb) + { + if (iosb->out_data) + { + data_size_t size = min( iosb->out_size, get_reply_max_size() ); + if (size) + { + set_reply_data_ptr( iosb->out_data, size ); + iosb->out_data = NULL; + } + } + reply->size = iosb->result; + set_error( iosb->status ); + release_iosb( iosb ); + } + else set_error( STATUS_INVALID_PARAMETER ); + + release_object(fd); +} + /* attach completion object to a fd */ DECL_HANDLER(set_completion_info) { diff --git a/server/file.c b/server/file.c index dacb24a..578e7a0 100644 --- a/server/file.c +++ b/server/file.c @@ -110,7 +110,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_find_async /* find_async */ }; static inline int is_overlapped( const struct file *file ) diff --git a/server/file.h b/server/file.h index c0a53a2..75a2e03 100644 --- a/server/file.h +++ b/server/file.h @@ -53,6 +53,8 @@ struct fd_ops void (*reselect_async)( struct fd *, struct async_queue *queue ); /* cancel an async operation */ int (*cancel_async)(struct fd *, struct process *process, struct thread *thread, client_ptr_t iosb); + /* find an async operation in queues */ + struct async *(*find_async)( struct fd *fd, struct process *process, client_ptr_t client_async ); }; /* server-side representation of I/O status block */ @@ -112,6 +114,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 int default_fd_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); +extern struct async *default_fd_find_async( struct fd *fd, struct process *process, client_ptr_t client_async ); extern void main_loop(void); extern void remove_process_locks( struct process *process ); @@ -189,12 +192,14 @@ extern int async_waiting( struct async_queue *queue ); 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 struct async *find_async( struct async_queue *queue, struct process *process, client_ptr_t client_async ); extern void async_wake_up( struct async_queue *queue, unsigned int status ); 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 ); extern struct iosb *alloc_iosb( const void *in_data, data_size_t in_size, data_size_t out_size ); extern struct iosb *grab_iosb( struct iosb *iosb ); extern void release_iosb( struct iosb *iosb ); +extern struct iosb *async_get_iosb( struct async *async ); /* access rights that require Unix read permission */ #define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA) diff --git a/server/mailslot.c b/server/mailslot.c index 2757028..eeff792 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -107,7 +107,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_find_async /* find_async */ }; @@ -161,7 +162,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_find_async /* find_async */ }; @@ -215,7 +217,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_find_async /* find_async */ }; static void mailslot_destroy( struct object *obj) diff --git a/server/mapping.c b/server/mapping.c index f82907b..eb36508 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -109,7 +109,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_find_async /* find_async */ }; static struct list shared_list = LIST_INIT(shared_list); diff --git a/server/protocol.def b/server/protocol.def index 8d86737..ddb49bd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2349,6 +2349,15 @@ enum message_type int only_thread; /* cancel matching this thread */ @END +/* Retrieve results of an async */ +@REQ(get_async_result) + obj_handle_t handle; /* handle to the object */ + client_ptr_t user_arg; /* user arg used to identify async */ +@REPLY + data_size_t size; /* result size (input or output depending on the operation) */ + VARARG(out_data,bytes); /* iosb output data */ +@END + /* Perform a read on a file object */ @REQ(read) @@ -2398,16 +2407,6 @@ enum message_type @END -/* Retrieve results of an async irp */ -@REQ(get_irp_result) - obj_handle_t handle; /* handle to the device */ - client_ptr_t user_arg; /* user arg used to identify the request */ -@REPLY - data_size_t size; /* result size (input or output depending on the operation) */ - VARARG(out_data,bytes); /* irp output data */ -@END - - /* Create a named pipe */ @REQ(create_named_pipe) unsigned int access; diff --git a/server/serial.c b/server/serial.c index c3cd43d..52fcb62 100644 --- a/server/serial.c +++ b/server/serial.c @@ -121,7 +121,8 @@ static const struct fd_ops serial_fd_ops = default_fd_ioctl, /* ioctl */ serial_queue_async, /* queue_async */ serial_reselect_async, /* reselect_async */ - default_fd_cancel_async /* cancel_async */ + default_fd_cancel_async, /* cancel_async */ + default_fd_find_async /* find_async */ }; /* check if the given fd is a serial port */ diff --git a/server/sock.c b/server/sock.c index eb84cc5..e39215d 100644 --- a/server/sock.c +++ b/server/sock.c @@ -171,7 +171,8 @@ static const struct fd_ops sock_fd_ops = sock_ioctl, /* ioctl */ sock_queue_async, /* queue_async */ sock_reselect_async, /* reselect_async */ - sock_cancel_async /* cancel_async */ + sock_cancel_async, /* cancel_async */ + default_fd_find_async /* find_async */ }; @@ -1017,7 +1018,8 @@ static const struct fd_ops ifchange_fd_ops = no_fd_ioctl, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ - NULL /* cancel_async */ + NULL, /* cancel_async */ + NULL /* find_async */ }; static void ifchange_dump( struct object *obj, int verbose )