Adapted to new select interface.
Fixed bug in *_signaled routines that could cause busy-waiting in the select loop.
This commit is contained in:
parent
88de35cd70
commit
57e1131334
105
server/console.c
105
server/console.c
|
@ -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 );
|
||||||
|
|
107
server/file.c
107
server/file.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) );
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue