Adapted to new select interface.

Fixed bug in *_signaled routines that could cause busy-waiting in the
select loop.
This commit is contained in:
Alexandre Julliard 1999-05-16 16:59:38 +00:00
parent 88de35cd70
commit 57e1131334
5 changed files with 206 additions and 181 deletions

View File

@ -33,7 +33,7 @@ struct screen_buffer;
struct console_input struct console_input
{ {
struct object obj; /* object header */ struct object obj; /* object header */
int fd; /* Unix file descriptor */ struct select_user select; /* select user */
int mode; /* input mode */ int mode; /* input mode */
struct screen_buffer *output; /* associated screen buffer */ struct screen_buffer *output; /* associated screen buffer */
int recnum; /* number of input records */ int recnum; /* number of input records */
@ -43,7 +43,7 @@ struct console_input
struct screen_buffer struct screen_buffer
{ {
struct object obj; /* object header */ struct object obj; /* object header */
int fd; /* Unix file descriptor */ struct select_user select; /* select user */
int mode; /* output mode */ int mode; /* output mode */
struct console_input *input; /* associated console input */ struct console_input *input; /* associated console input */
int cursor_size; /* size of cursor (percentage filled) */ int cursor_size; /* size of cursor (percentage filled) */
@ -98,11 +98,6 @@ static const struct object_ops screen_buffer_ops =
screen_buffer_destroy 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] ) int create_console( int fd, struct object *obj[2] )
{ {
@ -136,19 +131,25 @@ int create_console( int fd, struct object *obj[2] )
} }
init_object( &console_input->obj, &console_input_ops, NULL ); init_object( &console_input->obj, &console_input_ops, NULL );
init_object( &screen_buffer->obj, &screen_buffer_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 | console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
console_input->output = screen_buffer; console_input->output = screen_buffer;
console_input->recnum = 0; console_input->recnum = 0;
console_input->records = NULL; 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->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
screen_buffer->input = console_input; screen_buffer->input = console_input;
screen_buffer->cursor_size = 100; screen_buffer->cursor_size = 100;
screen_buffer->cursor_visible = 1; screen_buffer->cursor_visible = 1;
screen_buffer->pid = 0; screen_buffer->pid = 0;
screen_buffer->title = strdup( "Wine console" ); screen_buffer->title = strdup( "Wine console" );
register_select_user( &console_input->select );
register_select_user( &screen_buffer->select );
CLEAR_ERROR(); CLEAR_ERROR();
obj[0] = &console_input->obj; obj[0] = &console_input->obj;
obj[1] = &screen_buffer->obj; obj[1] = &screen_buffer->obj;
@ -183,6 +184,10 @@ static int set_console_fd( int handle, int fd, int pid )
return 0; 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) if ((fd_in = dup(fd)) == -1)
{ {
file_set_error(); file_set_error();
@ -198,11 +203,15 @@ static int set_console_fd( int handle, int fd, int pid )
release_object( output ); release_object( output );
return 0; return 0;
} }
close( input->fd ); unregister_select_user( &input->select );
close( output->fd ); unregister_select_user( &output->select );
input->fd = fd_in; close( input->select.fd );
output->fd = fd_out; close( output->select.fd );
output->pid = pid; 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( input );
release_object( output ); release_object( output );
return 1; return 1;
@ -346,7 +355,7 @@ static void console_input_dump( struct object *obj, int verbose )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); 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 ) static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
@ -354,13 +363,7 @@ static int console_input_add_queue( struct object *obj, struct wait_queue_entry
struct console_input *console = (struct console_input *)obj; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); assert( obj->ops == &console_input_ops );
if (!obj->head) /* first on the queue */ if (!obj->head) /* first on the queue */
{ set_select_events( &console->select, READ_EVENT );
if (!add_select_user( console->fd, READ_EVENT, &select_ops, console ))
{
SET_ERROR( ERROR_OUTOFMEMORY );
return 0;
}
}
add_queue( obj, entry ); add_queue( obj, entry );
return 1; return 1;
} }
@ -372,27 +375,34 @@ static void console_input_remove_queue( struct object *obj, struct wait_queue_en
remove_queue( obj, entry ); remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */ if (!obj->head) /* last on the queue is gone */
remove_select_user( console->fd ); set_select_events( &console->select, 0 );
release_object( obj ); release_object( obj );
} }
static int console_input_signaled( struct object *obj, struct thread *thread ) 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; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); assert( obj->ops == &console_input_ops );
FD_ZERO( &fds ); if (check_select_events( &console->select, READ_EVENT ))
FD_SET( console->fd, &fds ); {
return select( console->fd + 1, &fds, NULL, NULL, &tv ) > 0; /* 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 ) static int console_input_get_read_fd( struct object *obj )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); 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 ) static int console_get_info( struct object *obj, struct get_file_info_reply *reply )
@ -406,7 +416,8 @@ static void console_input_destroy( struct object *obj )
{ {
struct console_input *console = (struct console_input *)obj; struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops ); 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; if (console->output) console->output->input = NULL;
free( console ); free( console );
} }
@ -415,7 +426,7 @@ static void screen_buffer_dump( struct object *obj, int verbose )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); 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 ) static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
@ -423,13 +434,7 @@ static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry
struct screen_buffer *console = (struct screen_buffer *)obj; struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); assert( obj->ops == &screen_buffer_ops );
if (!obj->head) /* first on the queue */ if (!obj->head) /* first on the queue */
{ set_select_events( &console->select, WRITE_EVENT );
if (!add_select_user( console->fd, WRITE_EVENT, &select_ops, console ))
{
SET_ERROR( ERROR_OUTOFMEMORY );
return 0;
}
}
add_queue( obj, entry ); add_queue( obj, entry );
return 1; return 1;
} }
@ -441,34 +446,42 @@ static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_en
remove_queue( obj, entry ); remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */ if (!obj->head) /* last on the queue is gone */
remove_select_user( console->fd ); set_select_events( &console->select, 0 );
release_object( obj ); release_object( obj );
} }
static int screen_buffer_signaled( struct object *obj, struct thread *thread ) 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; struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); assert( obj->ops == &screen_buffer_ops );
FD_ZERO( &fds ); if (check_select_events( &console->select, WRITE_EVENT ))
FD_SET( console->fd, &fds ); {
return select( console->fd + 1, NULL, &fds, NULL, &tv ) > 0; /* 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 ) static int screen_buffer_get_write_fd( struct object *obj )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); assert( obj->ops == &screen_buffer_ops );
return dup( console->fd ); return dup( console->select.fd );
} }
static void screen_buffer_destroy( struct object *obj ) static void screen_buffer_destroy( struct object *obj )
{ {
struct screen_buffer *console = (struct screen_buffer *)obj; struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops ); 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->input) console->input->output = NULL;
if (console->pid) kill( console->pid, SIGTERM ); if (console->pid) kill( console->pid, SIGTERM );
if (console->title) free( console->title ); if (console->title) free( console->title );

View File

@ -26,13 +26,13 @@
struct file struct file
{ {
struct object obj; /* object header */ struct object obj; /* object header */
struct file *next; /* next file in hashing list */ struct select_user select; /* select user */
char *name; /* file name */ struct file *next; /* next file in hashing list */
int fd; /* Unix file descriptor */ char *name; /* file name */
unsigned int access; /* file access (GENERIC_READ/WRITE) */ unsigned int access; /* file access (GENERIC_READ/WRITE) */
unsigned int flags; /* flags (FILE_FLAG_*) */ unsigned int flags; /* flags (FILE_FLAG_*) */
unsigned int sharing; /* file sharing mode */ unsigned int sharing; /* file sharing mode */
}; };
#define NAME_HASH_SIZE 37 #define NAME_HASH_SIZE 37
@ -63,12 +63,6 @@ static const struct object_ops file_ops =
file_destroy file_destroy
}; };
static const struct select_ops select_ops =
{
default_select_event,
NULL /* we never set a timeout on a file */
};
static int get_name_hash( const char *name ) static int get_name_hash( const char *name )
{ {
@ -194,10 +188,13 @@ static struct object *create_file( int fd, const char *name, unsigned int access
file->next = NULL; file->next = NULL;
} }
init_object( &file->obj, &file_ops, NULL ); init_object( &file->obj, &file_ops, NULL );
file->fd = fd; file->select.fd = fd;
file->access = access; file->select.func = default_select_event;
file->flags = attrs; file->select.private = file;
file->sharing = sharing; file->access = access;
file->flags = attrs;
file->sharing = sharing;
register_select_user( &file->select );
CLEAR_ERROR(); CLEAR_ERROR();
return &file->obj; return &file->obj;
} }
@ -231,12 +228,15 @@ struct file *create_temp_file( int access )
return NULL; return NULL;
} }
init_object( &file->obj, &file_ops, NULL ); init_object( &file->obj, &file_ops, NULL );
file->name = NULL; file->name = NULL;
file->next = NULL; file->next = NULL;
file->fd = fd; file->select.fd = fd;
file->access = access; file->select.func = default_select_event;
file->flags = 0; file->select.private = file;
file->sharing = 0; file->access = access;
file->flags = 0;
file->sharing = 0;
register_select_user( &file->select );
CLEAR_ERROR(); CLEAR_ERROR();
return file; return file;
} }
@ -246,7 +246,7 @@ static void file_dump( struct object *obj, int verbose )
struct file *file = (struct file *)obj; struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
printf( "File fd=%d flags=%08x name='%s'\n", printf( "File fd=%d flags=%08x name='%s'\n",
file->fd, file->flags, file->name ); file->select.fd, file->flags, file->name );
} }
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry ) static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
@ -255,11 +255,10 @@ static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
if (!obj->head) /* first on the queue */ if (!obj->head) /* first on the queue */
{ {
if (!add_select_user( file->fd, READ_EVENT | WRITE_EVENT, &select_ops, file )) int events = 0;
{ if (file->access & GENERIC_READ) events |= READ_EVENT;
SET_ERROR( ERROR_OUTOFMEMORY ); if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
return 0; set_select_events( &file->select, events );
}
} }
add_queue( obj, entry ); add_queue( obj, entry );
return 1; return 1;
@ -272,37 +271,44 @@ static void file_remove_queue( struct object *obj, struct wait_queue_entry *entr
remove_queue( obj, entry ); remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */ if (!obj->head) /* last on the queue is gone */
remove_select_user( file->fd ); set_select_events( &file->select, 0 );
release_object( obj ); release_object( obj );
} }
static int file_signaled( struct object *obj, struct thread *thread ) static int file_signaled( struct object *obj, struct thread *thread )
{ {
fd_set read_fds, write_fds; int events = 0;
struct timeval tv = { 0, 0 };
struct file *file = (struct file *)obj; struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
FD_ZERO( &read_fds ); if (file->access & GENERIC_READ) events |= READ_EVENT;
FD_ZERO( &write_fds ); if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
if (file->access & GENERIC_READ) FD_SET( file->fd, &read_fds ); if (check_select_events( &file->select, events ))
if (file->access & GENERIC_WRITE) FD_SET( file->fd, &write_fds ); {
return select( file->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0; /* stop waiting on select() if we are signaled */
set_select_events( &file->select, 0 );
return 1;
}
else
{
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( &file->select, events );
return 0;
}
} }
static int file_get_read_fd( struct object *obj ) static int file_get_read_fd( struct object *obj )
{ {
struct file *file = (struct file *)obj; struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
return dup( file->fd ); return dup( file->select.fd );
} }
static int file_get_write_fd( struct object *obj ) static int file_get_write_fd( struct object *obj )
{ {
struct file *file = (struct file *)obj; struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
return dup( file->fd ); return dup( file->select.fd );
} }
static int file_flush( struct object *obj ) static int file_flush( struct object *obj )
@ -311,7 +317,7 @@ static int file_flush( struct object *obj )
struct file *file = (struct file *)grab_object(obj); struct file *file = (struct file *)grab_object(obj);
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
ret = (fsync( file->fd ) != -1); ret = (fsync( file->select.fd ) != -1);
if (!ret) file_set_error(); if (!ret) file_set_error();
release_object( file ); release_object( file );
return ret; return ret;
@ -323,13 +329,13 @@ static int file_get_info( struct object *obj, struct get_file_info_reply *reply
struct file *file = (struct file *)obj; struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops ); assert( obj->ops == &file_ops );
if (fstat( file->fd, &st ) == -1) if (fstat( file->select.fd, &st ) == -1)
{ {
file_set_error(); file_set_error();
return 0; return 0;
} }
if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) || if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
S_ISSOCK(st.st_mode) || isatty(file->fd)) reply->type = FILE_TYPE_CHAR; S_ISSOCK(st.st_mode) || isatty(file->select.fd)) reply->type = FILE_TYPE_CHAR;
else reply->type = FILE_TYPE_DISK; else reply->type = FILE_TYPE_DISK;
if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY; if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY;
else reply->attr = FILE_ATTRIBUTE_ARCHIVE; else reply->attr = FILE_ATTRIBUTE_ARCHIVE;
@ -360,7 +366,8 @@ static void file_destroy( struct object *obj )
if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name ); if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
free( file->name ); free( file->name );
} }
close( file->fd ); unregister_select_user( &file->select );
close( file->select.fd );
free( file ); free( file );
} }
@ -397,7 +404,7 @@ struct file *get_file_obj( struct process *process, int handle,
int file_get_mmap_fd( struct file *file ) int file_get_mmap_fd( struct file *file )
{ {
return dup( file->fd ); return dup( file->select.fd );
} }
static int set_file_pointer( int handle, int *low, int *high, int whence ) static int set_file_pointer( int handle, int *low, int *high, int whence )
@ -414,7 +421,7 @@ static int set_file_pointer( int handle, int *low, int *high, int whence )
if (!(file = get_file_obj( current->process, handle, 0 ))) if (!(file = get_file_obj( current->process, handle, 0 )))
return 0; return 0;
if ((result = lseek( file->fd, *low, whence )) == -1) if ((result = lseek( file->select.fd, *low, whence )) == -1)
{ {
/* Check for seek before start of file */ /* Check for seek before start of file */
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0)) if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
@ -436,8 +443,8 @@ static int truncate_file( int handle )
if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE ))) if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
return 0; return 0;
if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) || if (((result = lseek( file->select.fd, 0, SEEK_CUR )) == -1) ||
(ftruncate( file->fd, result ) == -1)) (ftruncate( file->select.fd, result ) == -1))
{ {
file_set_error(); file_set_error();
release_object( file ); release_object( file );
@ -458,13 +465,13 @@ int grow_file( struct file *file, int size_high, int size_low )
SET_ERROR( ERROR_INVALID_PARAMETER ); SET_ERROR( ERROR_INVALID_PARAMETER );
return 0; return 0;
} }
if (fstat( file->fd, &st ) == -1) if (fstat( file->select.fd, &st ) == -1)
{ {
file_set_error(); file_set_error();
return 0; return 0;
} }
if (st.st_size >= size_low) return 1; /* already large enough */ if (st.st_size >= size_low) return 1; /* already large enough */
if (ftruncate( file->fd, size_low ) != -1) return 1; if (ftruncate( file->select.fd, size_low ) != -1) return 1;
file_set_error(); file_set_error();
return 0; return 0;
} }

