From aafcfe766340201fb28cd047bb219d95de3ae13a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 8 May 2007 20:45:44 +0200 Subject: [PATCH] server: Add support for retrieving results of queued ioctls once they are done. --- dlls/ntdll/file.c | 38 ++++++++++++++++++++++++++++++++++++-- include/wine/server_protocol.h | 19 ++++++++++++++++++- server/device.c | 40 ++++++++++++++++++++++++++++++++++++++++ server/protocol.def | 9 +++++++++ server/request.h | 2 ++ server/trace.c | 15 +++++++++++++++ 6 files changed, 120 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 6912350ada6..4936bb241ae 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -918,10 +918,35 @@ done: } +struct async_ioctl +{ + HANDLE handle; /* handle to the device */ + void *buffer; /* buffer for output */ + ULONG size; /* size of buffer */ +}; + /* callback for ioctl async I/O completion */ static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status ) { - io->u.Status = status; + struct async_ioctl *async = arg; + + if (status == STATUS_ALERTED) + { + SERVER_START_REQ( get_ioctl_result ) + { + req->handle = async->handle; + req->user_arg = async; + wine_server_set_reply( req, async->buffer, async->size ); + if (!(status = wine_server_call( req ))) + io->Information = wine_server_reply_size( reply ); + } + SERVER_END_REQ; + } + if (status != STATUS_PENDING) + { + RtlFreeHeap( GetProcessHeap(), 0, async ); + io->u.Status = status; + } return status; } @@ -932,17 +957,24 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, PVOID in_buffer, ULONG in_size, PVOID out_buffer, ULONG out_size ) { + struct async_ioctl *async; NTSTATUS status; HANDLE wait_handle; ULONG options; + if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) ))) + return STATUS_NO_MEMORY; + async->handle = handle; + async->buffer = out_buffer; + async->size = out_size; + SERVER_START_REQ( ioctl ) { req->handle = handle; req->code = code; req->async.callback = ioctl_completion; req->async.iosb = io; - req->async.arg = NULL; + req->async.arg = async; req->async.apc = apc; req->async.apc_arg = apc_context; req->async.event = event; @@ -959,6 +991,8 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n", code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); + if (status != STATUS_PENDING) RtlFreeHeap( GetProcessHeap(), 0, async ); + if (wait_handle) { NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e9bb0982970..99f9f8218f1 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2684,6 +2684,20 @@ struct ioctl_reply +struct get_ioctl_result_request +{ + struct request_header __header; + obj_handle_t handle; + void* user_arg; +}; +struct get_ioctl_result_reply +{ + struct reply_header __header; + /* VARARG(out_data,bytes); */ +}; + + + struct create_named_pipe_request { struct request_header __header; @@ -4172,6 +4186,7 @@ enum request REQ_register_async, REQ_cancel_async, REQ_ioctl, + REQ_get_ioctl_result, REQ_create_named_pipe, REQ_get_named_pipe_info, REQ_create_window, @@ -4397,6 +4412,7 @@ union generic_request struct register_async_request register_async_request; struct cancel_async_request cancel_async_request; struct ioctl_request ioctl_request; + struct get_ioctl_result_request get_ioctl_result_request; struct create_named_pipe_request create_named_pipe_request; struct get_named_pipe_info_request get_named_pipe_info_request; struct create_window_request create_window_request; @@ -4620,6 +4636,7 @@ union generic_reply struct register_async_reply register_async_reply; struct cancel_async_reply cancel_async_reply; struct ioctl_reply ioctl_reply; + struct get_ioctl_result_reply get_ioctl_result_reply; struct create_named_pipe_reply create_named_pipe_reply; struct get_named_pipe_info_reply get_named_pipe_info_reply; struct create_window_reply create_window_reply; @@ -4705,6 +4722,6 @@ union generic_reply struct get_next_device_request_reply get_next_device_request_reply; }; -#define SERVER_PROTOCOL_VERSION 302 +#define SERVER_PROTOCOL_VERSION 303 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/device.c b/server/device.c index b811ff12960..c52cd221468 100644 --- a/server/device.c +++ b/server/device.c @@ -269,6 +269,18 @@ static enum server_fd_type device_get_fd_type( struct fd *fd ) return FD_TYPE_DEVICE; } +static struct ioctl_call *find_ioctl_call( struct device *device, struct thread *thread, + void *user_arg ) +{ + struct ioctl_call *ioctl; + + LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry ) + if (ioctl->thread == thread && ioctl->user_arg == user_arg) return ioctl; + + set_error( STATUS_INVALID_PARAMETER ); + return NULL; +} + static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, const void *data, data_size_t size ) { @@ -488,3 +500,31 @@ DECL_HANDLER(get_next_device_request) release_object( manager ); } + + +/* retrieve results of an async ioctl */ +DECL_HANDLER(get_ioctl_result) +{ + struct device *device; + struct ioctl_call *ioctl; + + if (!(device = (struct device *)get_handle_obj( current->process, req->handle, 0, &device_ops ))) + return; + + if ((ioctl = find_ioctl_call( device, current, req->user_arg ))) + { + if (ioctl->out_data) + { + data_size_t size = min( ioctl->out_size, get_reply_max_size() ); + if (size) + { + set_reply_data_ptr( ioctl->out_data, size ); + ioctl->out_data = NULL; + } + } + set_error( ioctl->status ); + list_remove( &ioctl->dev_entry ); + release_object( ioctl ); /* no longer on the device queue */ + } + release_object( device ); +} diff --git a/server/protocol.def b/server/protocol.def index 55055a41460..fb2d8cd84dd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1979,6 +1979,15 @@ enum message_type @END +/* Retrieve results of an async ioctl */ +@REQ(get_ioctl_result) + obj_handle_t handle; /* handle to the device */ + void* user_arg; /* user arg used to identify the request */ +@REPLY + VARARG(out_data,bytes); /* ioctl output data */ +@END + + /* Create a named pipe */ @REQ(create_named_pipe) unsigned int access; diff --git a/server/request.h b/server/request.h index 4f175a62aed..90a0c6c361f 100644 --- a/server/request.h +++ b/server/request.h @@ -245,6 +245,7 @@ DECL_HANDLER(set_serial_info); DECL_HANDLER(register_async); DECL_HANDLER(cancel_async); DECL_HANDLER(ioctl); +DECL_HANDLER(get_ioctl_result); DECL_HANDLER(create_named_pipe); DECL_HANDLER(get_named_pipe_info); DECL_HANDLER(create_window); @@ -469,6 +470,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_register_async, (req_handler)req_cancel_async, (req_handler)req_ioctl, + (req_handler)req_get_ioctl_result, (req_handler)req_create_named_pipe, (req_handler)req_get_named_pipe_info, (req_handler)req_create_window, diff --git a/server/trace.c b/server/trace.c index 7b8b7e425eb..8ae8d7307a8 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2424,6 +2424,18 @@ static void dump_ioctl_reply( const struct ioctl_reply *req ) dump_varargs_bytes( cur_size ); } +static void dump_get_ioctl_result_request( const struct get_ioctl_result_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " user_arg=%p", req->user_arg ); +} + +static void dump_get_ioctl_result_reply( const struct get_ioctl_result_reply *req ) +{ + fprintf( stderr, " out_data=" ); + dump_varargs_bytes( cur_size ); +} + static void dump_create_named_pipe_request( const struct create_named_pipe_request *req ) { fprintf( stderr, " access=%08x,", req->access ); @@ -3650,6 +3662,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_register_async_request, (dump_func)dump_cancel_async_request, (dump_func)dump_ioctl_request, + (dump_func)dump_get_ioctl_result_request, (dump_func)dump_create_named_pipe_request, (dump_func)dump_get_named_pipe_info_request, (dump_func)dump_create_window_request, @@ -3871,6 +3884,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)0, (dump_func)dump_ioctl_reply, + (dump_func)dump_get_ioctl_result_reply, (dump_func)dump_create_named_pipe_reply, (dump_func)dump_get_named_pipe_info_reply, (dump_func)dump_create_window_reply, @@ -4092,6 +4106,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "register_async", "cancel_async", "ioctl", + "get_ioctl_result", "create_named_pipe", "get_named_pipe_info", "create_window", -- 2.11.4.GIT