Adapted to new select interface.
Fixed bug in *_signaled routines that could cause busy-waiting in the
select loop.
diff --git a/server/console.c b/server/console.c
index d067c21..774e65f 100644
--- a/server/console.c
+++ b/server/console.c
@@ -33,7 +33,7 @@
struct console_input
{
struct object obj; /* object header */
- int fd; /* Unix file descriptor */
+ struct select_user select; /* select user */
int mode; /* input mode */
struct screen_buffer *output; /* associated screen buffer */
int recnum; /* number of input records */
@@ -43,7 +43,7 @@
struct screen_buffer
{
struct object obj; /* object header */
- int fd; /* Unix file descriptor */
+ struct select_user select; /* select user */
int mode; /* output mode */
struct console_input *input; /* associated console input */
int cursor_size; /* size of cursor (percentage filled) */
@@ -98,11 +98,6 @@
screen_buffer_destroy
};
-static const struct select_ops select_ops =
-{
- default_select_event,
- NULL /* we never set a timeout on a console */
-};
int create_console( int fd, struct object *obj[2] )
{
@@ -136,19 +131,25 @@
}
init_object( &console_input->obj, &console_input_ops, NULL );
init_object( &screen_buffer->obj, &screen_buffer_ops, NULL );
- console_input->fd = read_fd;
+ console_input->select.fd = read_fd;
+ console_input->select.func = default_select_event;
+ console_input->select.private = console_input;
console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = screen_buffer;
console_input->recnum = 0;
console_input->records = NULL;
- screen_buffer->fd = write_fd;
+ screen_buffer->select.fd = write_fd;
+ screen_buffer->select.func = default_select_event;
+ screen_buffer->select.private = screen_buffer;
screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input;
screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0;
screen_buffer->title = strdup( "Wine console" );
+ register_select_user( &console_input->select );
+ register_select_user( &screen_buffer->select );
CLEAR_ERROR();
obj[0] = &console_input->obj;
obj[1] = &screen_buffer->obj;
@@ -183,6 +184,10 @@
return 0;
}
+ /* can't change the fd if someone is waiting on it */
+ assert( !input->obj.head );
+ assert( !output->obj.head );
+
if ((fd_in = dup(fd)) == -1)
{
file_set_error();
@@ -198,11 +203,15 @@
release_object( output );
return 0;
}
- close( input->fd );
- close( output->fd );
- input->fd = fd_in;
- output->fd = fd_out;
- output->pid = pid;
+ unregister_select_user( &input->select );
+ unregister_select_user( &output->select );
+ close( input->select.fd );
+ close( output->select.fd );
+ input->select.fd = fd_in;
+ output->select.fd = fd_out;
+ output->pid = pid;
+ register_select_user( &input->select );
+ register_select_user( &output->select );
release_object( input );
release_object( output );
return 1;
@@ -346,7 +355,7 @@
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- fprintf( stderr, "Console input fd=%d\n", console->fd );
+ fprintf( stderr, "Console input fd=%d\n", console->select.fd );
}
static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -354,13 +363,7 @@
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
if (!obj->head) /* first on the queue */
- {
- if (!add_select_user( console->fd, READ_EVENT, &select_ops, console ))
- {
- SET_ERROR( ERROR_OUTOFMEMORY );
- return 0;
- }
- }
+ set_select_events( &console->select, READ_EVENT );
add_queue( obj, entry );
return 1;
}
@@ -372,27 +375,34 @@
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
- remove_select_user( console->fd );
+ set_select_events( &console->select, 0 );
release_object( obj );
}
static int console_input_signaled( struct object *obj, struct thread *thread )
{
- fd_set fds;
- struct timeval tv = { 0, 0 };
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- FD_ZERO( &fds );
- FD_SET( console->fd, &fds );
- return select( console->fd + 1, &fds, NULL, NULL, &tv ) > 0;
+ if (check_select_events( &console->select, READ_EVENT ))
+ {
+ /* stop waiting on select() if we are signaled */
+ set_select_events( &console->select, 0 );
+ return 1;
+ }
+ else
+ {
+ /* restart waiting on select() if we are no longer signaled */
+ if (obj->head) set_select_events( &console->select, READ_EVENT );
+ return 0;
+ }
}
static int console_input_get_read_fd( struct object *obj )
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- return dup( console->fd );
+ return dup( console->select.fd );
}
static int console_get_info( struct object *obj, struct get_file_info_reply *reply )
@@ -406,7 +416,8 @@
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- close( console->fd );
+ unregister_select_user( &console->select );
+ close( console->select.fd );
if (console->output) console->output->input = NULL;
free( console );
}
@@ -415,7 +426,7 @@
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
+ fprintf( stderr, "Console screen buffer fd=%d\n", console->select.fd );
}
static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -423,13 +434,7 @@
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
if (!obj->head) /* first on the queue */
- {
- if (!add_select_user( console->fd, WRITE_EVENT, &select_ops, console ))
- {
- SET_ERROR( ERROR_OUTOFMEMORY );
- return 0;
- }
- }
+ set_select_events( &console->select, WRITE_EVENT );
add_queue( obj, entry );
return 1;
}
@@ -441,34 +446,42 @@
remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */
- remove_select_user( console->fd );
+ set_select_events( &console->select, 0 );
release_object( obj );
}
static int screen_buffer_signaled( struct object *obj, struct thread *thread )
{
- fd_set fds;
- struct timeval tv = { 0, 0 };
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- FD_ZERO( &fds );
- FD_SET( console->fd, &fds );
- return select( console->fd + 1, NULL, &fds, NULL, &tv ) > 0;
+ if (check_select_events( &console->select, WRITE_EVENT ))
+ {
+ /* stop waiting on select() if we are signaled */
+ set_select_events( &console->select, 0 );
+ return 1;
+ }
+ else
+ {
+ /* restart waiting on select() if we are no longer signaled */
+ if (obj->head) set_select_events( &console->select, WRITE_EVENT );
+ return 0;
+ }
}
static int screen_buffer_get_write_fd( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- return dup( console->fd );
+ return dup( console->select.fd );
}
static void screen_buffer_destroy( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- close( console->fd );
+ unregister_select_user( &console->select );
+ close( console->select.fd );
if (console->input) console->input->output = NULL;
if (console->pid) kill( console->pid, SIGTERM );
if (console->title) free( console->title );