[PATCH 1/9] [Server]: enhanced the console input object so that it doesn't require a wineconsole to be running

Eric Pouech eric.pouech at orange.fr
Mon Aug 30 15:18:44 CDT 2010




A+
---

 include/wine/server_protocol.h     |    2 
 programs/wineconsole/wineconsole.c |    1 
 server/console.c                   |  153 ++++++++++++++++++++++++++++++------
 server/debugger.c                  |    8 +-
 server/protocol.def                |    1 
 server/request.h                   |    3 -
 server/trace.c                     |    1 
 7 files changed, 139 insertions(+), 30 deletions(-)


diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 0c43ecf..c35aab3 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1412,6 +1412,8 @@ struct alloc_console_request
     unsigned int access;
     unsigned int attributes;
     process_id_t pid;
+    int          input_fd;
+    char __pad_28[4];
 };
 struct alloc_console_reply
 {
diff --git a/programs/wineconsole/wineconsole.c b/programs/wineconsole/wineconsole.c
index 5acb9ad..3842303 100644
--- a/programs/wineconsole/wineconsole.c
+++ b/programs/wineconsole/wineconsole.c
@@ -596,6 +596,7 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
         req->access     = GENERIC_READ | GENERIC_WRITE;
         req->attributes = 0;
         req->pid        = pid;
+        req->input_fd   = -1;
 
         ret = !wine_server_call_err( req );
         data->hConIn = wine_server_ptr_handle( reply->handle_in );
diff --git a/server/console.c b/server/console.c
index d44ad41..9d84491 100644
--- a/server/console.c
+++ b/server/console.c
@@ -28,6 +28,9 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <signal.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -62,10 +65,13 @@ struct console_input
     int                          output_cp;     /* console output codepage */
     user_handle_t                win;           /* window handle if backend supports it */
     struct event                *event;         /* event to wait on for input queue */
+    struct fd                   *fd;            /* for bare console, attached input fd */
+    struct termios               termios;       /* for bare console, saved termio info */
 };
 
 static void console_input_dump( struct object *obj, int verbose );
 static void console_input_destroy( struct object *obj );
+static struct fd *console_input_get_fd( struct object *obj );
 
 static const struct object_ops console_input_ops =
 {
@@ -77,7 +83,7 @@ static const struct object_ops console_input_ops =
     NULL,                             /* signaled */
     no_satisfied,                     /* satisfied */
     no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
+    console_input_get_fd,             /* get_fd */
     default_fd_map_access,            /* map_access */
     default_get_sd,                   /* get_sd */
     default_set_sd,                   /* set_sd */
@@ -162,10 +168,36 @@ static const struct object_ops screen_buffer_ops =
     screen_buffer_destroy             /* destroy */
 };
 
+static enum server_fd_type console_get_fd_type( struct fd *fd );
+
+static const struct fd_ops console_fd_ops =
+{
+    default_fd_get_poll_events,   /* get_poll_events */
+    default_poll_event,           /* poll_event */
+    no_flush,                     /* flush */
+    console_get_fd_type,          /* get_fd_type */
+    default_fd_ioctl,             /* ioctl */
+    default_fd_queue_async,       /* queue_async */
+    default_fd_reselect_async,    /* reselect_async */
+    default_fd_cancel_async       /* cancel_async */
+};
+
 static struct list screen_buffer_list = LIST_INIT(screen_buffer_list);
 
 static const char_info_t empty_char_info = { ' ', 0x000f };  /* white on black space */
 