View File

@ -26,10 +26,10 @@ enum side { READ_SIDE, WRITE_SIDE };
struct pipe struct pipe
{ {
struct object obj; /* object header */ struct object obj; /* object header */
struct pipe *other; /* the pipe other end */ struct pipe *other; /* the pipe other end */
int fd; /* Unix file descriptor */ struct select_user select; /* select user */
enum side side; /* which side of the pipe is this */ enum side side; /* which side of the pipe is this */
}; };
static void pipe_dump( struct object *obj, int verbose ); static void pipe_dump( struct object *obj, int verbose );
@ -55,11 +55,6 @@ static const struct object_ops pipe_ops =
pipe_destroy pipe_destroy
}; };
static const struct select_ops select_ops =
{
default_select_event,
NULL /* we never set a timeout on a pipe */
};
static int create_pipe( struct object *obj[2] ) static int create_pipe( struct object *obj[2] )
{ {
@ -86,14 +81,20 @@ static int create_pipe( struct object *obj[2] )
} }
init_object( &newpipe[0]->obj, &pipe_ops, NULL ); init_object( &newpipe[0]->obj, &pipe_ops, NULL );
init_object( &newpipe[1]->obj, &pipe_ops, NULL ); init_object( &newpipe[1]->obj, &pipe_ops, NULL );
newpipe[0]->fd = fd[0]; newpipe[0]->select.fd = fd[0];
newpipe[0]->other = newpipe[1]; newpipe[0]->select.func = default_select_event;
newpipe[0]->side = READ_SIDE; newpipe[0]->select.private = newpipe[0];
newpipe[1]->fd = fd[1]; newpipe[0]->other = newpipe[1];
newpipe[1]->other = newpipe[0]; newpipe[0]->side = READ_SIDE;
newpipe[1]->side = WRITE_SIDE; newpipe[1]->select.fd = fd[1];
newpipe[1]->select.func = default_select_event;
newpipe[1]->select.private = newpipe[1];
newpipe[1]->other = newpipe[0];
newpipe[1]->side = WRITE_SIDE;
obj[0] = &newpipe[0]->obj; obj[0] = &newpipe[0]->obj;
obj[1] = &newpipe[1]->obj; obj[1] = &newpipe[1]->obj;
register_select_user( &newpipe[0]->select );
register_select_user( &newpipe[1]->select );
CLEAR_ERROR(); CLEAR_ERROR();
return 1; return 1;
} }
@ -103,7 +104,7 @@ static void pipe_dump( struct object *obj, int verbose )
struct pipe *pipe = (struct pipe *)obj; struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops ); assert( obj->ops == &pipe_ops );
fprintf( stderr, "Pipe %s-side fd=%d\n", fprintf( stderr, "Pipe %s-side fd=%d\n",
(pipe->side == READ_SIDE) ? "read" : "write", pipe->fd ); (pipe->side == READ_SIDE) ? "read" : "write", pipe->select.fd );
} }
static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry ) static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
@ -111,15 +112,8 @@ static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
struct pipe *pipe = (struct pipe *)obj; struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops ); assert( obj->ops == &pipe_ops );
if (!obj->head) /* first on the queue */ if (!obj->head) /* first on the queue */
{ set_select_events( &pipe->select,
if (!add_select_user( pipe->fd, (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT );
(pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT,
&select_ops, pipe ))
{
SET_ERROR( ERROR_OUTOFMEMORY );
return 0;
}
}
add_queue( obj, entry ); add_queue( obj, entry );
return 1; return 1;
} }
@ -131,23 +125,29 @@ static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entr
remove_queue( obj, entry ); remove_queue( obj, entry );
if (!obj->head) /* last on the queue is gone */ if (!obj->head) /* last on the queue is gone */
remove_select_user( pipe->fd ); set_select_events( &pipe->select, 0 );
release_object( obj ); release_object( obj );
} }
static int pipe_signaled( struct object *obj, struct thread *thread ) static int pipe_signaled( struct object *obj, struct thread *thread )
{ {
int event;
struct pipe *pipe = (struct pipe *)obj; struct pipe *pipe = (struct pipe *)obj;
struct timeval tv = { 0, 0 };
fd_set fds;
assert( obj->ops == &pipe_ops ); assert( obj->ops == &pipe_ops );
FD_ZERO( &fds );
FD_SET( pipe->fd, &fds ); event = (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT;
if (pipe->side == READ_SIDE) if (check_select_events( &pipe->select, event ))
return select( pipe->fd + 1, &fds, NULL, NULL, &tv ) > 0; {
/* stop waiting on select() if we are signaled */
set_select_events( &pipe->select, 0 );
return 1;
}
else else
return select( pipe->fd + 1, NULL, &fds, NULL, &tv ) > 0; {
/* restart waiting on select() if we are no longer signaled */
if (obj->head) set_select_events( &pipe->select, event );
return 0;
}
} }
static int pipe_get_read_fd( struct object *obj ) static int pipe_get_read_fd( struct object *obj )
@ -165,7 +165,7 @@ static int pipe_get_read_fd( struct object *obj )
SET_ERROR( ERROR_ACCESS_DENIED ); SET_ERROR( ERROR_ACCESS_DENIED );
return -1; return -1;
} }
return dup( pipe->fd ); return dup( pipe->select.fd );
} }
static int pipe_get_write_fd( struct object *obj ) static int pipe_get_write_fd( struct object *obj )
@ -183,7 +183,7 @@ static int pipe_get_write_fd( struct object *obj )
SET_ERROR( ERROR_ACCESS_DENIED ); SET_ERROR( ERROR_ACCESS_DENIED );
return -1; return -1;
} }
return dup( pipe->fd ); return dup( pipe->select.fd );
} }
static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply ) static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply )
@ -199,7 +199,8 @@ static void pipe_destroy( struct object *obj )
assert( obj->ops == &pipe_ops ); assert( obj->ops == &pipe_ops );
if (pipe->other) pipe->other->other = NULL; if (pipe->other) pipe->other->other = NULL;
close( pipe->fd ); unregister_select_user( &pipe->select );
close( pipe->select.fd );
free( pipe ); free( pipe );
} }

