We still don't quite handle this completely correctly, but we should at least avoid crashing the server due to a failed assertion.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/async.c | 2 -- server/device.c | 1 - 2 files changed, 3 deletions(-)
diff --git a/server/async.c b/server/async.c index 1c3082083ed..b414604fcd4 100644 --- a/server/async.c +++ b/server/async.c @@ -156,8 +156,6 @@ static void async_destroy( struct object *obj ) /* notifies client thread of new status of its async request */ void async_terminate( struct async *async, unsigned int status ) { - assert( status != STATUS_PENDING ); - if (async->terminated) return;
async->terminated = 1; diff --git a/server/device.c b/server/device.c index b669921a003..ef93a0a9024 100644 --- a/server/device.c +++ b/server/device.c @@ -386,7 +386,6 @@ static void set_irp_result( struct irp_call *irp, unsigned int status,
if (!file) return; /* already finished */
- /* FIXME: handle the STATUS_PENDING case */ iosb->status = status; iosb->result = result; iosb->out_size = min( iosb->out_size, out_size );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/async.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/server/async.c b/server/async.c index b414604fcd4..5deaf04d686 100644 --- a/server/async.c +++ b/server/async.c @@ -390,14 +390,11 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
assert( async->terminated ); /* it must have been woken up if we get a result */
- if (status == STATUS_PENDING) /* restart it */ + if (async->alerted && status == STATUS_PENDING) /* restart it */ { - if (async->alerted) - { - async->terminated = 0; - async->alerted = 0; - async_reselect( async ); - } + async->terminated = 0; + async->alerted = 0; + async_reselect( async ); } else {
From: Zebediah Figura z.figura12@gmail.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/async.c | 54 ++++++++++++++++++++++++------------------------- server/device.c | 36 +++++++++++++++++---------------- server/file.h | 1 - 3 files changed, 46 insertions(+), 45 deletions(-)
diff --git a/server/async.c b/server/async.c index 5deaf04d686..d45f234144d 100644 --- a/server/async.c +++ b/server/async.c @@ -282,32 +282,6 @@ void set_async_pending( struct async *async, int signal ) } }
-/* create an async associated with iosb for async-based requests - * returned async must be passed to async_handoff */ -struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data ) -{ - struct async *async; - struct iosb *iosb; - - if (!(iosb = create_iosb( get_req_data(), get_req_data_size(), get_reply_max_size() ))) - return NULL; - - async = create_async( fd, current, data, iosb ); - release_object( iosb ); - if (async) - { - if (!(async->wait_handle = alloc_handle( current->process, async, SYNCHRONIZE, 0 ))) - { - release_object( async ); - return NULL; - } - async->pending = 0; - async->direct_result = 1; - async->comp_flags = comp_flags; - } - return async; -} - /* return async object status and wait handle to client */ obj_handle_t async_handoff( struct async *async, int success, data_size_t *result, int force_blocking ) { @@ -536,7 +510,7 @@ static void iosb_destroy( struct object *obj ) }
/* allocate iosb struct */ -struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size ) +static struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size ) { struct iosb *iosb;
@@ -558,6 +532,32 @@ struct iosb *create_iosb( const void *in_data, data_size_t in_size, data_size_t return iosb; }
+/* create an async associated with iosb for async-based requests + * returned async must be passed to async_handoff */ +struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data ) +{ + struct async *async; + struct iosb *iosb; + + if (!(iosb = create_iosb( get_req_data(), get_req_data_size(), get_reply_max_size() ))) + return NULL; + + async = create_async( fd, current, data, iosb ); + release_object( iosb ); + if (async) + { + if (!(async->wait_handle = alloc_handle( current->process, async, SYNCHRONIZE, 0 ))) + { + release_object( async ); + return NULL; + } + async->pending = 0; + async->direct_result = 1; + async->comp_flags = comp_flags; + } + return async; +} + struct iosb *async_get_iosb( struct async *async ) { return async->iosb ? (struct iosb *)grab_object( async->iosb ) : NULL; diff --git a/server/device.c b/server/device.c index ef93a0a9024..a89c03f0fb0 100644 --- a/server/device.c +++ b/server/device.c @@ -369,11 +369,6 @@ static struct irp_call *create_irp( struct device_file *file, const irp_params_t irp->user_ptr = 0;
if (async) irp->iosb = async_get_iosb( async ); - if (!irp->iosb && !(irp->iosb = create_iosb( NULL, 0, 0 ))) - { - release_object( irp ); - irp = NULL; - } } return irp; } @@ -382,21 +377,22 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, const void *out_data, data_size_t out_size, data_size_t result ) { struct device_file *file = irp->file; - struct iosb *iosb = irp->iosb;
if (!file) return; /* already finished */
- iosb->status = status; - iosb->result = result; - 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; - /* remove it from the device queue */ list_remove( &irp->dev_entry ); irp->file = NULL; if (irp->async) { + struct iosb *iosb = irp->iosb; + + iosb->status = status; + iosb->result = result; + 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; + if (result) status = STATUS_ALERTED; async_terminate( irp->async, status ); release_object( irp->async ); @@ -993,15 +989,21 @@ DECL_HANDLER(get_next_device_request) reply->client_tid = get_thread_id( thread );
iosb = irp->iosb; - reply->in_size = iosb->in_size; - if (iosb->in_size > get_reply_max_size()) set_error( STATUS_BUFFER_OVERFLOW ); + if (iosb) + reply->in_size = iosb->in_size; + + if (iosb && iosb->in_size > get_reply_max_size()) + set_error( STATUS_BUFFER_OVERFLOW ); else if (!irp->file || (reply->next = alloc_handle( current->process, irp, 0, 0 ))) { if (fill_irp_params( manager, irp, &reply->params )) { - set_reply_data_ptr( iosb->in_data, iosb->in_size ); - iosb->in_data = NULL; - iosb->in_size = 0; + if (iosb) + { + set_reply_data_ptr( iosb->in_data, iosb->in_size ); + iosb->in_data = NULL; + iosb->in_size = 0; + } list_remove( &irp->mgr_entry ); list_init( &irp->mgr_entry ); /* we already own the object if it's only on manager queue */ diff --git a/server/file.h b/server/file.h index 10b5c0d0493..f6c5832a733 100644 --- a/server/file.h +++ b/server/file.h @@ -230,7 +230,6 @@ extern void async_terminate( struct async *async, unsigned int status ); 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 *create_iosb( const void *in_data, data_size_t in_size, data_size_t out_size ); extern struct iosb *async_get_iosb( struct async *async ); extern struct thread *async_get_thread( struct async *async ); extern struct async *find_pending_async( struct async_queue *queue );
For convenience, and to centralize the STATUS_ALERTED logic into one place.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/async.c | 29 +++++++++++ server/console.c | 51 +++++++------------ server/device.c | 14 ++--- server/file.h | 2 + server/named_pipe.c | 4 +- server/sock.c | 121 +++++++++++++++++++------------------------- 6 files changed, 105 insertions(+), 116 deletions(-)
diff --git a/server/async.c b/server/async.c index d45f234144d..e71dceb201b 100644 --- a/server/async.c +++ b/server/async.c @@ -332,6 +332,35 @@ obj_handle_t async_handoff( struct async *async, int success, data_size_t *resul return async->wait_handle; }
+/* complete a request-based async with a pre-allocated buffer */ +void async_request_complete( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, void *out_data ) +{ + struct iosb *iosb = async_get_iosb( async ); + + /* the async may have already been canceled */ + if (iosb->status != STATUS_PENDING) + { + release_object( iosb ); + free( out_data ); + return; + } + + iosb->status = status; + iosb->result = result; + iosb->out_data = out_data; + iosb->out_size = out_size; + + release_object( iosb ); + + /* if the result is nonzero or there is output data, the client needs to + * make an extra request to retrieve them; use STATUS_ALERTED to signal + * this case */ + if (result || out_data) + status = STATUS_ALERTED; + async_terminate( async, status ); +} + /* set the timeout of an async operation */ void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ) { diff --git a/server/console.c b/server/console.c index 1e6f6c0f8a3..94f7c37e7c5 100644 --- a/server/console.c +++ b/server/console.c @@ -976,7 +976,6 @@ static int console_flush( struct fd *fd, struct async *async ) static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t pos ) { struct screen_buffer *screen_buffer = get_fd_user( fd ); - struct iosb *iosb;
if (!screen_buffer->input || !screen_buffer->input->server) { @@ -984,16 +983,8 @@ static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t p return 0; }
- if (!queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE, - screen_buffer->id, async, &screen_buffer->ioctl_q )) - return 0; - - /* we can't use default async handling, because write result is not - * compatible with ioctl result */ - iosb = async_get_iosb( async ); - iosb->result = iosb->in_size; - release_object( iosb ); - return 1; + return queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE, + screen_buffer->id, async, &screen_buffer->ioctl_q ); }
static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) @@ -1498,36 +1489,28 @@ DECL_HANDLER(get_next_console_request)
if (ioctl) { + struct async *async = ioctl->async; unsigned int status = req->status; + if (status == STATUS_PENDING) status = STATUS_INVALID_PARAMETER; - if (ioctl->async) + if (async) { - iosb = async_get_iosb( ioctl->async ); + iosb = async_get_iosb( async ); if (iosb->status == STATUS_PENDING) { - iosb->status = status; - iosb->out_size = min( iosb->out_size, get_req_data_size() ); - if (iosb->out_size) - { - if ((iosb->out_data = memdup( get_req_data(), iosb->out_size ))) - { - iosb->result = iosb->out_size; - } - else if (!status) - { - iosb->status = STATUS_NO_MEMORY; - iosb->out_size = 0; - } - } - if (iosb->result) status = STATUS_ALERTED; - } - else - { - release_object( ioctl->async ); - ioctl->async = NULL; + data_size_t out_size = min( iosb->out_size, get_req_data_size() ); + data_size_t result = ioctl->code == IOCTL_CONDRV_WRITE_FILE ? iosb->in_size : out_size; + void *out_data; + + if (!out_size || (out_data = memdup( get_req_data(), out_size ))) + async_request_complete( async, status, result, out_size, out_data ); + else + async_terminate( async, STATUS_NO_MEMORY ); } + + release_object( async ); } - console_host_ioctl_terminate( ioctl, status ); + free( ioctl ); if (iosb) release_object( iosb );
if (req->read) diff --git a/server/device.c b/server/device.c index a89c03f0fb0..96389a1459b 100644 --- a/server/device.c +++ b/server/device.c @@ -385,16 +385,12 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, irp->file = NULL; if (irp->async) { - struct iosb *iosb = irp->iosb; + void *out_data;
- iosb->status = status; - iosb->result = result; - 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; - - if (result) status = STATUS_ALERTED; - async_terminate( irp->async, status ); + out_size = min( irp->iosb->out_size, out_size ); + if (out_size && !(out_data = memdup( out_data, out_size ))) + out_size = 0; + async_request_complete( irp->async, status, result, out_size, out_data ); release_object( irp->async ); irp->async = NULL; } diff --git a/server/file.h b/server/file.h index f6c5832a733..1c019a0667e 100644 --- a/server/file.h +++ b/server/file.h @@ -227,6 +227,8 @@ extern void async_set_completion_callback( struct async *async, async_completion extern void set_async_pending( struct async *async, int signal ); extern int async_waiting( struct async_queue *queue ); extern void async_terminate( struct async *async, unsigned int status ); +extern void async_request_complete( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, void *out_data ); 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 ); diff --git a/server/named_pipe.c b/server/named_pipe.c index df8c7e3170c..da3485dd2bc 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -390,9 +390,7 @@ static void wake_message( struct pipe_message *message, data_size_t result ) message->async = NULL; if (!async) return;
- message->iosb->status = STATUS_SUCCESS; - message->iosb->result = result; - async_terminate( async, message->iosb->result ? STATUS_ALERTED : STATUS_SUCCESS ); + async_request_complete( async, STATUS_SUCCESS, result, 0, NULL ); release_object( async ); }
diff --git a/server/sock.c b/server/sock.c index 50bfc08e145..00d5d47edff 100644 --- a/server/sock.c +++ b/server/sock.c @@ -623,7 +623,8 @@ static void free_accept_req( void *private )
static void fill_accept_output( struct accept_req *req ) { - struct iosb *iosb = req->iosb; + const data_size_t out_size = req->iosb->out_size; + struct async *async = req->async; union unix_sockaddr unix_addr; struct WS_sockaddr *win_addr; unsigned int remote_len; @@ -632,7 +633,11 @@ static void fill_accept_output( struct accept_req *req ) char *out_data; int win_len;
- if (!(out_data = mem_alloc( iosb->out_size ))) return; + if (!(out_data = mem_alloc( out_size ))) + { + async_terminate( async, get_error() ); + return; + }
fd = get_unix_fd( req->acceptsock->fd );
@@ -642,11 +647,10 @@ static void fill_accept_output( struct accept_req *req ) { req->accepted = 1; sock_reselect( req->acceptsock ); - set_error( STATUS_PENDING ); return; }
- set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } @@ -655,7 +659,7 @@ static void fill_accept_output( struct accept_req *req ) { if (req->local_len < sizeof(int)) { - set_error( STATUS_BUFFER_TOO_SMALL ); + async_terminate( async, STATUS_BUFFER_TOO_SMALL ); free( out_data ); return; } @@ -665,7 +669,7 @@ static void fill_accept_output( struct accept_req *req ) if (getsockname( fd, &unix_addr.addr, &unix_len ) < 0 || (win_len = sockaddr_from_unix( &unix_addr, win_addr, req->local_len - sizeof(int) )) < 0) { - set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } @@ -674,20 +678,17 @@ static void fill_accept_output( struct accept_req *req )
unix_len = sizeof(unix_addr); win_addr = (struct WS_sockaddr *)(out_data + req->recv_len + req->local_len + sizeof(int)); - remote_len = iosb->out_size - req->recv_len - req->local_len; + remote_len = out_size - req->recv_len - req->local_len; if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0 || (win_len = sockaddr_from_unix( &unix_addr, win_addr, remote_len - sizeof(int) )) < 0) { - set_error( sock_get_ntstatus( errno ) ); + async_terminate( async, sock_get_ntstatus( errno ) ); free( out_data ); return; } memcpy( out_data + req->recv_len + req->local_len, &win_len, sizeof(int) );
- iosb->status = STATUS_SUCCESS; - iosb->result = size; - iosb->out_data = out_data; - set_error( STATUS_ALERTED ); + async_request_complete( req->async, STATUS_SUCCESS, size, out_size, out_data ); }
static void complete_async_accept( struct sock *sock, struct accept_req *req ) @@ -699,27 +700,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req )
if (acceptsock) { - if (!accept_into_socket( sock, acceptsock )) return; + if (!accept_into_socket( sock, acceptsock )) + { + async_terminate( async, get_error() ); + return; + } fill_accept_output( req ); } else { - struct iosb *iosb = req->iosb; obj_handle_t handle; + void *out_data;
- if (!(acceptsock = accept_socket( sock ))) return; + if (!(acceptsock = accept_socket( sock ))) + { + async_terminate( async, get_error() ); + return; + } handle = alloc_handle_no_access_check( async_get_thread( async )->process, &acceptsock->obj, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT ); acceptsock->wparam = handle; release_object( acceptsock ); - if (!handle) return; + if (!handle) + { + async_terminate( async, get_error() ); + return; + }
- if (!(iosb->out_data = malloc( sizeof(handle) ))) return; + if (!(out_data = malloc( sizeof(handle) ))) return;
- iosb->status = STATUS_SUCCESS; - iosb->out_size = sizeof(handle); - memcpy( iosb->out_data, &handle, sizeof(handle) ); - set_error( STATUS_ALERTED ); + memcpy( out_data, &handle, sizeof(handle) ); + async_request_complete( req->async, STATUS_SUCCESS, 0, sizeof(handle), out_data ); } }
@@ -747,7 +758,6 @@ static void complete_async_connect( struct sock *sock ) { struct connect_req *req = sock->connect_req; const char *in_buffer; - struct iosb *iosb; size_t len; int ret;
@@ -757,28 +767,20 @@ static void complete_async_connect( struct sock *sock )
if (!req->send_len) { - set_error( STATUS_SUCCESS ); + async_terminate( req->async, STATUS_SUCCESS ); return; }
- iosb = req->iosb; - in_buffer = (const char *)iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len; + in_buffer = (const char *)req->iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len; len = req->send_len - req->send_cursor;
ret = send( get_unix_fd( sock->fd ), in_buffer + req->send_cursor, len, 0 ); if (ret < 0 && errno != EWOULDBLOCK) - set_error( sock_get_ntstatus( errno ) ); + async_terminate( req->async, sock_get_ntstatus( errno ) ); else if (ret == len) - { - iosb->result = req->send_len; - iosb->status = STATUS_SUCCESS; - set_error( STATUS_ALERTED ); - } + async_request_complete( req->async, STATUS_SUCCESS, req->send_len, 0, NULL ); else - { req->send_cursor += ret; - set_error( STATUS_PENDING ); - } }
static void free_poll_req( void *private ) @@ -840,10 +842,9 @@ static void complete_async_polls( struct sock *sock, int event, int error )
LIST_FOR_EACH_ENTRY_SAFE( req, next, &poll_list, struct poll_req, entry ) { - struct iosb *iosb = req->iosb; unsigned int i;
- if (iosb->status != STATUS_PENDING) continue; + if (req->iosb->status != STATUS_PENDING) continue;
for (i = 0; i < req->count; ++i) { @@ -857,10 +858,8 @@ static void complete_async_polls( struct sock *sock, int event, int error ) req->output[i].flags = req->sockets[i].flags & flags; req->output[i].status = sock_get_ntstatus( error );
- iosb->status = STATUS_SUCCESS; - iosb->out_data = req->output; - iosb->out_size = req->count * sizeof(*req->output); - async_terminate( req->async, STATUS_ALERTED ); + async_request_complete( req->async, STATUS_SUCCESS, 0, + req->count * sizeof(*req->output), req->output ); break; } } @@ -869,16 +868,12 @@ static void complete_async_polls( struct sock *sock, int event, int error ) static void async_poll_timeout( void *private ) { struct poll_req *req = private; - struct iosb *iosb = req->iosb;
req->timeout = NULL;
- if (iosb->status != STATUS_PENDING) return; + if (req->iosb->status != STATUS_PENDING) return;
- iosb->status = STATUS_TIMEOUT; - iosb->out_data = req->output; - iosb->out_size = req->count * sizeof(*req->output); - async_terminate( req->async, STATUS_ALERTED ); + async_request_complete( req->async, STATUS_TIMEOUT, 0, req->count * sizeof(*req->output), req->output ); }
static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) @@ -892,26 +887,16 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error ) if (req->iosb->status == STATUS_PENDING && !req->accepted) { complete_async_accept( sock, req ); - if (get_error() != STATUS_PENDING) - async_terminate( req->async, get_error() ); break; } }
if (sock->accept_recv_req && sock->accept_recv_req->iosb->status == STATUS_PENDING) - { complete_async_accept_recv( sock->accept_recv_req ); - if (get_error() != STATUS_PENDING) - async_terminate( sock->accept_recv_req->async, get_error() ); - } }
if ((event & POLLOUT) && sock->connect_req && sock->connect_req->iosb->status == STATUS_PENDING) - { complete_async_connect( sock ); - if (get_error() != STATUS_PENDING) - async_terminate( sock->connect_req->async, get_error() ); - }
if (event & (POLLIN | POLLPRI) && async_waiting( &sock->read_q )) { @@ -1323,6 +1308,7 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h LIST_FOR_EACH_ENTRY_SAFE( poll_req, poll_next, &poll_list, struct poll_req, entry ) { struct iosb *iosb = poll_req->iosb; + BOOL signaled = FALSE; unsigned int i;
if (iosb->status != STATUS_PENDING) continue; @@ -1331,17 +1317,17 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h { if (poll_req->sockets[i].sock == sock) { - iosb->status = STATUS_SUCCESS; + signaled = TRUE; poll_req->output[i].flags = AFD_POLL_CLOSE; poll_req->output[i].status = 0; } }
- if (iosb->status != STATUS_PENDING) + if (signaled) { - iosb->out_data = poll_req->output; - iosb->out_size = poll_req->count * sizeof(*poll_req->output); - async_terminate( poll_req->async, STATUS_ALERTED ); + /* pass 0 as result; client will set actual result size */ + async_request_complete( poll_req->async, STATUS_SUCCESS, 0, + poll_req->count * sizeof(*poll_req->output), poll_req->output ); } } } @@ -2857,6 +2843,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t unsigned int count, const struct poll_socket_input *input ) { struct poll_socket_output *output; + BOOL signaled = FALSE; struct poll_req *req; unsigned int i, j;
@@ -2902,8 +2889,6 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t async_set_completion_callback( async, free_poll_req, req ); queue_async( &poll_sock->poll_q, async );
- if (!timeout) req->iosb->status = STATUS_SUCCESS; - for (i = 0; i < count; ++i) { struct sock *sock = req->sockets[i].sock; @@ -2912,7 +2897,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t
if (flags) { - req->iosb->status = STATUS_SUCCESS; + signaled = TRUE; output[i].flags = flags; output[i].status = sock_get_ntstatus( sock_error( sock->fd ) ); } @@ -2926,12 +2911,8 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t } }
- if (req->iosb->status != STATUS_PENDING) - { - req->iosb->out_data = output; - req->iosb->out_size = count * sizeof(*output); - async_terminate( req->async, STATUS_ALERTED ); - } + if (!timeout || signaled) + async_request_complete( req->async, STATUS_SUCCESS, 0, count * sizeof(*output), output );
for (i = 0; i < req->count; ++i) sock_reselect( req->sockets[i].sock );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/async.c | 15 +++++++++++++++ server/console.c | 7 +------ server/device.c | 6 +----- server/file.h | 2 ++ server/sock.c | 6 +----- 5 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/server/async.c b/server/async.c index e71dceb201b..17ef709f89e 100644 --- a/server/async.c +++ b/server/async.c @@ -361,6 +361,21 @@ void async_request_complete( struct async *async, unsigned int status, data_size async_terminate( async, status ); }
+/* complete a request-based async */ +void async_request_complete_alloc( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, const void *out_data ) +{ + void *out_data_copy = NULL; + + if (out_size && !(out_data_copy = memdup( out_data, out_size ))) + { + async_terminate( async, STATUS_NO_MEMORY ); + return; + } + + async_request_complete( async, status, result, out_size, out_data_copy ); +} + /* set the timeout of an async operation */ void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ) { diff --git a/server/console.c b/server/console.c index 94f7c37e7c5..3360f680448 100644 --- a/server/console.c +++ b/server/console.c @@ -1500,12 +1500,7 @@ DECL_HANDLER(get_next_console_request) { data_size_t out_size = min( iosb->out_size, get_req_data_size() ); data_size_t result = ioctl->code == IOCTL_CONDRV_WRITE_FILE ? iosb->in_size : out_size; - void *out_data; - - if (!out_size || (out_data = memdup( get_req_data(), out_size ))) - async_request_complete( async, status, result, out_size, out_data ); - else - async_terminate( async, STATUS_NO_MEMORY ); + async_request_complete_alloc( async, status, result, out_size, get_req_data() ); }
release_object( async ); diff --git a/server/device.c b/server/device.c index 96389a1459b..29b36845e68 100644 --- a/server/device.c +++ b/server/device.c @@ -385,12 +385,8 @@ static void set_irp_result( struct irp_call *irp, unsigned int status, irp->file = NULL; if (irp->async) { - void *out_data; - out_size = min( irp->iosb->out_size, out_size ); - if (out_size && !(out_data = memdup( out_data, out_size ))) - out_size = 0; - async_request_complete( irp->async, status, result, out_size, out_data ); + async_request_complete_alloc( irp->async, status, result, out_size, out_data ); release_object( irp->async ); irp->async = NULL; } diff --git a/server/file.h b/server/file.h index 1c019a0667e..8e42cd3704e 100644 --- a/server/file.h +++ b/server/file.h @@ -229,6 +229,8 @@ extern int async_waiting( struct async_queue *queue ); extern void async_terminate( struct async *async, unsigned int status ); extern void async_request_complete( struct async *async, unsigned int status, data_size_t result, data_size_t out_size, void *out_data ); +extern void async_request_complete_alloc( struct async *async, unsigned int status, data_size_t result, + data_size_t out_size, const void *out_data ); 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 ); diff --git a/server/sock.c b/server/sock.c index 00d5d47edff..1e31b806986 100644 --- a/server/sock.c +++ b/server/sock.c @@ -710,7 +710,6 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req ) else { obj_handle_t handle; - void *out_data;
if (!(acceptsock = accept_socket( sock ))) { @@ -727,10 +726,7 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req ) return; }
- if (!(out_data = malloc( sizeof(handle) ))) return; - - memcpy( out_data, &handle, sizeof(handle) ); - async_request_complete( req->async, STATUS_SUCCESS, 0, sizeof(handle), out_data ); + async_request_complete_alloc( req->async, STATUS_SUCCESS, 0, sizeof(handle), &handle ); } }
From: Zebediah Figura z.figura12@gmail.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/named_pipe.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/server/named_pipe.c b/server/named_pipe.c index da3485dd2bc..20407badc4c 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -763,16 +763,20 @@ static int pipe_end_get_volume_info( struct fd *fd, struct async *async, unsigne return 0; }
-static void message_queue_read( struct pipe_end *pipe_end, struct iosb *iosb ) +static void message_queue_read( struct pipe_end *pipe_end, struct async *async ) { + struct iosb *iosb = async_get_iosb( async ); + unsigned int status = STATUS_SUCCESS; struct pipe_message *message; + data_size_t out_size;
if (pipe_end->flags & NAMED_PIPE_MESSAGE_STREAM_READ) { message = LIST_ENTRY( list_head(&pipe_end->message_queue), struct pipe_message, entry ); - iosb->out_size = min( iosb->out_size, message->iosb->in_size - message->read_pos ); - iosb->status = message->read_pos + iosb->out_size < message->iosb->in_size - ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; + out_size = min( iosb->out_size, message->iosb->in_size - message->read_pos ); + + if (message->read_pos + out_size < message->iosb->in_size) + status = STATUS_BUFFER_OVERFLOW; } else { @@ -782,14 +786,13 @@ static void message_queue_read( struct pipe_end *pipe_end, struct iosb *iosb ) avail += message->iosb->in_size - message->read_pos; if (avail >= iosb->out_size) break; } - iosb->out_size = min( iosb->out_size, avail ); - iosb->status = STATUS_SUCCESS; + out_size = min( iosb->out_size, avail ); }
message = LIST_ENTRY( list_head(&pipe_end->message_queue), struct pipe_message, entry ); if (!message->read_pos && message->iosb->in_size == iosb->out_size) /* fast path */ { - iosb->out_data = message->iosb->in_data; + async_request_complete( async, status, out_size, out_size, message->iosb->in_data ); message->iosb->in_data = NULL; wake_message( message, message->iosb->in_size ); free_message( message ); @@ -799,17 +802,17 @@ static void message_queue_read( struct pipe_end *pipe_end, struct iosb *iosb ) data_size_t write_pos = 0, writing; char *buf = NULL;
- if (iosb->out_size && !(buf = iosb->out_data = malloc( iosb->out_size ))) + if (out_size && !(buf = malloc( out_size ))) { - iosb->out_size = 0; - iosb->status = STATUS_NO_MEMORY; + async_terminate( async, STATUS_NO_MEMORY ); + release_object( iosb ); return; }
do { message = LIST_ENTRY( list_head(&pipe_end->message_queue), struct pipe_message, entry ); - writing = min( iosb->out_size - write_pos, message->iosb->in_size - message->read_pos ); + writing = min( out_size - write_pos, message->iosb->in_size - message->read_pos ); if (writing) memcpy( buf + write_pos, (const char *)message->iosb->in_data + message->read_pos, writing ); write_pos += writing; message->read_pos += writing; @@ -818,9 +821,12 @@ static void message_queue_read( struct pipe_end *pipe_end, struct iosb *iosb ) wake_message(message, message->iosb->in_size); free_message(message); } - } while (write_pos < iosb->out_size); + } while (write_pos < out_size); + + async_request_complete( async, status, out_size, out_size, buf ); } - iosb->result = iosb->out_size; + + release_object( iosb ); }
/* We call async_terminate in our reselect implementation, which causes recursive reselect. @@ -832,16 +838,12 @@ static void reselect_write_queue( struct pipe_end *pipe_end ); static void reselect_read_queue( struct pipe_end *pipe_end, int reselect_write ) { struct async *async; - struct iosb *iosb;
ignore_reselect = 1; while (!list_empty( &pipe_end->message_queue ) && (async = find_pending_async( &pipe_end->read_q ))) { - iosb = async_get_iosb( async ); - message_queue_read( pipe_end, iosb ); - async_terminate( async, iosb->result ? STATUS_ALERTED : iosb->status ); + message_queue_read( pipe_end, async ); release_object( async ); - release_object( iosb ); reselect_write = 1; } ignore_reselect = 0;
In particular, don't mark asyncs with output data as "alerted", i.e. restartable.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 48 +++++++++++++++++++----------- server/async.c | 17 +++++++---- 2 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 8ede0e55513..b85c0078620 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -663,11 +663,12 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) size = 0xdeadf00d; SetLastError(0xdeadf00d); ret = DeviceIoControl(device, ioctl, params, sizeof(*params), buffer, sizeof(buffer), &size, NULL); - todo_wine_if (NT_SUCCESS(expect_status) != NT_SUCCESS(params->iosb_status)) + todo_wine_if ((params->iosb_status != STATUS_PENDING && NT_SUCCESS(expect_status) != NT_SUCCESS(params->iosb_status)) + || (params->iosb_status == STATUS_PENDING && NT_SUCCESS(expect_status))) ok(ret == NT_SUCCESS(expect_status), "got %d\n", ret); if (NT_SUCCESS(expect_status)) { - todo_wine_if (!NT_SUCCESS(params->iosb_status)) + todo_wine_if (!NT_SUCCESS(params->iosb_status) || params->iosb_status == STATUS_PENDING) ok(GetLastError() == 0xdeadf00d, "got error %u\n", GetLastError()); } else @@ -679,7 +680,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) if (NT_ERROR(expect_status)) todo_wine ok(size == 0xdeadf00d, "got size %u\n", size); else if (!NT_ERROR(params->iosb_status)) - ok(size == 3, "got size %u\n", size); + todo_wine_if (params->iosb_status == STATUS_PENDING) ok(size == 3, "got size %u\n", size); /* size is garbage if !NT_ERROR(expect_status) && NT_ERROR(iosb_status) */ todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); @@ -689,8 +690,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if ((params->ret_status != params->iosb_status && params->ret_status != STATUS_PENDING) - || params->iosb_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status && params->ret_status != STATUS_PENDING) ok(ret == expect_status, "got %#x\n", ret); if (NT_ERROR(params->iosb_status)) { @@ -700,8 +700,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } } todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); @@ -723,7 +725,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status) ok(ret == params->ret_status || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ "got %#x\n", ret); @@ -737,8 +739,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } ret = WaitForSingleObject(event, 0); ok(!ret, "got %d\n", ret); } @@ -761,9 +765,9 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) ok(!ret, "got %#x\n", ret); ok(key == 123, "got key %Iu\n", key); ok(value == 456, "got value %Iu\n", value); + ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status); todo_wine_if (params->iosb_status == STATUS_PENDING) - ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status); - ok(io.Information == 3, "got information %Iu\n", io.Information); + ok(io.Information == 3, "got information %Iu\n", io.Information); }
/* As above, but set the event first, to show that the event is always @@ -774,7 +778,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(file, event, NULL, NULL, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status) ok(ret == params->ret_status || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ "got %#x\n", ret); @@ -788,8 +792,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } ret = WaitForSingleObject(event, 0); ok(!ret, "got %d\n", ret); } @@ -805,7 +811,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(file, NULL, NULL, NULL, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status) ok(ret == params->ret_status || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ "got %#x\n", ret); @@ -819,8 +825,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } ret = WaitForSingleObject(file, 0); ok(!ret, "got %d\n", ret); } @@ -840,7 +848,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status) ok(ret == params->ret_status || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ "got %#x\n", ret); @@ -854,8 +862,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } ret = WaitForSingleObject(event, 0); ok(!ret, "got %d\n", ret); } @@ -909,7 +919,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) io.Information = 0xdeadf00d; ret = NtDeviceIoControlFile(file, NULL, return_status_apc, (void *)456, &io, ioctl, params, sizeof(*params), buffer, sizeof(buffer)); - todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + todo_wine_if (params->ret_status != params->iosb_status) ok(ret == params->ret_status, "got %#x\n", ret); if (!params->pending && NT_ERROR(params->iosb_status)) { @@ -919,8 +929,10 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) else { todo_wine_if (params->iosb_status == STATUS_PENDING) + { ok(io.Status == params->iosb_status, "got %#x\n", io.Status); - ok(io.Information == 3, "got size %Iu\n", io.Information); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } } todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); diff --git a/server/async.c b/server/async.c index 17ef709f89e..e8d95a62d4b 100644 --- a/server/async.c +++ b/server/async.c @@ -156,6 +156,8 @@ static void async_destroy( struct object *obj ) /* notifies client thread of new status of its async request */ void async_terminate( struct async *async, unsigned int status ) { + struct iosb *iosb = async->iosb; + if (async->terminated) return;
async->terminated = 1; @@ -176,7 +178,15 @@ void async_terminate( struct async *async, unsigned int status ) data.type = APC_ASYNC_IO; data.async_io.user = async->data.user; data.async_io.sb = async->data.iosb; - data.async_io.status = status; + + /* if the result is nonzero or there is output data, the client needs to + * make an extra request to retrieve them; use STATUS_ALERTED to signal + * this case */ + if (iosb && (iosb->result || iosb->out_data)) + data.async_io.status = STATUS_ALERTED; + else + data.async_io.status = status; + thread_queue_apc( async->thread->process, async->thread, &async->obj, &data ); }
@@ -353,11 +363,6 @@ void async_request_complete( struct async *async, unsigned int status, data_size
release_object( iosb );
- /* if the result is nonzero or there is output data, the client needs to - * make an extra request to retrieve them; use STATUS_ALERTED to signal - * this case */ - if (result || out_data) - status = STATUS_ALERTED; async_terminate( async, status ); }