+static struct fd *console_input_get_fd( struct object* obj )
+{
+    struct console_input *console_input = (struct console_input*)obj;
+    assert( obj->ops == &console_input_ops );
+    return console_input->fd ? (struct fd*)grab_object( console_input->fd ) : NULL;
+}
+
+static enum server_fd_type console_get_fd_type( struct fd *fd )
+{
+    return FD_TYPE_CHAR;
+}
+
 /* dumps the renderer events of a console */
 static void console_input_events_dump( struct object *obj, int verbose )
 {
@@ -197,7 +229,8 @@ static void console_input_events_append( struct console_input_events* evts,
 {
     int collapsed = FALSE;
 
-    /* to be done even when evt has been generated by the rendere ? */
+    if (!evts) return;
+    /* to be done even when evt has been generated by the renderer ? */
 
     /* try to collapse evt into current queue's events */
     if (evts->num_used)
@@ -255,7 +288,7 @@ static struct console_input_events *create_console_input_events(void)
     return evt;
 }
 
-static struct object *create_console_input( struct thread* renderer )
+static struct object *create_console_input( struct thread* renderer, int fd )
 {
     struct console_input *console_input;
 
@@ -267,7 +300,7 @@ static struct object *create_console_input( struct thread* renderer )
     console_input->active        = NULL;
     console_input->recnum        = 0;
     console_input->records       = NULL;
-    console_input->evt           = create_console_input_events();
+    console_input->evt           = renderer ? create_console_input_events() : NULL;
     console_input->title         = NULL;
     console_input->history_size  = 50;
     console_input->history       = calloc( console_input->history_size, sizeof(WCHAR*) );
@@ -278,12 +311,50 @@ static struct object *create_console_input( struct thread* renderer )
     console_input->output_cp     = 0;
     console_input->win           = 0;
     console_input->event         = create_event( NULL, NULL, 0, 1, 0, NULL );
+    console_input->fd            = NULL;
 
-    if (!console_input->history || !console_input->evt || !console_input->event)
+    if (!console_input->history || (renderer && !console_input->evt) || !console_input->event)
     {
 	release_object( console_input );
 	return NULL;
     }
+    if (fd != -1) /* bare console */
+    {
+        struct termios  term;
+
+        if (!(console_input->fd = create_anonymous_fd( &console_fd_ops, fd, &console_input->obj,
+                                                       FILE_SYNCHRONOUS_IO_NONALERT )))
+        {
+            release_object( console_input );
+            return NULL;
+        }
+        if (tcgetattr(fd, &term) < 0)
+        {
+            release_object( console_input );
+            set_error( STATUS_INVALID_HANDLE );
+            return NULL;
+        }
+        console_input->termios = term;
+        term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+        term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+        term.c_cflag &= ~(CSIZE | PARENB);
+        term.c_cflag |= CS8;
+        /* FIXME: we should actually disable output processing here
+         * and let kernel32/console.c do the job (with support of enable/disable of
+         * processed output)
+         */
+        /* term.c_oflag &= ~(OPOST); */
+        term.c_cc[VMIN] = 1;
+        term.c_cc[VTIME] = 0;
+        if (tcsetattr(fd, TCSANOW, &term) < 0)
+        {
+            release_object( console_input );
+            set_error( STATUS_INVALID_HANDLE );
+            return NULL;
+        }
+        allow_fd_caching( console_input->fd );
+    }
+
     return &console_input->obj;
 }
 
@@ -374,10 +445,10 @@ int free_console( struct process *process )
 {
     struct console_input* console = process->console;
 
-    if (!console || !console->renderer) return 0;
+    if (!console) return 0;
 
     process->console = NULL;
-    if (--console->num_proc == 0)
+    if (--console->num_proc == 0 && console->renderer)
     {
 	/* all processes have terminated... tell the renderer to terminate too */
 	struct console_renderer_event evt;
@@ -424,7 +495,6 @@ void inherit_console(struct thread *parent_thread, struct process *process, obj_
     /* otherwise, if parent has a console, attach child to this console */
     if (!done && parent->console)
     {
-	assert(parent->console->renderer);
 	process->console = (struct console_input*)grab_object( parent->console );
 	process->console->num_proc++;
     }
@@ -444,7 +514,6 @@ static struct console_input* console_input_get( obj_handle_t handle, unsigned ac
 							  access, &console_input_ops );
     else if (current->process->console)
     {
-	assert( current->process->console->renderer );
 	console = (struct console_input *)grab_object( current->process->console );
     }
 
@@ -1020,9 +1089,17 @@ static void console_input_destroy( struct object *obj )
         if (curr->input == console_in) curr->input = NULL;
     }
 
-    release_object( console_in->evt );
-    console_in->evt = NULL;
+    if (console_in->evt)
+    {
+        release_object( console_in->evt );
+        console_in->evt = NULL;
+    }
     release_object( console_in->event );
+    if (console_in->fd)
+    {
+        tcsetattr(get_unix_fd(console_in->fd), TCSANOW, &console_in->termios);
+        release_object( console_in->fd );
+    }
 
     for (i = 0; i < console_in->history_size; i++)
         free( console_in->history[i] );
@@ -1295,35 +1372,58 @@ DECL_HANDLER(alloc_console)
     obj_handle_t in = 0;
     obj_handle_t evt = 0;
     struct process *process;
+    struct thread *renderer;
     struct console_input *console;
+    int fd;
 
-    if (req->pid)
-    {
-        if (!(process = get_process_from_id( req->pid ))) return;
-    }
-    else
+    switch (req->pid)
     {
+    case 0:
+        /* renderer is current, console to be attached to parent process */
+        renderer = current;
         if (!(process = current->process->parent))
         {
             set_error( STATUS_ACCESS_DENIED );
             return;
         }
         grab_object( process );
+        break;
+    case 0xffffffff:
+        /* no renderer, console to be attached to current process */
+        renderer = NULL;
+        process = current->process;
+        grab_object( process );
+        break;
+    default:
+        /* renderer is current, console to be attached to req->pid */
+        renderer = current;
+        if (!(process = get_process_from_id( req->pid ))) return;
     }
 
     if (process != current->process && process->console)
+    {
         set_error( STATUS_ACCESS_DENIED );
-    else if ((console = (struct console_input*)create_console_input( current )))
+        goto the_end;
+    }
+    if (req->input_fd != -1)
+    {
+        if ((fd = thread_get_inflight_fd( current, req->input_fd )) == -1)
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            goto the_end;
+        }
+    }
+    else fd = -1;
+
+    if ((console = (struct console_input*)create_console_input( renderer, fd )))
     {
         if ((in = alloc_handle( current->process, console, req->access, req->attributes )))
         {
-            if ((evt = alloc_handle( current->process, console->evt, SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, 0 )))
+            if (!console->evt ||
+                (evt = alloc_handle( current->process, console->evt, SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, 0 )))
             {
-                if (process != current->process)
-                {
-                    process->console = (struct console_input*)grab_object( console );
-                    console->num_proc++;
-                }
+                process->console = (struct console_input*)grab_object( console );
+                console->num_proc++;
                 reply->handle_in = in;
                 reply->event = evt;
                 release_object( console );
@@ -1363,13 +1463,12 @@ DECL_HANDLER(open_console)
     reply->handle = 0;
     if (!req->from)
     {
-        if (current->process->console && current->process->console->renderer)
+        if (current->process->console)
             obj = grab_object( (struct object*)current->process->console );
     }
     else if (req->from == (obj_handle_t)1)
     {
-         if (current->process->console && current->process->console->renderer &&
-             current->process->console->active)
+         if (current->process->console && current->process->console->active)
              obj = grab_object( (struct object*)current->process->console->active );
     }
     else if ((obj = get_handle_obj( current->process, req->from,
@@ -1608,7 +1707,7 @@ DECL_HANDLER(get_console_wait_event)
 {
     struct console_input* console = NULL;
 
-    if (current->process->console && current->process->console->renderer)
+    if (current->process->console)
         console = (struct console_input*)grab_object( (struct object*)current->process->console );
     else enum_processes(cgwe_enum, &console);
 
diff --git a/server/debugger.c b/server/debugger.c
index f76b44c..74c59f2 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -426,8 +426,12 @@ static int debugger_attach( struct process *process, struct thread *debugger )
     if (list_empty( &process->thread_list )) goto error;  /* no thread running in the process */
 
     /* don't let a debugger debug its console... won't work */
-    if (debugger->process->console && console_get_renderer(debugger->process->console)->process == process)
-        goto error;
+    if (debugger->process->console)
+    {
+        struct thread *renderer = console_get_renderer(debugger->process->console);
+        if (renderer && renderer->process == process)
+            goto error;
+    }
 
     suspend_process( process );
     if (!set_process_debugger( process, debugger ))
diff --git a/server/protocol.def b/server/protocol.def
index 5f1a8f9..2ebca95 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1130,6 +1130,7 @@ enum server_fd_type
     unsigned int access;        /* wanted access rights */
     unsigned int attributes;    /* object attributes */
     process_id_t pid;           /* pid of process which shall be attached to the console */
+    int          input_fd;      /* if pid=-1 (bare console to current process), fd for input */
 @REPLY
     obj_handle_t handle_in;     /* handle to console input */
     obj_handle_t event;         /* handle to renderer events change notification */
diff --git a/server/request.h b/server/request.h
index 7897673..ca406e1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -949,7 +949,8 @@ C_ASSERT( sizeof(struct set_socket_deferred_request) == 24 );
 C_ASSERT( FIELD_OFFSET(struct alloc_console_request, access) == 12 );
 C_ASSERT( FIELD_OFFSET(struct alloc_console_request, attributes) == 16 );
 C_ASSERT( FIELD_OFFSET(struct alloc_console_request, pid) == 20 );
-C_ASSERT( sizeof(struct alloc_console_request) == 24 );
+C_ASSERT( FIELD_OFFSET(struct alloc_console_request, input_fd) == 24 );
+C_ASSERT( sizeof(struct alloc_console_request) == 32 );
 C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, handle_in) == 8 );
 C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, event) == 12 );
 C_ASSERT( sizeof(struct alloc_console_reply) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 944d939..443321a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1582,6 +1582,7 @@ static void dump_alloc_console_request( const struct alloc_console_request *req
     fprintf( stderr, " access=%08x", req->access );
     fprintf( stderr, ", attributes=%08x", req->attributes );
     fprintf( stderr, ", pid=%04x", req->pid );
+    fprintf( stderr, ", input_fd=%d", req->input_fd );
 }
 
 static void dump_alloc_console_reply( const struct alloc_console_reply *req )






More information about the wine-patches mailing list