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:
parent
4225ec994e
commit
b75ae8c31e
|
@ -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 ### */
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue