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 );
diff --git a/server/file.c b/server/file.c
index 00f1c60..041c67c 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 575f6f2..368c782 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -26,10 +26,10 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 eff2b08..d4fea46 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -40,6 +40,7 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
void thread_timeout(void)
{
assert( current->wait );
+ current->wait->user = NULL;
end_wait( current );
send_select_reply( current, STATUS_TIMEOUT );
}
@@ -513,7 +513,7 @@
{
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 @@
}
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 fed1d18..cffe255 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -19,7 +19,7 @@
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 *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 */