Jacek Caban : server: Support blocking console host ioctls.
Alexandre Julliard
julliard at winehq.org
Wed Aug 26 15:24:44 CDT 2020
Module: wine
Branch: master
Commit: b75ae8c31eba2a59e2b32bf8d456ca5756ac6e0d
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b75ae8c31eba2a59e2b32bf8d456ca5756ac6e0d
Author: Jacek Caban <jacek at codeweavers.com>
Date: Tue Aug 25 14:52:48 2020 +0200
server: Support blocking console host ioctls.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
include/wine/server_protocol.h | 4 ++-
server/console.c | 71 ++++++++++++++++++++++++++++++++++++++----
server/protocol.def | 1 +
server/request.h | 5 +--
server/trace.c | 1 +
5 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index af3353eae3..76206413d4 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -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 ### */
diff --git a/server/console.c b/server/console.c
index 5cdf3e7822..2c2978fc0c 100644
--- a/server/console.c
+++ b/server/console.c
@@ -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
{
diff --git a/server/protocol.def b/server/protocol.def
index 75888ea9a2..14bf046816 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -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
diff --git a/server/request.h b/server/request.h
index ba278122eb..4c16b24685 100644
--- a/server/request.h
+++ b/server/request.h
@@ -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 );
diff --git a/server/trace.c b/server/trace.c
index 42e048998c..dac0a5f6e1 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -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 );
}
More information about the wine-cvs
mailing list