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:
parent
fd4e7703e9
commit
96593370cd
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
121
server/sock.c
121
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 );
|
||||
|
|
Loading…
Reference in New Issue