View File

@ -40,6 +40,7 @@ struct thread_wait
int count; /* count of objects */ int count; /* count of objects */
int flags; int flags;
struct timeval timeout; struct timeval timeout;
struct timeout_user *user;
struct wait_queue_entry queues[1]; struct wait_queue_entry queues[1];
}; };
@ -80,21 +81,23 @@ static struct thread *first_thread = &initial_thread;
static void init_thread( struct thread *thread, int fd ) static void init_thread( struct thread *thread, int fd )
{ {
init_object( &thread->obj, &thread_ops, NULL ); init_object( &thread->obj, &thread_ops, NULL );
thread->client_fd = fd; thread->client = NULL;
thread->unix_pid = 0; /* not known yet */ thread->unix_pid = 0; /* not known yet */
thread->mutex = NULL; thread->teb = NULL;
thread->debugger = NULL; thread->mutex = NULL;
thread->wait = NULL; thread->debug_ctx = NULL;
thread->apc = NULL; thread->debug_first = NULL;
thread->apc_count = 0; thread->wait = NULL;
thread->error = 0; thread->apc = NULL;
thread->state = STARTING; thread->apc_count = 0;
thread->exit_code = 0x103; /* STILL_ACTIVE */ thread->error = 0;
thread->next = NULL; thread->state = STARTING;
thread->prev = NULL; thread->exit_code = 0x103; /* STILL_ACTIVE */
thread->priority = THREAD_PRIORITY_NORMAL; thread->next = NULL;
thread->affinity = 1; thread->prev = NULL;
thread->suspend = 0; thread->priority = THREAD_PRIORITY_NORMAL;
thread->affinity = 1;
thread->suspend = 0;
} }
/* create the initial thread and start the main server loop */ /* create the initial thread and start the main server loop */
@ -104,7 +107,7 @@ void create_initial_thread( int fd )
init_thread( &initial_thread, fd ); init_thread( &initial_thread, fd );
initial_thread.process = create_initial_process(); initial_thread.process = create_initial_process();
add_process_thread( initial_thread.process, &initial_thread ); add_process_thread( initial_thread.process, &initial_thread );
add_client( fd, &initial_thread ); initial_thread.client = add_client( fd, &initial_thread );
grab_object( &initial_thread ); /* so that we never free it */ grab_object( &initial_thread ); /* so that we never free it */
select_loop(); select_loop();
} }
@ -134,7 +137,7 @@ static struct thread *create_thread( int fd, void *pid, int suspend, int inherit
if ((*handle = alloc_handle( current->process, thread, if ((*handle = alloc_handle( current->process, thread,
THREAD_ALL_ACCESS, inherit )) == -1) goto error; THREAD_ALL_ACCESS, inherit )) == -1) goto error;
if (add_client( fd, thread ) == -1) if (!(thread->client = add_client( fd, thread )))
{ {
SET_ERROR( ERROR_TOO_MANY_OPEN_FILES ); SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
goto error; goto error;
@ -169,8 +172,8 @@ static void dump_thread( struct object *obj, int verbose )
struct thread *thread = (struct thread *)obj; struct thread *thread = (struct thread *)obj;
assert( obj->ops == &thread_ops ); assert( obj->ops == &thread_ops );
fprintf( stderr, "Thread pid=%d fd=%d\n", fprintf( stderr, "Thread pid=%d teb=%p client=%p\n",
thread->unix_pid, thread->client_fd ); thread->unix_pid, thread->teb, thread->client );
} }
static int thread_signaled( struct object *obj, struct thread *thread ) static int thread_signaled( struct object *obj, struct thread *thread )
@ -214,7 +217,7 @@ static int suspend_thread( struct thread *thread )
int old_count = thread->suspend; int old_count = thread->suspend;
if (thread->suspend < MAXIMUM_SUSPEND_COUNT) if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
{ {
if (!thread->suspend++) if (!(thread->process->suspend + thread->suspend++))
{ {
if (thread->unix_pid) kill( thread->unix_pid, SIGSTOP ); if (thread->unix_pid) kill( thread->unix_pid, SIGSTOP );
} }
@ -228,7 +231,7 @@ static int resume_thread( struct thread *thread )
int old_count = thread->suspend; int old_count = thread->suspend;
if (thread->suspend > 0) if (thread->suspend > 0)
{ {
if (!--thread->suspend) if (!(--thread->suspend + thread->process->suspend))
{ {
if (thread->unix_pid) kill( thread->unix_pid, SIGCONT ); if (thread->unix_pid) kill( thread->unix_pid, SIGCONT );
} }
@ -270,7 +273,7 @@ int send_reply( struct thread *thread, int pass_fd, int n,
vec[i].iov_len = va_arg( args, int ); vec[i].iov_len = va_arg( args, int );
} }
va_end( args ); va_end( args );
return send_reply_v( thread->client_fd, thread->error, pass_fd, vec, n ); return send_reply_v( thread->client, thread->error, pass_fd, vec, n );
} }
/* add a thread to an object wait queue; return 1 if OK, 0 on error */ /* add a thread to an object wait queue; return 1 if OK, 0 on error */
@ -306,7 +309,7 @@ static void end_wait( struct thread *thread )
assert( wait ); assert( wait );
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
entry->obj->ops->remove_queue( entry->obj, entry ); entry->obj->ops->remove_queue( entry->obj, entry );
if (wait->flags & SELECT_TIMEOUT) set_select_timeout( thread->client_fd, NULL ); if (wait->user) remove_timeout_user( wait->user );
free( wait ); free( wait );
thread->wait = NULL; thread->wait = NULL;
} }
@ -329,20 +332,8 @@ static int wait_on( struct thread *thread, int count,
thread->wait = wait; thread->wait = wait;
wait->count = count; wait->count = count;
wait->flags = flags; wait->flags = flags;
if (flags & SELECT_TIMEOUT) wait->user = NULL;
{ if (flags & SELECT_TIMEOUT) make_timeout( &wait->timeout, timeout );
gettimeofday( &wait->timeout, 0 );
if (timeout)
{
wait->timeout.tv_usec += (timeout % 1000) * 1000;
if (wait->timeout.tv_usec >= 1000000)
{
wait->timeout.tv_usec -= 1000000;
wait->timeout.tv_sec++;
}
wait->timeout.tv_sec += timeout / 1000;
}
}
for (i = 0, entry = wait->queues; i < count; i++, entry++) for (i = 0, entry = wait->queues; i < count; i++, entry++)
{ {
@ -375,8 +366,12 @@ static int check_wait( struct thread *thread, int *signaled )
assert( wait ); assert( wait );
if (wait->flags & SELECT_ALL) if (wait->flags & SELECT_ALL)
{ {
int not_ok = 0;
/* Note: we must check them all anyway, as some objects may
* want to do something when signaled, even if others are not */
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
if (!entry->obj->ops->signaled( entry->obj, thread )) goto other_checks; not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
if (not_ok) goto other_checks;
/* Wait satisfied: tell it to all objects */ /* Wait satisfied: tell it to all objects */
*signaled = 0; *signaled = 0;
for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
@ -458,11 +453,15 @@ static void sleep_on( struct thread *thread, int count, int *handles, int flags,
send_select_reply( thread, -1 ); send_select_reply( thread, -1 );
return; return;
} }
if (!wake_thread( thread )) if (wake_thread( thread )) return;
/* now we need to wait */
if (flags & SELECT_TIMEOUT)
{ {
/* we need to wait */ if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
if (flags & SELECT_TIMEOUT) call_timeout_handler, thread )))
set_select_timeout( thread->client_fd, &thread->wait->timeout ); {
send_select_reply( thread, -1 );
}
} }
} }
@ -470,6 +469,7 @@ static void sleep_on( struct thread *thread, int count, int *handles, int flags,
void thread_timeout(void) void thread_timeout(void)
{ {
assert( current->wait ); assert( current->wait );
current->wait->user = NULL;
end_wait( current ); end_wait( current );
send_select_reply( current, STATUS_TIMEOUT ); send_select_reply( current, STATUS_TIMEOUT );
} }
@ -513,7 +513,7 @@ void kill_thread( struct thread *thread, int exit_code )
{ {
if (thread->state == TERMINATED) return; /* already killed */ if (thread->state == TERMINATED) return; /* already killed */
if (thread->unix_pid) kill( thread->unix_pid, SIGTERM ); if (thread->unix_pid) kill( thread->unix_pid, SIGTERM );
remove_client( thread->client_fd, exit_code ); /* this will call thread_killed */ remove_client( thread->client, exit_code ); /* this will call thread_killed */
} }
/* a thread has been killed */ /* a thread has been killed */
@ -558,7 +558,9 @@ DECL_HANDLER(init_thread)
} }
current->state = RUNNING; current->state = RUNNING;
current->unix_pid = req->unix_pid; current->unix_pid = req->unix_pid;
if (current->suspend > 0) kill( current->unix_pid, SIGSTOP ); current->teb = req->teb;
if (current->suspend + current->process->suspend > 0)
kill( current->unix_pid, SIGSTOP );
reply.pid = current->process; reply.pid = current->process;
reply.tid = current; reply.tid = current;
send_reply( current, -1, 1, &reply, sizeof(reply) ); send_reply( current, -1, 1, &reply, sizeof(reply) );

