From 57e1131334cd33d3876d3edddb15c00226b3603c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 16 May 1999 16:59:38 +0000 Subject: [PATCH] Adapted to new select interface. Fixed bug in *_signaled routines that could cause busy-waiting in the select loop. --- server/console.c | 105 +++++++++++++++++++++++++++++------------------------ server/file.c | 107 +++++++++++++++++++++++++++++-------------------------- server/pipe.c | 75 +++++++++++++++++++------------------- server/thread.c | 90 +++++++++++++++++++++++----------------------- server/thread.h | 10 +++--- 5 files changed, 206 insertions(+), 181 deletions(-) diff --git a/server/console.c b/server/console.c index d067c211fc7..774e65f0c40 100644 --- a/server/console.c +++ b/server/console.c @@ -33,7 +33,7 @@ struct screen_buffer; 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 console_input 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 @@ static const struct object_ops screen_buffer_ops = 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 @@ int create_console( int fd, struct object *obj[2] ) } 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 @@ static int set_console_fd( int handle, int fd, int pid ) 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 @@ static int set_console_fd( int handle, int fd, int pid ) 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 @@ static void console_input_dump( struct object *obj, int verbose ) { 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 @@ static int console_input_add_queue( struct object *obj, struct wait_queue_entry 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 @@ static void console_input_remove_queue( struct object *obj, struct wait_queue_en 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 @@ static void console_input_destroy( struct object *obj ) { 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 @@ static void screen_buffer_dump( struct object *obj, int verbose ) { 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 @@ static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry 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 @@ static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_en 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 ); diff --git a/server/file.c b/server/file.c index 00f1c60897b..041c67c1bf9 100644 --- a/server/file.c +++ b/server/file.c @@ -26,13 +26,13 @@ struct file { - struct object obj; /* object header */ - struct file *next; /* next file in hashing list */ - char *name; /* file name */ - int fd; /* Unix file descriptor */ - unsigned int access; /* file access (GENERIC_READ/WRITE) */ - unsigned int flags; /* flags (FILE_FLAG_*) */ - unsigned int sharing; /* file sharing mode */ + struct object obj; /* object header */ + struct select_user select; /* select user */ + struct file *next; /* next file in hashing list */ + char *name; /* file name */ + unsigned int access; /* file access (GENERIC_READ/WRITE) */ + unsigned int flags; /* flags (FILE_FLAG_*) */ + unsigned int sharing; /* file sharing mode */ }; #define NAME_HASH_SIZE 37 @@ -63,12 +63,6 @@ static const struct object_ops file_ops = 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 ) { @@ -194,10 +188,13 @@ static struct object *create_file( int fd, const char *name, unsigned int access file->next = NULL; } init_object( &file->obj, &file_ops, NULL ); - file->fd = fd; - file->access = access; - file->flags = attrs; - file->sharing = sharing; + file->select.fd = fd; + file->select.func = default_select_event; + file->select.private = file; + file->access = access; + file->flags = attrs; + file->sharing = sharing; + register_select_user( &file->select ); CLEAR_ERROR(); return &file->obj; } @@ -231,12 +228,15 @@ struct file *create_temp_file( int access ) return NULL; } init_object( &file->obj, &file_ops, NULL ); - file->name = NULL; - file->next = NULL; - file->fd = fd; - file->access = access; - file->flags = 0; - file->sharing = 0; + file->name = NULL; + file->next = NULL; + file->select.fd = fd; + file->select.func = default_select_event; + file->select.private = file; + file->access = access; + file->flags = 0; + file->sharing = 0; + register_select_user( &file->select ); CLEAR_ERROR(); return file; } @@ -246,7 +246,7 @@ static void file_dump( struct object *obj, int verbose ) struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); 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 ) @@ -255,11 +255,10 @@ static int file_add_queue( struct object *obj, struct wait_queue_entry *entry ) assert( obj->ops == &file_ops ); if (!obj->head) /* first on the queue */ { - if (!add_select_user( file->fd, READ_EVENT | WRITE_EVENT, &select_ops, file )) - { - SET_ERROR( ERROR_OUTOFMEMORY ); - return 0; - } + int events = 0; + if (file->access & GENERIC_READ) events |= READ_EVENT; + if (file->access & GENERIC_WRITE) events |= WRITE_EVENT; + set_select_events( &file->select, events ); } add_queue( obj, entry ); return 1; @@ -272,37 +271,44 @@ static void file_remove_queue( struct object *obj, struct wait_queue_entry *entr remove_queue( obj, entry ); if (!obj->head) /* last on the queue is gone */ - remove_select_user( file->fd ); + set_select_events( &file->select, 0 ); release_object( obj ); } static int file_signaled( struct object *obj, struct thread *thread ) { - fd_set read_fds, write_fds; - struct timeval tv = { 0, 0 }; - + int events = 0; struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); - FD_ZERO( &read_fds ); - FD_ZERO( &write_fds ); - if (file->access & GENERIC_READ) FD_SET( file->fd, &read_fds ); - if (file->access & GENERIC_WRITE) FD_SET( file->fd, &write_fds ); - return select( file->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0; + if (file->access & GENERIC_READ) events |= READ_EVENT; + if (file->access & GENERIC_WRITE) events |= WRITE_EVENT; + if (check_select_events( &file->select, events )) + { + /* 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 ) { struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); - return dup( file->fd ); + return dup( file->select.fd ); } static int file_get_write_fd( struct object *obj ) { struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); - return dup( file->fd ); + return dup( file->select.fd ); } 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); assert( obj->ops == &file_ops ); - ret = (fsync( file->fd ) != -1); + ret = (fsync( file->select.fd ) != -1); if (!ret) file_set_error(); release_object( file ); 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; assert( obj->ops == &file_ops ); - if (fstat( file->fd, &st ) == -1) + if (fstat( file->select.fd, &st ) == -1) { file_set_error(); return 0; } 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; if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY; 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 ); free( file->name ); } - close( file->fd ); + unregister_select_user( &file->select ); + close( file->select.fd ); free( file ); } @@ -397,7 +404,7 @@ struct file *get_file_obj( struct process *process, int handle, 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 ) @@ -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 ))) 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 */ 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 ))) return 0; - if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) || - (ftruncate( file->fd, result ) == -1)) + if (((result = lseek( file->select.fd, 0, SEEK_CUR )) == -1) || + (ftruncate( file->select.fd, result ) == -1)) { file_set_error(); release_object( file ); @@ -458,13 +465,13 @@ int grow_file( struct file *file, int size_high, int size_low ) SET_ERROR( ERROR_INVALID_PARAMETER ); return 0; } - if (fstat( file->fd, &st ) == -1) + if (fstat( file->select.fd, &st ) == -1) { file_set_error(); return 0; } 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(); return 0; } diff --git a/server/pipe.c b/server/pipe.c index 575f6f25413..368c7826688 100644 --- a/server/pipe.c +++ b/server/pipe.c @@ -26,10 +26,10 @@ enum side { READ_SIDE, WRITE_SIDE }; struct pipe { - struct object obj; /* object header */ - struct pipe *other; /* the pipe other end */ - int fd; /* Unix file descriptor */ - enum side side; /* which side of the pipe is this */ + struct object obj; /* object header */ + struct pipe *other; /* the pipe other end */ + struct select_user select; /* select user */ + enum side side; /* which side of the pipe is this */ }; static void pipe_dump( struct object *obj, int verbose ); @@ -55,11 +55,6 @@ static const struct object_ops pipe_ops = 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] ) { @@ -86,14 +81,20 @@ static int create_pipe( struct object *obj[2] ) } init_object( &newpipe[0]->obj, &pipe_ops, NULL ); init_object( &newpipe[1]->obj, &pipe_ops, NULL ); - newpipe[0]->fd = fd[0]; - newpipe[0]->other = newpipe[1]; - newpipe[0]->side = READ_SIDE; - newpipe[1]->fd = fd[1]; - newpipe[1]->other = newpipe[0]; - newpipe[1]->side = WRITE_SIDE; + newpipe[0]->select.fd = fd[0]; + newpipe[0]->select.func = default_select_event; + newpipe[0]->select.private = newpipe[0]; + newpipe[0]->other = newpipe[1]; + newpipe[0]->side = READ_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[1] = &newpipe[1]->obj; + register_select_user( &newpipe[0]->select ); + register_select_user( &newpipe[1]->select ); CLEAR_ERROR(); return 1; } @@ -103,7 +104,7 @@ static void pipe_dump( struct object *obj, int verbose ) struct pipe *pipe = (struct pipe *)obj; assert( obj->ops == &pipe_ops ); 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 ) @@ -111,15 +112,8 @@ static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry ) struct pipe *pipe = (struct pipe *)obj; assert( obj->ops == &pipe_ops ); if (!obj->head) /* first on the queue */ - { - if (!add_select_user( pipe->fd, - (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT, - &select_ops, pipe )) - { - SET_ERROR( ERROR_OUTOFMEMORY ); - return 0; - } - } + set_select_events( &pipe->select, + (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT ); add_queue( obj, entry ); return 1; } @@ -131,23 +125,29 @@ static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entr remove_queue( obj, entry ); if (!obj->head) /* last on the queue is gone */ - remove_select_user( pipe->fd ); + set_select_events( &pipe->select, 0 ); release_object( obj ); } static int pipe_signaled( struct object *obj, struct thread *thread ) { + int event; struct pipe *pipe = (struct pipe *)obj; - struct timeval tv = { 0, 0 }; - fd_set fds; - assert( obj->ops == &pipe_ops ); - FD_ZERO( &fds ); - FD_SET( pipe->fd, &fds ); - if (pipe->side == READ_SIDE) - return select( pipe->fd + 1, &fds, NULL, NULL, &tv ) > 0; + + event = (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT; + if (check_select_events( &pipe->select, event )) + { + /* stop waiting on select() if we are signaled */ + set_select_events( &pipe->select, 0 ); + return 1; + } 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 ) @@ -165,7 +165,7 @@ static int pipe_get_read_fd( struct object *obj ) SET_ERROR( ERROR_ACCESS_DENIED ); return -1; } - return dup( pipe->fd ); + return dup( pipe->select.fd ); } 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 ); 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 ) @@ -199,7 +199,8 @@ static void pipe_destroy( struct object *obj ) assert( obj->ops == &pipe_ops ); if (pipe->other) pipe->other->other = NULL; - close( pipe->fd ); + unregister_select_user( &pipe->select ); + close( pipe->select.fd ); free( pipe ); } diff --git a/server/thread.c b/server/thread.c index eff2b08cae1..d4fea46963c 100644 --- a/server/thread.c +++ b/server/thread.c @@ -40,6 +40,7 @@ struct thread_wait int count; /* count of objects */ int flags; struct timeval timeout; + struct timeout_user *user; 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 ) { init_object( &thread->obj, &thread_ops, NULL ); - thread->client_fd = fd; - thread->unix_pid = 0; /* not known yet */ - thread->mutex = NULL; - thread->debugger = NULL; - thread->wait = NULL; - thread->apc = NULL; - thread->apc_count = 0; - thread->error = 0; - thread->state = STARTING; - thread->exit_code = 0x103; /* STILL_ACTIVE */ - thread->next = NULL; - thread->prev = NULL; - thread->priority = THREAD_PRIORITY_NORMAL; - thread->affinity = 1; - thread->suspend = 0; + thread->client = NULL; + thread->unix_pid = 0; /* not known yet */ + thread->teb = NULL; + thread->mutex = NULL; + thread->debug_ctx = NULL; + thread->debug_first = NULL; + thread->wait = NULL; + thread->apc = NULL; + thread->apc_count = 0; + thread->error = 0; + thread->state = STARTING; + thread->exit_code = 0x103; /* STILL_ACTIVE */ + thread->next = NULL; + thread->prev = NULL; + thread->priority = THREAD_PRIORITY_NORMAL; + thread->affinity = 1; + thread->suspend = 0; } /* 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 ); initial_thread.process = create_initial_process(); 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 */ 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, 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 ); goto error; @@ -169,8 +172,8 @@ static void dump_thread( struct object *obj, int verbose ) struct thread *thread = (struct thread *)obj; assert( obj->ops == &thread_ops ); - fprintf( stderr, "Thread pid=%d fd=%d\n", - thread->unix_pid, thread->client_fd ); + fprintf( stderr, "Thread pid=%d teb=%p client=%p\n", + thread->unix_pid, thread->teb, thread->client ); } 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; if (thread->suspend < MAXIMUM_SUSPEND_COUNT) { - if (!thread->suspend++) + if (!(thread->process->suspend + thread->suspend++)) { 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; if (thread->suspend > 0) { - if (!--thread->suspend) + if (!(--thread->suspend + thread->process->suspend)) { 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 ); } 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 */ @@ -306,7 +309,7 @@ static void end_wait( struct thread *thread ) assert( wait ); for (i = 0, entry = wait->queues; i < wait->count; i++, 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 ); thread->wait = NULL; } @@ -329,20 +332,8 @@ static int wait_on( struct thread *thread, int count, thread->wait = wait; wait->count = count; wait->flags = flags; - if (flags & SELECT_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; - } - } + wait->user = NULL; + if (flags & SELECT_TIMEOUT) make_timeout( &wait->timeout, timeout ); 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 ); 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++) - 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 */ *signaled = 0; 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 ); return; } - if (!wake_thread( thread )) + if (wake_thread( thread )) return; + /* now we need to wait */ + if (flags & SELECT_TIMEOUT) { - /* we need to wait */ - if (flags & SELECT_TIMEOUT) - set_select_timeout( thread->client_fd, &thread->wait->timeout ); + if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout, + call_timeout_handler, thread ))) + { + 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) { assert( current->wait ); + current->wait->user = NULL; end_wait( current ); 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->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 */ @@ -558,7 +558,9 @@ DECL_HANDLER(init_thread) } current->state = RUNNING; 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.tid = current; send_reply( current, -1, 1, &reply, sizeof(reply) ); diff --git a/server/thread.h b/server/thread.h index fed1d185663..cffe25549ec 100644 --- a/server/thread.h +++ b/server/thread.h @@ -19,7 +19,7 @@ struct process; struct thread_wait; struct thread_apc; struct mutex; -struct debugger; +struct debug_ctx; enum run_state { STARTING, RUNNING, TERMINATED }; @@ -31,16 +31,18 @@ struct thread struct thread *proc_next; /* per-process thread list */ struct thread *proc_prev; struct process *process; - struct mutex *mutex; /* list of currently owned mutexes */ - struct debugger *debugger; /* debugger info if this thread is a debugger */ + struct mutex *mutex; /* list of currently owned mutexes */ + 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_apc *apc; /* list of async procedure calls */ int apc_count; /* number of outstanding APCs */ int error; /* current error code */ enum run_state state; /* running state */ 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 */ + void *teb; /* TEB address (in client address space) */ int priority; /* priority level */ int affinity; /* affinity mask */ int suspend; /* suspend count */ -- 2.11.4.GIT