server: Enhanced the console input object so that it doesn't require a wineconsole to be running.

This commit is contained in:
Eric Pouech 2010-08-30 22:18:44 +02:00 committed by Alexandre Julliard
parent 258dba1a52
commit b39a8d9ea2
7 changed files with 140 additions and 31 deletions

View File

@ -1426,6 +1426,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
{
@ -5504,6 +5506,6 @@ union generic_reply
struct set_cursor_reply set_cursor_reply;
};
#define SERVER_PROTOCOL_VERSION 404
#define SERVER_PROTOCOL_VERSION 405
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -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 );

View File

@ -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);

View File

@ -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 ))

View File

@ -1137,6 +1137,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 */

View File

@ -954,7 +954,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 );

View File

@ -1588,6 +1588,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 )