server: Support blocking console host ioctls.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2020-08-25 14:52:48 +02:00 committed by Alexandre Julliard
parent 4225ec994e
commit b75ae8c31e
5 changed files with 73 additions and 9 deletions

View File

@ -1943,8 +1943,10 @@ struct get_next_console_request_request
struct request_header __header;
obj_handle_t handle;
int signal;
int read;
unsigned int status;
/* VARARG(out_data,bytes); */
char __pad_28[4];
};
struct get_next_console_request_reply
{
@ -6333,7 +6335,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 638
#define SERVER_PROTOCOL_VERSION 639
/* ### protocol_version end ### */

View File

@ -192,6 +192,7 @@ struct console_server
struct object obj; /* object header */
struct console_input *console; /* attached console */
struct list queue; /* ioctl queue */
struct list read_queue; /* blocking read queue */
int busy; /* flag if server processing an ioctl */
};
@ -577,6 +578,12 @@ static void disconnect_console_server( struct console_server *server )
list_remove( &call->entry );
console_host_ioctl_terminate( call, STATUS_CANCELLED );
}
while (!list_empty( &server->read_queue ))
{
struct console_host_ioctl *call = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry );
list_remove( &call->entry );
console_host_ioctl_terminate( call, STATUS_CANCELLED );
}
if (server->console)
{
@ -1638,10 +1645,16 @@ static struct object *create_console_server( void )
server->console = NULL;
server->busy = 0;
list_init( &server->queue );
list_init( &server->read_queue );
return &server->obj;
}
static int is_blocking_read_ioctl( unsigned int code )
{
return code == IOCTL_CONDRV_READ_INPUT;
}
static int console_input_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
{
struct console_input *console = get_fd_user( fd );
@ -2385,11 +2398,10 @@ DECL_HANDLER(get_console_wait_event)
/* retrieve the next pending console ioctl request */
DECL_HANDLER(get_next_console_request)
{
struct console_host_ioctl *ioctl = NULL;
struct console_host_ioctl *ioctl = NULL, *next;
struct console_server *server;
struct iosb *iosb = NULL;
server = (struct console_server *)get_handle_obj( current->process, req->handle, 0, &console_server_ops );
if (!server) return;
@ -2403,12 +2415,30 @@ DECL_HANDLER(get_next_console_request)
if (req->signal) set_event( server->console->event);
else reset_event( server->console->event );
/* set result of previous ioctl, if any */
if (server->busy)
if (req->read)
{
unsigned int status = req->status;
/* set result of current pending ioctl */
if (list_empty( &server->read_queue ))
{
set_error( STATUS_INVALID_HANDLE );
release_object( server );
return;
}
ioctl = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry );
list_remove( &ioctl->entry );
list_move_tail( &server->queue, &server->read_queue );
}
else if (server->busy)
{
/* set result of previous ioctl */
ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry );
list_remove( &ioctl->entry );
}
if (ioctl)
{
unsigned int status = req->status;
if (ioctl->async)
{
iosb = async_get_iosb( ioctl->async );
@ -2430,9 +2460,32 @@ DECL_HANDLER(get_next_console_request)
}
console_host_ioctl_terminate( ioctl, status );
if (iosb) release_object( iosb );
if (req->read)
{
release_object( server );
return;
}
server->busy = 0;
}
/* if we have a blocking read ioctl in queue head and previous blocking read is still waiting,
* move it to read queue for execution after current read is complete. move all blocking
* ioctl at the same time to preserve their order. */
if (!list_empty( &server->queue ) && !list_empty( &server->read_queue ))
{
ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry );
if (is_blocking_read_ioctl( ioctl->code ))
{
LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &server->queue, struct console_host_ioctl, entry )
{
if (!is_blocking_read_ioctl( ioctl->code )) continue;
list_remove( &ioctl->entry );
list_add_tail( &server->read_queue, &ioctl->entry );
}
}
}
/* return the next ioctl */
if (!list_empty( &server->queue ))
{
@ -2450,7 +2503,13 @@ DECL_HANDLER(get_next_console_request)
iosb->in_data = NULL;
}
server->busy = 1;
if (is_blocking_read_ioctl( ioctl->code ))
{
list_remove( &ioctl->entry );
assert( list_empty( &server->read_queue ));
list_add_tail( &server->read_queue, &ioctl->entry );
}
else server->busy = 1;
}
else
{

View File

@ -1526,6 +1526,7 @@ enum server_fd_type
@REQ(get_next_console_request)
obj_handle_t handle; /* console server handle */
int signal; /* server signal state */
int read; /* 1 if reporting result of blocked read ioctl */
unsigned int status; /* status of previous ioctl */
VARARG(out_data,bytes); /* out_data of previous ioctl */
@REPLY

View File

@ -1136,8 +1136,9 @@ C_ASSERT( FIELD_OFFSET(struct send_console_signal_request, group_id) == 16 );
C_ASSERT( sizeof(struct send_console_signal_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, signal) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, status) == 20 );
C_ASSERT( sizeof(struct get_next_console_request_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, read) == 20 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, status) == 24 );
C_ASSERT( sizeof(struct get_next_console_request_request) == 32 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_reply, code) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_reply, out_size) == 12 );
C_ASSERT( sizeof(struct get_next_console_request_reply) == 16 );

View File

@ -2098,6 +2098,7 @@ static void dump_get_next_console_request_request( const struct get_next_console
{
fprintf( stderr, " handle=%04x", req->handle );
fprintf( stderr, ", signal=%d", req->signal );
fprintf( stderr, ", read=%d", req->read );
fprintf( stderr, ", status=%08x", req->status );
dump_varargs_bytes( ", out_data=", cur_size );
}