View File

@ -19,7 +19,7 @@ struct process;
struct thread_wait; struct thread_wait;
struct thread_apc; struct thread_apc;
struct mutex; struct mutex;
struct debugger; struct debug_ctx;
enum run_state { STARTING, RUNNING, TERMINATED }; enum run_state { STARTING, RUNNING, TERMINATED };
@ -31,16 +31,18 @@ struct thread
struct thread *proc_next; /* per-process thread list */ struct thread *proc_next; /* per-process thread list */
struct thread *proc_prev; struct thread *proc_prev;
struct process *process; struct process *process;
struct mutex *mutex; /* list of currently owned mutexes */ struct mutex *mutex; /* list of currently owned mutexes */
struct debugger *debugger; /* debugger info if this thread is a debugger */ struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
struct process *debug_first; /* head of debugged processes list */
struct thread_wait *wait; /* current wait condition if sleeping */ struct thread_wait *wait; /* current wait condition if sleeping */
struct thread_apc *apc; /* list of async procedure calls */ struct thread_apc *apc; /* list of async procedure calls */
int apc_count; /* number of outstanding APCs */ int apc_count; /* number of outstanding APCs */
int error; /* current error code */ int error; /* current error code */
enum run_state state; /* running state */ enum run_state state; /* running state */
int exit_code; /* thread exit code */ int exit_code; /* thread exit code */
int client_fd; /* client fd for socket communications */ struct client *client; /* client for socket communications */
int unix_pid; /* Unix pid of client */ int unix_pid; /* Unix pid of client */
void *teb; /* TEB address (in client address space) */
int priority; /* priority level */ int priority; /* priority level */
int affinity; /* affinity mask */ int affinity; /* affinity mask */
int suspend; /* suspend count */ int suspend; /* suspend count */