Commit 57e11313 authored by Alexandre Julliard's avatar Alexandre Julliard

Adapted to new select interface.

Fixed bug in *_signaled routines that could cause busy-waiting in the select loop.
parent 88de35cd
......@@ -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 );
......
......@@ -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;
}
......
......@@ -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 );
}
......
......@@ -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) );
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment