server: Introduce a helper to fill an iosb and terminate the async.

For convenience, and to centralize the STATUS_ALERTED logic into one place.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-09-01 17:28:38 -05:00 committed by Alexandre Julliard
parent fd4e7703e9
commit 96593370cd
6 changed files with 105 additions and 116 deletions

View File

@ -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 )
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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 );