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