forked from Mirrors/wine-wine
Moved poll handling to the generic part of the server objects.
Fixed busy waiting on POLLERR events. Merged struct client into struct thread.oldstable
parent
81ee21ddff
commit
1dca5e24c7
|
@ -25,7 +25,6 @@ C_SRCS = \
|
||||||
semaphore.c \
|
semaphore.c \
|
||||||
snapshot.c \
|
snapshot.c \
|
||||||
sock.c \
|
sock.c \
|
||||||
socket.c \
|
|
||||||
thread.c \
|
thread.c \
|
||||||
timer.c \
|
timer.c \
|
||||||
trace.c \
|
trace.c \
|
||||||
|
|
|
@ -27,24 +27,26 @@ static int change_signaled( struct object *obj, struct thread *thread );
|
||||||
|
|
||||||
static const struct object_ops change_ops =
|
static const struct object_ops change_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct change),
|
sizeof(struct change), /* size */
|
||||||
change_dump,
|
change_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
change_signaled,
|
change_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
no_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
no_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct change *create_change_notification( int subtree, int filter )
|
static struct change *create_change_notification( int subtree, int filter )
|
||||||
{
|
{
|
||||||
struct change *change;
|
struct change *change;
|
||||||
if ((change = alloc_object( &change_ops )))
|
if ((change = alloc_object( &change_ops, -1 )))
|
||||||
{
|
{
|
||||||
change->subtree = subtree;
|
change->subtree = subtree;
|
||||||
change->filter = filter;
|
change->filter = filter;
|
||||||
|
|
179
server/console.c
179
server/console.c
|
@ -38,8 +38,6 @@ struct screen_buffer;
|
||||||
struct console_input
|
struct console_input
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
int fd; /* file descriptor */
|
|
||||||
int select; /* select user id */
|
|
||||||
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 */
|
||||||
|
@ -49,8 +47,6 @@ struct console_input
|
||||||
struct screen_buffer
|
struct screen_buffer
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
int fd; /* file descriptor */
|
|
||||||
int select; /* select user id */
|
|
||||||
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) */
|
||||||
|
@ -61,16 +57,12 @@ struct screen_buffer
|
||||||
|
|
||||||
|
|
||||||
static void console_input_dump( struct object *obj, int verbose );
|
static void console_input_dump( struct object *obj, int verbose );
|
||||||
static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
static int console_input_get_poll_events( struct object *obj );
|
||||||
static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static int console_input_signaled( struct object *obj, struct thread *thread );
|
|
||||||
static int console_input_get_read_fd( struct object *obj );
|
static int console_input_get_read_fd( struct object *obj );
|
||||||
static void console_input_destroy( struct object *obj );
|
static void console_input_destroy( struct object *obj );
|
||||||
|
|
||||||
static void screen_buffer_dump( struct object *obj, int verbose );
|
static void screen_buffer_dump( struct object *obj, int verbose );
|
||||||
static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
static int screen_buffer_get_poll_events( struct object *obj );
|
||||||
static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static int screen_buffer_signaled( struct object *obj, struct thread *thread );
|
|
||||||
static int screen_buffer_get_write_fd( struct object *obj );
|
static int screen_buffer_get_write_fd( struct object *obj );
|
||||||
static void screen_buffer_destroy( struct object *obj );
|
static void screen_buffer_destroy( struct object *obj );
|
||||||
|
|
||||||
|
@ -79,32 +71,36 @@ static int console_get_info( struct object *obj, struct get_file_info_request *r
|
||||||
|
|
||||||
static const struct object_ops console_input_ops =
|
static const struct object_ops console_input_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct console_input),
|
sizeof(struct console_input), /* size */
|
||||||
console_input_dump,
|
console_input_dump, /* dump */
|
||||||
console_input_add_queue,
|
default_poll_add_queue, /* add_queue */
|
||||||
console_input_remove_queue,
|
default_poll_remove_queue, /* remove_queue */
|
||||||
console_input_signaled,
|
default_poll_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
console_input_get_read_fd,
|
console_input_get_poll_events, /* get_poll_events */
|
||||||
no_write_fd,
|
default_poll_event, /* poll_event */
|
||||||
no_flush,
|
console_input_get_read_fd, /* get_read_fd */
|
||||||
console_get_info,
|
no_write_fd, /* get_write_fd */
|
||||||
console_input_destroy
|
no_flush, /* flush */
|
||||||
|
console_get_info, /* get_file_info */
|
||||||
|
console_input_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct object_ops screen_buffer_ops =
|
static const struct object_ops screen_buffer_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct screen_buffer),
|
sizeof(struct screen_buffer), /* size */
|
||||||
screen_buffer_dump,
|
screen_buffer_dump, /* dump */
|
||||||
screen_buffer_add_queue,
|
default_poll_add_queue, /* add_queue */
|
||||||
screen_buffer_remove_queue,
|
default_poll_remove_queue, /* remove_queue */
|
||||||
screen_buffer_signaled,
|
default_poll_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
screen_buffer_get_poll_events, /* get_poll_events */
|
||||||
screen_buffer_get_write_fd,
|
default_poll_event, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
console_get_info,
|
screen_buffer_get_write_fd, /* get_write_fd */
|
||||||
screen_buffer_destroy
|
no_flush, /* flush */
|
||||||
|
console_get_info, /* get_file_info */
|
||||||
|
screen_buffer_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,21 +113,13 @@ static struct object *create_console_input( int fd )
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ((console_input = alloc_object( &console_input_ops )))
|
if (!(console_input = alloc_object( &console_input_ops, fd ))) return NULL;
|
||||||
{
|
|
||||||
console_input->fd = fd;
|
|
||||||
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 = NULL;
|
console_input->output = NULL;
|
||||||
console_input->recnum = 0;
|
console_input->recnum = 0;
|
||||||
console_input->records = NULL;
|
console_input->records = NULL;
|
||||||
console_input->select = add_select_user( fd, default_select_event, console_input );
|
return &console_input->obj;
|
||||||
if (console_input->select != -1) return &console_input->obj;
|
|
||||||
release_object( console_input );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
close( fd );
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct object *create_console_output( int fd, struct object *input )
|
static struct object *create_console_output( int fd, struct object *input )
|
||||||
|
@ -144,27 +132,16 @@ static struct object *create_console_output( int fd, struct object *input )
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ((screen_buffer = alloc_object( &screen_buffer_ops )))
|
if (!(screen_buffer = alloc_object( &screen_buffer_ops, fd ))) return NULL;
|
||||||
{
|
|
||||||
screen_buffer->fd = fd;
|
|
||||||
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" );
|
||||||
screen_buffer->select = add_select_user( fd, default_select_event, screen_buffer );
|
|
||||||
if (screen_buffer->select == -1)
|
|
||||||
{
|
|
||||||
release_object( screen_buffer );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
console_input->output = screen_buffer;
|
console_input->output = screen_buffer;
|
||||||
return &screen_buffer->obj;
|
return &screen_buffer->obj;
|
||||||
}
|
}
|
||||||
close( fd );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate a console for this process */
|
/* allocate a console for this process */
|
||||||
int alloc_console( struct process *process )
|
int alloc_console( struct process *process )
|
||||||
|
@ -223,10 +200,8 @@ static int set_console_fd( int handle, int fd_in, int fd_out, int pid )
|
||||||
assert( !input->obj.head );
|
assert( !input->obj.head );
|
||||||
assert( !output->obj.head );
|
assert( !output->obj.head );
|
||||||
|
|
||||||
change_select_fd( input->select, fd_in );
|
change_select_fd( &input->obj, fd_in );
|
||||||
change_select_fd( output->select, fd_out );
|
change_select_fd( &output->obj, fd_out );
|
||||||
input->fd = fd_in;
|
|
||||||
output->fd = fd_out;
|
|
||||||
output->pid = pid;
|
output->pid = pid;
|
||||||
release_object( input );
|
release_object( input );
|
||||||
release_object( output );
|
release_object( output );
|
||||||
|
@ -360,54 +335,19 @@ 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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
static int console_input_get_poll_events( struct object *obj )
|
||||||
{
|
{
|
||||||
struct console_input *console = (struct console_input *)obj;
|
return POLLIN;
|
||||||
assert( obj->ops == &console_input_ops );
|
|
||||||
if (!obj->head) /* first on the queue */
|
|
||||||
set_select_events( console->select, POLLIN );
|
|
||||||
add_queue( obj, entry );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void console_input_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
struct console_input *console = (struct console_input *)grab_object(obj);
|
|
||||||
assert( obj->ops == &console_input_ops );
|
|
||||||
|
|
||||||
remove_queue( obj, entry );
|
|
||||||
if (!obj->head) /* last on the queue is gone */
|
|
||||||
set_select_events( console->select, 0 );
|
|
||||||
release_object( obj );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int console_input_signaled( struct object *obj, struct thread *thread )
|
|
||||||
{
|
|
||||||
struct console_input *console = (struct console_input *)obj;
|
|
||||||
assert( obj->ops == &console_input_ops );
|
|
||||||
|
|
||||||
if (check_select_events( console->fd, POLLIN ))
|
|
||||||
{
|
|
||||||
/* 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, POLLIN );
|
|
||||||
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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int console_get_info( struct object *obj, struct get_file_info_request *req )
|
static int console_get_info( struct object *obj, struct get_file_info_request *req )
|
||||||
|
@ -429,7 +369,6 @@ 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 );
|
||||||
remove_select_user( console->select );
|
|
||||||
if (console->output) console->output->input = NULL;
|
if (console->output) console->output->input = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,61 +376,25 @@ 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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
static int screen_buffer_get_poll_events( struct object *obj )
|
||||||
{
|
{
|
||||||
struct screen_buffer *console = (struct screen_buffer *)obj;
|
return POLLOUT;
|
||||||
assert( obj->ops == &screen_buffer_ops );
|
|
||||||
if (!obj->head) /* first on the queue */
|
|
||||||
set_select_events( console->select, POLLOUT );
|
|
||||||
add_queue( obj, entry );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void screen_buffer_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
struct screen_buffer *console = (struct screen_buffer *)grab_object(obj);
|
|
||||||
assert( obj->ops == &screen_buffer_ops );
|
|
||||||
|
|
||||||
remove_queue( obj, entry );
|
|
||||||
if (!obj->head) /* last on the queue is gone */
|
|
||||||
set_select_events( console->select, 0 );
|
|
||||||
release_object( obj );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int screen_buffer_signaled( struct object *obj, struct thread *thread )
|
|
||||||
{
|
|
||||||
struct screen_buffer *console = (struct screen_buffer *)obj;
|
|
||||||
assert( obj->ops == &screen_buffer_ops );
|
|
||||||
|
|
||||||
if (check_select_events( console->fd, POLLOUT ))
|
|
||||||
{
|
|
||||||
/* 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, POLLOUT );
|
|
||||||
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->obj.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 );
|
||||||
remove_select_user( console->select );
|
|
||||||
if (console->input) console->input->output = NULL;
|
if (console->input) console->input->output = NULL;
|
||||||
if (console->title) free( console->title );
|
if (console->title) free( console->title );
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,23 +34,25 @@ static int device_get_info( struct object *obj, struct get_file_info_request *re
|
||||||
|
|
||||||
static const struct object_ops device_ops =
|
static const struct object_ops device_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct device),
|
sizeof(struct device), /* size */
|
||||||
device_dump,
|
device_dump, /* dump */
|
||||||
no_add_queue,
|
no_add_queue, /* add_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* remove_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* signaled */
|
||||||
NULL, /* should never get called */
|
NULL, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
device_get_info,
|
no_write_fd, /* get_write_fd */
|
||||||
no_destroy
|
no_flush, /* flush */
|
||||||
|
device_get_info, /* get_file_info */
|
||||||
|
no_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct device *create_device( int id )
|
static struct device *create_device( int id )
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
if ((dev = alloc_object( &device_ops )))
|
if ((dev = alloc_object( &device_ops, -1 )))
|
||||||
{
|
{
|
||||||
dev->id = id;
|
dev->id = id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,19 @@ static int event_satisfied( struct object *obj, struct thread *thread );
|
||||||
|
|
||||||
static const struct object_ops event_ops =
|
static const struct object_ops event_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct event),
|
sizeof(struct event), /* size */
|
||||||
event_dump,
|
event_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
event_signaled,
|
event_signaled, /* signaled */
|
||||||
event_satisfied,
|
event_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
no_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
no_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
120
server/file.c
120
server/file.c
|
@ -32,8 +32,6 @@
|
||||||
struct file
|
struct file
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
int fd; /* file descriptor */
|
|
||||||
int select; /* select user id */
|
|
||||||
struct file *next; /* next file in hashing list */
|
struct file *next; /* next file in hashing list */
|
||||||
char *name; /* file name */
|
char *name; /* file name */
|
||||||
unsigned int access; /* file access (GENERIC_READ/WRITE) */
|
unsigned int access; /* file access (GENERIC_READ/WRITE) */
|
||||||
|
@ -46,9 +44,7 @@ struct file
|
||||||
static struct file *file_hash[NAME_HASH_SIZE];
|
static struct file *file_hash[NAME_HASH_SIZE];
|
||||||
|
|
||||||
static void file_dump( struct object *obj, int verbose );
|
static void file_dump( struct object *obj, int verbose );
|
||||||
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
static int file_get_poll_events( struct object *obj );
|
||||||
static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static int file_signaled( struct object *obj, struct thread *thread );
|
|
||||||
static int file_get_read_fd( struct object *obj );
|
static int file_get_read_fd( struct object *obj );
|
||||||
static int file_get_write_fd( struct object *obj );
|
static int file_get_write_fd( struct object *obj );
|
||||||
static int file_flush( struct object *obj );
|
static int file_flush( struct object *obj );
|
||||||
|
@ -57,17 +53,19 @@ static void file_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops file_ops =
|
static const struct object_ops file_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct file),
|
sizeof(struct file), /* size */
|
||||||
file_dump,
|
file_dump, /* dump */
|
||||||
file_add_queue,
|
default_poll_add_queue, /* add_queue */
|
||||||
file_remove_queue,
|
default_poll_remove_queue, /* remove_queue */
|
||||||
file_signaled,
|
default_poll_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
file_get_read_fd,
|
file_get_poll_events, /* get_poll_events */
|
||||||
file_get_write_fd,
|
default_poll_event, /* poll_event */
|
||||||
file_flush,
|
file_get_read_fd, /* get_read_fd */
|
||||||
file_get_info,
|
file_get_write_fd, /* get_write_fd */
|
||||||
file_destroy
|
file_flush, /* flush */
|
||||||
|
file_get_info, /* get_file_info */
|
||||||
|
file_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,23 +101,19 @@ static int check_sharing( const char *name, int hash, unsigned int access,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create a file from a file descriptor */
|
||||||
|
/* if the function fails the fd is closed */
|
||||||
static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
|
static struct file *create_file_for_fd( int fd, unsigned int access, unsigned int sharing,
|
||||||
unsigned int attrs )
|
unsigned int attrs )
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
if ((file = alloc_object( &file_ops )))
|
if ((file = alloc_object( &file_ops, fd )))
|
||||||
{
|
{
|
||||||
file->name = NULL;
|
file->name = NULL;
|
||||||
file->next = NULL;
|
file->next = NULL;
|
||||||
file->fd = fd;
|
|
||||||
file->access = access;
|
file->access = access;
|
||||||
file->flags = attrs;
|
file->flags = attrs;
|
||||||
file->sharing = sharing;
|
file->sharing = sharing;
|
||||||
if ((file->select = add_select_user( fd, default_select_event, file )) == -1)
|
|
||||||
{
|
|
||||||
release_object( file );
|
|
||||||
file = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +165,11 @@ static struct file *create_file( const char *nameptr, size_t len, unsigned int a
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(file = create_file_for_fd( fd, access, sharing, attrs ))) goto error;
|
if (!(file = create_file_for_fd( fd, access, sharing, attrs )))
|
||||||
|
{
|
||||||
|
free( name );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
file->name = name;
|
file->name = name;
|
||||||
file->next = file_hash[hash];
|
file->next = file_hash[hash];
|
||||||
file_hash[hash] = file;
|
file_hash[hash] = file;
|
||||||
|
@ -212,81 +210,41 @@ int create_anonymous_file(void)
|
||||||
/* Create a temp file for anonymous mappings */
|
/* Create a temp file for anonymous mappings */
|
||||||
struct file *create_temp_file( int access )
|
struct file *create_temp_file( int access )
|
||||||
{
|
{
|
||||||
struct file *file;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if ((fd = create_anonymous_file()) == -1) return NULL;
|
if ((fd = create_anonymous_file()) == -1) return NULL;
|
||||||
if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
|
return create_file_for_fd( fd, access, 0, 0 );
|
||||||
return file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void file_dump( struct object *obj, int verbose )
|
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 );
|
||||||
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->fd, file->flags, file->name );
|
fprintf( stderr, "File fd=%d flags=%08x name='%s'\n", file->obj.fd, file->flags, file->name );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
static int file_get_poll_events( struct object *obj )
|
||||||
{
|
{
|
||||||
struct file *file = (struct file *)obj;
|
struct file *file = (struct file *)obj;
|
||||||
assert( obj->ops == &file_ops );
|
|
||||||
if (!obj->head) /* first on the queue */
|
|
||||||
{
|
|
||||||
int events = 0;
|
int events = 0;
|
||||||
|
assert( obj->ops == &file_ops );
|
||||||
if (file->access & GENERIC_READ) events |= POLLIN;
|
if (file->access & GENERIC_READ) events |= POLLIN;
|
||||||
if (file->access & GENERIC_WRITE) events |= POLLOUT;
|
if (file->access & GENERIC_WRITE) events |= POLLOUT;
|
||||||
set_select_events( file->select, events );
|
return events;
|
||||||
}
|
|
||||||
add_queue( obj, entry );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void file_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
struct file *file = (struct file *)grab_object(obj);
|
|
||||||
assert( obj->ops == &file_ops );
|
|
||||||
|
|
||||||
remove_queue( obj, entry );
|
|
||||||
if (!obj->head) /* last on the queue is gone */
|
|
||||||
set_select_events( file->select, 0 );
|
|
||||||
release_object( obj );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int file_signaled( struct object *obj, struct thread *thread )
|
|
||||||
{
|
|
||||||
int events = 0;
|
|
||||||
struct file *file = (struct file *)obj;
|
|
||||||
assert( obj->ops == &file_ops );
|
|
||||||
|
|
||||||
if (file->access & GENERIC_READ) events |= POLLIN;
|
|
||||||
if (file->access & GENERIC_WRITE) events |= POLLOUT;
|
|
||||||
if (check_select_events( file->fd, 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 )
|
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->obj.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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_flush( struct object *obj )
|
static int file_flush( struct object *obj )
|
||||||
|
@ -295,7 +253,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->obj.fd ) != -1);
|
||||||
if (!ret) file_set_error();
|
if (!ret) file_set_error();
|
||||||
release_object( file );
|
release_object( file );
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -307,13 +265,13 @@ static int file_get_info( struct object *obj, struct get_file_info_request *req
|
||||||
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->obj.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)) req->type = FILE_TYPE_CHAR;
|
S_ISSOCK(st.st_mode) || isatty(file->obj.fd)) req->type = FILE_TYPE_CHAR;
|
||||||
else req->type = FILE_TYPE_DISK;
|
else req->type = FILE_TYPE_DISK;
|
||||||
if (S_ISDIR(st.st_mode)) req->attr = FILE_ATTRIBUTE_DIRECTORY;
|
if (S_ISDIR(st.st_mode)) req->attr = FILE_ATTRIBUTE_DIRECTORY;
|
||||||
else req->attr = FILE_ATTRIBUTE_ARCHIVE;
|
else req->attr = FILE_ATTRIBUTE_ARCHIVE;
|
||||||
|
@ -344,7 +302,6 @@ 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 );
|
||||||
}
|
}
|
||||||
remove_select_user( file->select );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the last error depending on errno */
|
/* set the last error depending on errno */
|
||||||
|
@ -379,7 +336,7 @@ struct file *get_file_obj( struct process *process, int handle, unsigned int acc
|
||||||
|
|
||||||
int file_get_mmap_fd( struct file *file )
|
int file_get_mmap_fd( struct file *file )
|
||||||
{
|
{
|
||||||
return dup( file->fd );
|
return dup( file->obj.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 )
|
||||||
|
@ -396,7 +353,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->obj.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))
|
||||||
|
@ -418,8 +375,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->obj.fd, 0, SEEK_CUR )) == -1) ||
|
||||||
(ftruncate( file->fd, result ) == -1))
|
(ftruncate( file->obj.fd, result ) == -1))
|
||||||
{
|
{
|
||||||
file_set_error();
|
file_set_error();
|
||||||
release_object( file );
|
release_object( file );
|
||||||
|
@ -440,13 +397,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->obj.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->obj.fd, size_low ) != -1) return 1;
|
||||||
file_set_error();
|
file_set_error();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -518,7 +475,6 @@ DECL_HANDLER(alloc_file_handle)
|
||||||
req->handle = alloc_handle( current->process, file, req->access, 0 );
|
req->handle = alloc_handle( current->process, file, req->access, 0 );
|
||||||
release_object( file );
|
release_object( file );
|
||||||
}
|
}
|
||||||
else close( fd );
|
|
||||||
}
|
}
|
||||||
else file_set_error();
|
else file_set_error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,17 +69,19 @@ static void handle_table_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops handle_table_ops =
|
static const struct object_ops handle_table_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct handle_table),
|
sizeof(struct handle_table), /* size */
|
||||||
handle_table_dump,
|
handle_table_dump, /* dump */
|
||||||
no_add_queue,
|
no_add_queue, /* add_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* remove_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* signaled */
|
||||||
NULL, /* should never get called */
|
NULL, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
handle_table_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
handle_table_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* dump a handle table */
|
/* dump a handle table */
|
||||||
|
@ -127,7 +129,7 @@ struct object *alloc_handle_table( struct process *process, int count )
|
||||||
struct handle_table *table;
|
struct handle_table *table;
|
||||||
|
|
||||||
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
|
if (count < MIN_HANDLE_ENTRIES) count = MIN_HANDLE_ENTRIES;
|
||||||
if (!(table = alloc_object( &handle_table_ops )))
|
if (!(table = alloc_object( &handle_table_ops, -1 )))
|
||||||
return NULL;
|
return NULL;
|
||||||
table->process = process;
|
table->process = process;
|
||||||
table->count = count;
|
table->count = count;
|
||||||
|
|
|
@ -32,17 +32,19 @@ static void mapping_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops mapping_ops =
|
static const struct object_ops mapping_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct mapping),
|
sizeof(struct mapping), /* size */
|
||||||
mapping_dump,
|
mapping_dump, /* dump */
|
||||||
no_add_queue,
|
no_add_queue, /* add_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* remove_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* signaled */
|
||||||
NULL, /* should never get called */
|
NULL, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
mapping_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
mapping_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
|
|
@ -32,17 +32,19 @@ static void mutex_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops mutex_ops =
|
static const struct object_ops mutex_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct mutex),
|
sizeof(struct mutex), /* size */
|
||||||
mutex_dump,
|
mutex_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
mutex_signaled,
|
mutex_signaled, /* signaled */
|
||||||
mutex_satisfied,
|
mutex_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
mutex_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
mutex_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
@ -121,31 +122,42 @@ static void set_object_name( struct object *obj, struct object_name *ptr )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate and initialize an object */
|
/* allocate and initialize an object */
|
||||||
void *alloc_object( const struct object_ops *ops )
|
/* if the function fails the fd is closed */
|
||||||
|
void *alloc_object( const struct object_ops *ops, int fd )
|
||||||
{
|
{
|
||||||
struct object *obj = mem_alloc( ops->size );
|
struct object *obj = mem_alloc( ops->size );
|
||||||
if (obj)
|
if (obj)
|
||||||
{
|
{
|
||||||
obj->refcount = 1;
|
obj->refcount = 1;
|
||||||
|
obj->fd = fd;
|
||||||
|
obj->select = -1;
|
||||||
obj->ops = ops;
|
obj->ops = ops;
|
||||||
obj->head = NULL;
|
obj->head = NULL;
|
||||||
obj->tail = NULL;
|
obj->tail = NULL;
|
||||||
obj->name = NULL;
|
obj->name = NULL;
|
||||||
|
if ((fd != -1) && (add_select_user( obj ) == -1))
|
||||||
|
{
|
||||||
|
close( fd );
|
||||||
|
free( obj );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
obj->prev = NULL;
|
obj->prev = NULL;
|
||||||
if ((obj->next = first) != NULL) obj->next->prev = obj;
|
if ((obj->next = first) != NULL) obj->next->prev = obj;
|
||||||
first = obj;
|
first = obj;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
if (fd != -1) close( fd );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len )
|
void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len )
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
struct object_name *name_ptr;
|
struct object_name *name_ptr;
|
||||||
|
|
||||||
if (!name || !len) return alloc_object( ops );
|
if (!name || !len) return alloc_object( ops, -1 );
|
||||||
if (!(name_ptr = alloc_name( name, len ))) return NULL;
|
if (!(name_ptr = alloc_name( name, len ))) return NULL;
|
||||||
|
|
||||||
if ((obj = find_object( name_ptr->name, name_ptr->len )))
|
if ((obj = find_object( name_ptr->name, name_ptr->len )))
|
||||||
|
@ -159,7 +171,7 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size
|
||||||
set_error( ERROR_INVALID_HANDLE );
|
set_error( ERROR_INVALID_HANDLE );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if ((obj = alloc_object( ops )))
|
if ((obj = alloc_object( ops, -1 )))
|
||||||
{
|
{
|
||||||
set_object_name( obj, name_ptr );
|
set_object_name( obj, name_ptr );
|
||||||
clear_error();
|
clear_error();
|
||||||
|
@ -199,14 +211,16 @@ void release_object( void *ptr )
|
||||||
/* if the refcount is 0, nobody can be in the wait queue */
|
/* if the refcount is 0, nobody can be in the wait queue */
|
||||||
assert( !obj->head );
|
assert( !obj->head );
|
||||||
assert( !obj->tail );
|
assert( !obj->tail );
|
||||||
|
obj->ops->destroy( obj );
|
||||||
if (obj->name) free_name( obj );
|
if (obj->name) free_name( obj );
|
||||||
|
if (obj->select != -1) remove_select_user( obj );
|
||||||
|
if (obj->fd != -1) close( obj->fd );
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
if (obj->next) obj->next->prev = obj->prev;
|
if (obj->next) obj->next->prev = obj->prev;
|
||||||
if (obj->prev) obj->prev->next = obj->next;
|
if (obj->prev) obj->prev->next = obj->next;
|
||||||
else first = obj->next;
|
else first = obj->next;
|
||||||
#endif
|
|
||||||
obj->ops->destroy( obj );
|
|
||||||
memset( obj, 0xaa, obj->ops->size );
|
memset( obj, 0xaa, obj->ops->size );
|
||||||
|
#endif
|
||||||
free( obj );
|
free( obj );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +238,7 @@ struct object *find_object( const WCHAR *name, size_t len )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* functions for unimplemented object operations */
|
/* functions for unimplemented/default object operations */
|
||||||
|
|
||||||
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
|
@ -265,9 +279,45 @@ void no_destroy( struct object *obj )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void default_select_event( int event, void *private )
|
/* default add_queue() routine for objects that poll() on an fd */
|
||||||
|
int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
{
|
{
|
||||||
struct object *obj = (struct object *)private;
|
if (!obj->head) /* first on the queue */
|
||||||
assert( obj );
|
set_select_events( obj, obj->ops->get_poll_events( obj ) );
|
||||||
|
add_queue( obj, entry );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default remove_queue() routine for objects that poll() on an fd */
|
||||||
|
void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
||||||
|
{
|
||||||
|
grab_object(obj);
|
||||||
|
remove_queue( obj, entry );
|
||||||
|
if (!obj->head) /* last on the queue is gone */
|
||||||
|
set_select_events( obj, 0 );
|
||||||
|
release_object( obj );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default signaled() routine for objects that poll() on an fd */
|
||||||
|
int default_poll_signaled( struct object *obj, struct thread *thread )
|
||||||
|
{
|
||||||
|
int events = obj->ops->get_poll_events( obj );
|
||||||
|
|
||||||
|
if (check_select_events( obj->fd, events ))
|
||||||
|
{
|
||||||
|
/* stop waiting on select() if we are signaled */
|
||||||
|
set_select_events( obj, 0 );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* restart waiting on select() if we are no longer signaled */
|
||||||
|
if (obj->head) set_select_events( obj, events );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* default handler for poll() events */
|
||||||
|
void default_poll_event( struct object *obj, int event )
|
||||||
|
{
|
||||||
|
/* an error occurred, stop polling this fd to avoid busy-looping */
|
||||||
|
if (event & (POLLERR | POLLHUP)) set_select_events( obj, -1 );
|
||||||
wake_up( obj, 0 );
|
wake_up( obj, 0 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,10 @@ struct object_ops
|
||||||
int (*signaled)(struct object *,struct thread *);
|
int (*signaled)(struct object *,struct thread *);
|
||||||
/* wait satisfied; return 1 if abandoned */
|
/* wait satisfied; return 1 if abandoned */
|
||||||
int (*satisfied)(struct object *,struct thread *);
|
int (*satisfied)(struct object *,struct thread *);
|
||||||
|
/* get the events we want to poll() for on this object */
|
||||||
|
int (*get_poll_events)(struct object *);
|
||||||
|
/* a poll() event occured */
|
||||||
|
void (*poll_event)(struct object *,int event);
|
||||||
/* return a Unix fd that can be used to read from the object */
|
/* return a Unix fd that can be used to read from the object */
|
||||||
int (*get_read_fd)(struct object *);
|
int (*get_read_fd)(struct object *);
|
||||||
/* return a Unix fd that can be used to write to the object */
|
/* return a Unix fd that can be used to write to the object */
|
||||||
|
@ -55,7 +59,9 @@ struct object_ops
|
||||||
|
|
||||||
struct object
|
struct object
|
||||||
{
|
{
|
||||||
unsigned int refcount;
|
unsigned int refcount; /* reference count */
|
||||||
|
int fd; /* file descriptor */
|
||||||
|
int select; /* select() user id */
|
||||||
const struct object_ops *ops;
|
const struct object_ops *ops;
|
||||||
struct wait_queue_entry *head;
|
struct wait_queue_entry *head;
|
||||||
struct wait_queue_entry *tail;
|
struct wait_queue_entry *tail;
|
||||||
|
@ -68,7 +74,7 @@ struct object
|
||||||
|
|
||||||
extern void *mem_alloc( size_t size ); /* malloc wrapper */
|
extern void *mem_alloc( size_t size ); /* malloc wrapper */
|
||||||
extern void *memdup( const void *data, size_t len );
|
extern void *memdup( const void *data, size_t len );
|
||||||
extern void *alloc_object( const struct object_ops *ops );
|
extern void *alloc_object( const struct object_ops *ops, int fd );
|
||||||
extern void dump_object_name( struct object *obj );
|
extern void dump_object_name( struct object *obj );
|
||||||
extern void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len );
|
extern void *create_named_object( const struct object_ops *ops, const WCHAR *name, size_t len );
|
||||||
/* grab/release_object can take any pointer, but you better make sure */
|
/* grab/release_object can take any pointer, but you better make sure */
|
||||||
|
@ -83,17 +89,20 @@ extern int no_write_fd( struct object *obj );
|
||||||
extern int no_flush( struct object *obj );
|
extern int no_flush( struct object *obj );
|
||||||
extern int no_get_file_info( struct object *obj, struct get_file_info_request *info );
|
extern int no_get_file_info( struct object *obj, struct get_file_info_request *info );
|
||||||
extern void no_destroy( struct object *obj );
|
extern void no_destroy( struct object *obj );
|
||||||
extern void default_select_event( int event, void *private );
|
extern int default_poll_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
|
extern void default_poll_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
|
extern int default_poll_signaled( struct object *obj, struct thread *thread );
|
||||||
|
extern void default_poll_event( struct object *obj, int event );
|
||||||
#ifdef DEBUG_OBJECTS
|
#ifdef DEBUG_OBJECTS
|
||||||
extern void dump_objects(void);
|
extern void dump_objects(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* select functions */
|
/* select functions */
|
||||||
|
|
||||||
extern int add_select_user( int fd, void (*func)(int, void *), void *private );
|
extern int add_select_user( struct object *obj );
|
||||||
extern void remove_select_user( int user );
|
extern void remove_select_user( struct object *obj );
|
||||||
extern void change_select_fd( int user, int fd );
|
extern void change_select_fd( struct object *obj, int fd );
|
||||||
extern void set_select_events( int user, int events );
|
extern void set_select_events( struct object *obj, int events );
|
||||||
extern int check_select_events( int fd, int events );
|
extern int check_select_events( int fd, int events );
|
||||||
extern void select_loop(void);
|
extern void select_loop(void);
|
||||||
|
|
||||||
|
@ -114,15 +123,6 @@ static inline int time_before( struct timeval *t1, struct timeval *t2 )
|
||||||
((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
|
((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* socket functions */
|
|
||||||
|
|
||||||
struct client;
|
|
||||||
|
|
||||||
extern struct client *add_client( int client_fd, struct thread *self );
|
|
||||||
extern void remove_client( struct client *client, int exit_code );
|
|
||||||
extern void client_pass_fd( struct client *client, int pass_fd );
|
|
||||||
extern void client_reply( struct client *client, unsigned int res );
|
|
||||||
|
|
||||||
/* event functions */
|
/* event functions */
|
||||||
|
|
||||||
struct event;
|
struct event;
|
||||||
|
|
|
@ -33,15 +33,11 @@ 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; /* file descriptor */
|
|
||||||
int select; /* select user id */
|
|
||||||
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 );
|
||||||
static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
static int pipe_get_poll_events( struct object *obj );
|
||||||
static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static int pipe_signaled( struct object *obj, struct thread *thread );
|
|
||||||
static int pipe_get_read_fd( struct object *obj );
|
static int pipe_get_read_fd( struct object *obj );
|
||||||
static int pipe_get_write_fd( struct object *obj );
|
static int pipe_get_write_fd( struct object *obj );
|
||||||
static int pipe_get_info( struct object *obj, struct get_file_info_request *req );
|
static int pipe_get_info( struct object *obj, struct get_file_info_request *req );
|
||||||
|
@ -49,17 +45,19 @@ static void pipe_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops pipe_ops =
|
static const struct object_ops pipe_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct pipe),
|
sizeof(struct pipe), /* size */
|
||||||
pipe_dump,
|
pipe_dump, /* dump */
|
||||||
pipe_add_queue,
|
default_poll_add_queue, /* add_queue */
|
||||||
pipe_remove_queue,
|
default_poll_remove_queue, /* remove_queue */
|
||||||
pipe_signaled,
|
default_poll_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
pipe_get_read_fd,
|
pipe_get_poll_events, /* get_poll_events */
|
||||||
pipe_get_write_fd,
|
default_poll_event, /* poll_event */
|
||||||
no_flush,
|
pipe_get_read_fd, /* get_read_fd */
|
||||||
pipe_get_info,
|
pipe_get_write_fd, /* get_write_fd */
|
||||||
pipe_destroy
|
no_flush, /* flush */
|
||||||
|
pipe_get_info, /* get_file_info */
|
||||||
|
pipe_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,16 +65,10 @@ static struct pipe *create_pipe_side( int fd, int side )
|
||||||
{
|
{
|
||||||
struct pipe *pipe;
|
struct pipe *pipe;
|
||||||
|
|
||||||
if ((pipe = alloc_object( &pipe_ops )))
|
if ((pipe = alloc_object( &pipe_ops, fd )))
|
||||||
{
|
{
|
||||||
pipe->fd = fd;
|
|
||||||
pipe->other = NULL;
|
pipe->other = NULL;
|
||||||
pipe->side = side;
|
pipe->side = side;
|
||||||
if ((pipe->select = add_select_user( fd, default_select_event, pipe )) == -1)
|
|
||||||
{
|
|
||||||
release_object( pipe );
|
|
||||||
pipe = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
@ -104,8 +96,7 @@ static int create_pipe( struct object *obj[2] )
|
||||||
}
|
}
|
||||||
release_object( read_pipe );
|
release_object( read_pipe );
|
||||||
}
|
}
|
||||||
close( fd[0] );
|
else close( fd[1] );
|
||||||
close( fd[1] );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,49 +105,14 @@ 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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
static int pipe_get_poll_events( struct object *obj )
|
||||||
{
|
{
|
||||||
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 */
|
return (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
|
||||||
set_select_events( pipe->select, (pipe->side == READ_SIDE) ? POLLIN : POLLOUT );
|
|
||||||
add_queue( obj, entry );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pipe_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
struct pipe *pipe = (struct pipe *)grab_object(obj);
|
|
||||||
assert( obj->ops == &pipe_ops );
|
|
||||||
|
|
||||||
remove_queue( obj, entry );
|
|
||||||
if (!obj->head) /* last on the queue is gone */
|
|
||||||
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;
|
|
||||||
assert( obj->ops == &pipe_ops );
|
|
||||||
|
|
||||||
event = (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
|
|
||||||
if (check_select_events( pipe->fd, event ))
|
|
||||||
{
|
|
||||||
/* stop waiting on select() if we are signaled */
|
|
||||||
set_select_events( pipe->select, 0 );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 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 )
|
||||||
|
@ -174,7 +130,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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_get_write_fd( struct object *obj )
|
static int pipe_get_write_fd( struct object *obj )
|
||||||
|
@ -192,7 +148,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->obj.fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pipe_get_info( struct object *obj, struct get_file_info_request *req )
|
static int pipe_get_info( struct object *obj, struct get_file_info_request *req )
|
||||||
|
@ -216,7 +172,6 @@ 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;
|
||||||
remove_select_user( pipe->select );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create an anonymous pipe */
|
/* create an anonymous pipe */
|
||||||
|
|
|
@ -36,17 +36,19 @@ static void process_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops process_ops =
|
static const struct object_ops process_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct process),
|
sizeof(struct process), /* size */
|
||||||
process_dump,
|
process_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
process_signaled,
|
process_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
process_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
process_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,7 +58,7 @@ static struct process *create_process( struct process *parent, struct new_proces
|
||||||
{
|
{
|
||||||
struct process *process;
|
struct process *process;
|
||||||
|
|
||||||
if (!(process = alloc_object( &process_ops ))) return NULL;
|
if (!(process = alloc_object( &process_ops, -1 ))) return NULL;
|
||||||
process->next = NULL;
|
process->next = NULL;
|
||||||
process->prev = NULL;
|
process->prev = NULL;
|
||||||
process->thread_list = NULL;
|
process->thread_list = NULL;
|
||||||
|
|
|
@ -106,17 +106,19 @@ static void key_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops key_ops =
|
static const struct object_ops key_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct key),
|
sizeof(struct key), /* size */
|
||||||
key_dump,
|
key_dump, /* dump */
|
||||||
no_add_queue,
|
no_add_queue, /* add_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* remove_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* signaled */
|
||||||
NULL, /* should never get called */
|
NULL, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
key_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
key_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -322,7 +324,7 @@ static WCHAR *req_strdupW( const WCHAR *str )
|
||||||
static struct key *alloc_key( const WCHAR *name, time_t modif )
|
static struct key *alloc_key( const WCHAR *name, time_t modif )
|
||||||
{
|
{
|
||||||
struct key *key;
|
struct key *key;
|
||||||
if ((key = (struct key *)alloc_object( &key_ops )))
|
if ((key = (struct key *)alloc_object( &key_ops, -1 )))
|
||||||
{
|
{
|
||||||
key->name = NULL;
|
key->name = NULL;
|
||||||
key->class = NULL;
|
key->class = NULL;
|
||||||
|
|
148
server/request.c
148
server/request.c
|
@ -4,13 +4,20 @@
|
||||||
* Copyright (C) 1998 Alexandre Julliard
|
* Copyright (C) 1998 Alexandre Julliard
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
# include <sys/socket.h>
|
||||||
|
#endif
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -23,8 +30,29 @@
|
||||||
#define WANT_REQUEST_HANDLERS
|
#define WANT_REQUEST_HANDLERS
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
|
|
||||||
|
/* Some versions of glibc don't define this */
|
||||||
|
#ifndef SCM_RIGHTS
|
||||||
|
#define SCM_RIGHTS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct thread *current = NULL; /* thread handling the current request */
|
struct thread *current = NULL; /* thread handling the current request */
|
||||||
|
|
||||||
|
|
||||||
|
/* socket communication static structures */
|
||||||
|
static struct iovec myiovec;
|
||||||
|
static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
|
||||||
|
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
||||||
|
struct cmsg_fd
|
||||||
|
{
|
||||||
|
int len; /* sizeof structure */
|
||||||
|
int level; /* SOL_SOCKET */
|
||||||
|
int type; /* SCM_RIGHTS */
|
||||||
|
int fd; /* fd to pass */
|
||||||
|
};
|
||||||
|
static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
|
||||||
|
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
|
||||||
/* complain about a protocol error and terminate the client connection */
|
/* complain about a protocol error and terminate the client connection */
|
||||||
void fatal_protocol_error( struct thread *thread, const char *err, ... )
|
void fatal_protocol_error( struct thread *thread, const char *err, ... )
|
||||||
{
|
{
|
||||||
|
@ -34,11 +62,11 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... )
|
||||||
fprintf( stderr, "Protocol error:%p: ", thread );
|
fprintf( stderr, "Protocol error:%p: ", thread );
|
||||||
vfprintf( stderr, err, args );
|
vfprintf( stderr, err, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
remove_client( thread->client, PROTOCOL_ERROR );
|
kill_thread( thread, PROTOCOL_ERROR );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call a request handler */
|
/* call a request handler */
|
||||||
void call_req_handler( struct thread *thread, enum request req, int fd )
|
static void call_req_handler( struct thread *thread, enum request req, int fd )
|
||||||
{
|
{
|
||||||
current = thread;
|
current = thread;
|
||||||
clear_error();
|
clear_error();
|
||||||
|
@ -65,31 +93,109 @@ void call_timeout_handler( void *thread )
|
||||||
current = NULL;
|
current = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a thread has been killed */
|
|
||||||
void call_kill_handler( struct thread *thread, int exit_code )
|
|
||||||
{
|
|
||||||
/* must be reentrant WRT call_req_handler */
|
|
||||||
struct thread *old_current = current;
|
|
||||||
current = thread;
|
|
||||||
if (current)
|
|
||||||
{
|
|
||||||
if (debug_level) trace_kill( exit_code );
|
|
||||||
thread_killed( current, exit_code );
|
|
||||||
}
|
|
||||||
current = (old_current != thread) ? old_current : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the fd to pass to the thread */
|
/* set the fd to pass to the thread */
|
||||||
void set_reply_fd( struct thread *thread, int pass_fd )
|
void set_reply_fd( struct thread *thread, int pass_fd )
|
||||||
{
|
{
|
||||||
client_pass_fd( thread->client, pass_fd );
|
assert( thread->pass_fd == -1 );
|
||||||
|
thread->pass_fd = pass_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send a reply to a thread */
|
/* send a reply to a thread */
|
||||||
void send_reply( struct thread *thread )
|
void send_reply( struct thread *thread )
|
||||||
{
|
{
|
||||||
if (thread->state == SLEEPING) thread->state = RUNNING;
|
if (thread->state == SLEEPING) thread->state = RUNNING;
|
||||||
client_reply( thread->client, thread->error );
|
if (debug_level) trace_reply( thread );
|
||||||
|
if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read a message from a client that has something to say */
|
||||||
|
void read_request( struct thread *thread )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
enum request req;
|
||||||
|
|
||||||
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
|
msghdr.msg_accrightslen = sizeof(int);
|
||||||
|
msghdr.msg_accrights = (void *)&thread->pass_fd;
|
||||||
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
msghdr.msg_control = &cmsg;
|
||||||
|
msghdr.msg_controllen = sizeof(cmsg);
|
||||||
|
cmsg.fd = -1;
|
||||||
|
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
|
||||||
|
assert( thread->pass_fd == -1 );
|
||||||
|
|
||||||
|
myiovec.iov_base = (void *)&req;
|
||||||
|
myiovec.iov_len = sizeof(req);
|
||||||
|
|
||||||
|
ret = recvmsg( thread->obj.fd, &msghdr, 0 );
|
||||||
|
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
||||||
|
thread->pass_fd = cmsg.fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret == sizeof(req))
|
||||||
|
{
|
||||||
|
int pass_fd = thread->pass_fd;
|
||||||
|
thread->pass_fd = -1;
|
||||||
|
call_req_handler( thread, req, pass_fd );
|
||||||
|
if (pass_fd != -1) close( pass_fd );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
perror("recvmsg");
|
||||||
|
kill_thread( thread, BROKEN_PIPE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ret) /* closed pipe */
|
||||||
|
{
|
||||||
|
kill_thread( thread, BROKEN_PIPE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send a message to a client that is ready to receive something */
|
||||||
|
int write_request( struct thread *thread )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (thread->pass_fd == -1)
|
||||||
|
{
|
||||||
|
ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
|
||||||
|
if (ret == sizeof(thread->error)) goto ok;
|
||||||
|
}
|
||||||
|
else /* we have an fd to send */
|
||||||
|
{
|
||||||
|
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
||||||
|
msghdr.msg_accrightslen = sizeof(int);
|
||||||
|
msghdr.msg_accrights = (void *)&thread->pass_fd;
|
||||||
|
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
msghdr.msg_control = &cmsg;
|
||||||
|
msghdr.msg_controllen = sizeof(cmsg);
|
||||||
|
cmsg.fd = thread->pass_fd;
|
||||||
|
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
||||||
|
|
||||||
|
myiovec.iov_base = (void *)&thread->error;
|
||||||
|
myiovec.iov_len = sizeof(thread->error);
|
||||||
|
|
||||||
|
ret = sendmsg( thread->obj.fd, &msghdr, 0 );
|
||||||
|
close( thread->pass_fd );
|
||||||
|
thread->pass_fd = -1;
|
||||||
|
if (ret == sizeof(thread->error)) goto ok;
|
||||||
|
}
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
|
||||||
|
if (errno != EPIPE) perror("sendmsg");
|
||||||
|
}
|
||||||
|
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
|
||||||
|
kill_thread( thread, BROKEN_PIPE );
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ok:
|
||||||
|
set_select_events( &thread->obj, POLLIN );
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the debug level */
|
/* set the debug level */
|
||||||
|
|
|
@ -26,17 +26,17 @@
|
||||||
|
|
||||||
/* request functions */
|
/* request functions */
|
||||||
|
|
||||||
|
extern void read_request( struct thread *thread );
|
||||||
|
extern int write_request( struct thread *thread );
|
||||||
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
extern void fatal_protocol_error( struct thread *thread, const char *err, ... );
|
||||||
extern void call_req_handler( struct thread *thread, enum request req, int fd );
|
|
||||||
extern void call_timeout_handler( void *thread );
|
extern void call_timeout_handler( void *thread );
|
||||||
extern void call_kill_handler( struct thread *thread, int exit_code );
|
|
||||||
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
extern void set_reply_fd( struct thread *thread, int pass_fd );
|
||||||
extern void send_reply( struct thread *thread );
|
extern void send_reply( struct thread *thread );
|
||||||
|
|
||||||
extern void trace_request( enum request req, int fd );
|
extern void trace_request( enum request req, int fd );
|
||||||
extern void trace_timeout(void);
|
extern void trace_timeout(void);
|
||||||
extern void trace_kill( int exit_code );
|
extern void trace_kill( struct thread *thread );
|
||||||
extern void trace_reply( struct thread *thread, unsigned int res, int pass_fd );
|
extern void trace_reply( struct thread *thread );
|
||||||
|
|
||||||
/* get the request buffer */
|
/* get the request buffer */
|
||||||
static inline void *get_req_ptr( struct thread *thread )
|
static inline void *get_req_ptr( struct thread *thread )
|
||||||
|
|
|
@ -19,12 +19,6 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
|
|
||||||
struct poll_user
|
|
||||||
{
|
|
||||||
void (*func)(int event, void *private); /* callback function */
|
|
||||||
void *private; /* callback private data */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct timeout_user
|
struct timeout_user
|
||||||
{
|
{
|
||||||
struct timeout_user *next; /* next in sorted timeout list */
|
struct timeout_user *next; /* next in sorted timeout list */
|
||||||
|
@ -34,32 +28,31 @@ struct timeout_user
|
||||||
void *private; /* callback private data */
|
void *private; /* callback private data */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct poll_user *poll_users; /* users array */
|
static struct object **poll_users; /* users array */
|
||||||
static struct pollfd *pollfd; /* poll fd array */
|
static struct pollfd *pollfd; /* poll fd array */
|
||||||
static int nb_users; /* count of array entries actually in use */
|
static int nb_users; /* count of array entries actually in use */
|
||||||
static int active_users; /* current number of active users */
|
static int active_users; /* current number of active users */
|
||||||
static int allocated_users; /* count of allocated entries in the array */
|
static int allocated_users; /* count of allocated entries in the array */
|
||||||
static struct poll_user *freelist; /* list of free entries in the array */
|
static struct object **freelist; /* list of free entries in the array */
|
||||||
|
|
||||||
static struct timeout_user *timeout_head; /* sorted timeouts list head */
|
static struct timeout_user *timeout_head; /* sorted timeouts list head */
|
||||||
static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
|
static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
|
||||||
|
|
||||||
|
|
||||||
/* add a user and return an opaque handle to it, or -1 on failure */
|
/* add a user and return an opaque handle to it, or -1 on failure */
|
||||||
int add_select_user( int fd, void (*func)(int, void *), void *private )
|
int add_select_user( struct object *obj )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (freelist)
|
if (freelist)
|
||||||
{
|
{
|
||||||
ret = freelist - poll_users;
|
ret = freelist - poll_users;
|
||||||
freelist = poll_users[ret].private;
|
freelist = (struct object **)poll_users[ret];
|
||||||
assert( !poll_users[ret].func );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (nb_users == allocated_users)
|
if (nb_users == allocated_users)
|
||||||
{
|
{
|
||||||
struct poll_user *newusers;
|
struct object **newusers;
|
||||||
struct pollfd *newpoll;
|
struct pollfd *newpoll;
|
||||||
int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
|
int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
|
||||||
if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
|
if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
|
||||||
|
@ -74,43 +67,53 @@ int add_select_user( int fd, void (*func)(int, void *), void *private )
|
||||||
}
|
}
|
||||||
ret = nb_users++;
|
ret = nb_users++;
|
||||||
}
|
}
|
||||||
pollfd[ret].fd = fd;
|
pollfd[ret].fd = obj->fd;
|
||||||
pollfd[ret].events = 0;
|
pollfd[ret].events = 0;
|
||||||
pollfd[ret].revents = 0;
|
pollfd[ret].revents = 0;
|
||||||
poll_users[ret].func = func;
|
poll_users[ret] = obj;
|
||||||
poll_users[ret].private = private;
|
obj->select = ret;
|
||||||
active_users++;
|
active_users++;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove a user and close its fd */
|
/* remove an object from the select list and close its fd */
|
||||||
void remove_select_user( int user )
|
void remove_select_user( struct object *obj )
|
||||||
{
|
{
|
||||||
if (user == -1) return; /* avoids checking in all callers */
|
int user = obj->select;
|
||||||
assert( poll_users[user].func );
|
assert( poll_users[user] == obj );
|
||||||
close( pollfd[user].fd );
|
|
||||||
pollfd[user].fd = -1;
|
pollfd[user].fd = -1;
|
||||||
pollfd[user].events = 0;
|
pollfd[user].events = 0;
|
||||||
pollfd[user].revents = 0;
|
pollfd[user].revents = 0;
|
||||||
poll_users[user].func = NULL;
|
poll_users[user] = (struct object *)freelist;
|
||||||
poll_users[user].private = freelist;
|
|
||||||
freelist = &poll_users[user];
|
freelist = &poll_users[user];
|
||||||
|
close( obj->fd );
|
||||||
|
obj->fd = -1;
|
||||||
|
obj->select = -1;
|
||||||
active_users--;
|
active_users--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change the fd of a select user (the old fd is closed) */
|
/* change the fd of an object (the old fd is closed) */
|
||||||
void change_select_fd( int user, int fd )
|
void change_select_fd( struct object *obj, int fd )
|
||||||
{
|
{
|
||||||
assert( poll_users[user].func );
|
int user = obj->select;
|
||||||
close( pollfd[user].fd );
|
assert( poll_users[user] == obj );
|
||||||
pollfd[user].fd = fd;
|
pollfd[user].fd = fd;
|
||||||
|
close( obj->fd );
|
||||||
|
obj->fd = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the events that select waits for on this fd */
|
/* set the events that select waits for on this fd */
|
||||||
void set_select_events( int user, int events )
|
void set_select_events( struct object *obj, int events )
|
||||||
{
|
{
|
||||||
assert( poll_users[user].func );
|
int user = obj->select;
|
||||||
pollfd[user].events = events;
|
assert( poll_users[user] == obj );
|
||||||
|
if (events == -1) /* stop waiting on this fd completely */
|
||||||
|
{
|
||||||
|
pollfd[user].fd = -1;
|
||||||
|
pollfd[user].events = 0;
|
||||||
|
pollfd[user].revents = 0;
|
||||||
|
}
|
||||||
|
else if (pollfd[user].fd != -1) pollfd[user].events = events;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if events are pending */
|
/* check if events are pending */
|
||||||
|
@ -259,7 +262,7 @@ void select_loop(void)
|
||||||
{
|
{
|
||||||
if (pollfd[i].revents)
|
if (pollfd[i].revents)
|
||||||
{
|
{
|
||||||
poll_users[i].func( pollfd[i].revents, poll_users[i].private );
|
poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
|
||||||
if (!--ret) break;
|
if (!--ret) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,17 +28,19 @@ static int semaphore_satisfied( struct object *obj, struct thread *thread );
|
||||||
|
|
||||||
static const struct object_ops semaphore_ops =
|
static const struct object_ops semaphore_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct semaphore),
|
sizeof(struct semaphore), /* size */
|
||||||
semaphore_dump,
|
semaphore_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
semaphore_signaled,
|
semaphore_signaled, /* signaled */
|
||||||
semaphore_satisfied,
|
semaphore_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
no_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
no_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,17 +33,19 @@ static void snapshot_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops snapshot_ops =
|
static const struct object_ops snapshot_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct snapshot),
|
sizeof(struct snapshot), /* size */
|
||||||
snapshot_dump,
|
snapshot_dump, /* dump */
|
||||||
no_add_queue,
|
no_add_queue, /* add_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* remove_queue */
|
||||||
NULL, /* should never get called */
|
NULL, /* signaled */
|
||||||
NULL, /* should never get called */
|
NULL, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
snapshot_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
snapshot_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ static struct snapshot *create_snapshot( int flags )
|
||||||
{
|
{
|
||||||
struct snapshot *snapshot;
|
struct snapshot *snapshot;
|
||||||
|
|
||||||
if ((snapshot = alloc_object( &snapshot_ops )))
|
if ((snapshot = alloc_object( &snapshot_ops, -1 )))
|
||||||
{
|
{
|
||||||
if (flags & TH32CS_SNAPPROCESS)
|
if (flags & TH32CS_SNAPPROCESS)
|
||||||
snapshot->process = process_snap( &snapshot->process_count );
|
snapshot->process = process_snap( &snapshot->process_count );
|
||||||
|
|
180
server/sock.c
180
server/sock.c
|
@ -42,8 +42,6 @@
|
||||||
struct sock
|
struct sock
|
||||||
{
|
{
|
||||||
struct object obj; /* object header */
|
struct object obj; /* object header */
|
||||||
int fd; /* file descriptor */
|
|
||||||
int select; /* select user */
|
|
||||||
unsigned int state; /* status bits */
|
unsigned int state; /* status bits */
|
||||||
unsigned int mask; /* event mask */
|
unsigned int mask; /* event mask */
|
||||||
unsigned int hmask; /* held (blocked) events */
|
unsigned int hmask; /* held (blocked) events */
|
||||||
|
@ -53,51 +51,36 @@ struct sock
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sock_dump( struct object *obj, int verbose );
|
static void sock_dump( struct object *obj, int verbose );
|
||||||
static int sock_add_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static void sock_remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
|
||||||
static int sock_signaled( struct object *obj, struct thread *thread );
|
static int sock_signaled( struct object *obj, struct thread *thread );
|
||||||
|
static int sock_get_poll_events( struct object *obj );
|
||||||
|
static void sock_poll_event( struct object *obj, int event );
|
||||||
static int sock_get_fd( struct object *obj );
|
static int sock_get_fd( struct object *obj );
|
||||||
static void sock_destroy( struct object *obj );
|
static void sock_destroy( struct object *obj );
|
||||||
static void sock_set_error(void);
|
static void sock_set_error(void);
|
||||||
|
|
||||||
static const struct object_ops sock_ops =
|
static const struct object_ops sock_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct sock),
|
sizeof(struct sock), /* size */
|
||||||
sock_dump,
|
sock_dump, /* dump */
|
||||||
sock_add_queue,
|
add_queue, /* add_queue */
|
||||||
sock_remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
sock_signaled,
|
sock_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
sock_get_fd,
|
sock_get_poll_events, /* get_poll_events */
|
||||||
sock_get_fd,
|
sock_poll_event, /* poll_event */
|
||||||
no_flush,
|
sock_get_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
sock_get_fd, /* get_write_fd */
|
||||||
sock_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
sock_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sock_event( struct sock *sock )
|
|
||||||
{
|
|
||||||
unsigned int mask = sock->mask & sock->state & ~sock->hmask;
|
|
||||||
int ev = 0;
|
|
||||||
|
|
||||||
if (sock->state & WS_FD_CONNECT)
|
|
||||||
/* connecting, wait for writable */
|
|
||||||
return POLLOUT;
|
|
||||||
if (sock->state & WS_FD_LISTENING)
|
|
||||||
/* listening, wait for readable */
|
|
||||||
return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN;
|
|
||||||
|
|
||||||
if (mask & FD_READ) ev |= POLLIN;
|
|
||||||
if (mask & FD_WRITE) ev |= POLLOUT;
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sock_reselect( struct sock *sock )
|
static void sock_reselect( struct sock *sock )
|
||||||
{
|
{
|
||||||
int ev = sock_event( sock );
|
int ev = sock_get_poll_events( &sock->obj );
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->fd, ev);
|
fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->obj.fd, ev);
|
||||||
set_select_events( sock->select, ev );
|
set_select_events( &sock->obj, ev );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static int sock_error(int s)
|
inline static int sock_error(int s)
|
||||||
|
@ -109,13 +92,13 @@ inline static int sock_error(int s)
|
||||||
return optval;
|
return optval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sock_select_event( int event, void *private )
|
static void sock_poll_event( struct object *obj, int event )
|
||||||
{
|
{
|
||||||
struct sock *sock = (struct sock *)private;
|
struct sock *sock = (struct sock *)obj;
|
||||||
unsigned int emask;
|
unsigned int emask;
|
||||||
assert( sock->obj.ops == &sock_ops );
|
assert( sock->obj.ops == &sock_ops );
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d select event: %x\n", sock->fd, event);
|
fprintf(stderr, "socket %d select event: %x\n", sock->obj.fd, event);
|
||||||
if (sock->state & WS_FD_CONNECT)
|
if (sock->state & WS_FD_CONNECT)
|
||||||
{
|
{
|
||||||
/* connecting */
|
/* connecting */
|
||||||
|
@ -127,16 +110,16 @@ static void sock_select_event( int event, void *private )
|
||||||
sock->pmask |= FD_CONNECT;
|
sock->pmask |= FD_CONNECT;
|
||||||
sock->errors[FD_CONNECT_BIT] = 0;
|
sock->errors[FD_CONNECT_BIT] = 0;
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d connection success\n", sock->fd);
|
fprintf(stderr, "socket %d connection success\n", sock->obj.fd);
|
||||||
}
|
}
|
||||||
else if (event & (POLLERR|POLLHUP))
|
else if (event & (POLLERR|POLLHUP))
|
||||||
{
|
{
|
||||||
/* we didn't get connected? */
|
/* we didn't get connected? */
|
||||||
sock->state &= ~WS_FD_CONNECT;
|
sock->state &= ~WS_FD_CONNECT;
|
||||||
sock->pmask |= FD_CONNECT;
|
sock->pmask |= FD_CONNECT;
|
||||||
sock->errors[FD_CONNECT_BIT] = sock_error( sock->fd );
|
sock->errors[FD_CONNECT_BIT] = sock_error( sock->obj.fd );
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d connection failure\n", sock->fd);
|
fprintf(stderr, "socket %d connection failure\n", sock->obj.fd);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (sock->state & WS_FD_LISTENING)
|
if (sock->state & WS_FD_LISTENING)
|
||||||
|
@ -153,35 +136,20 @@ static void sock_select_event( int event, void *private )
|
||||||
{
|
{
|
||||||
/* failed incoming connection? */
|
/* failed incoming connection? */
|
||||||
sock->pmask |= FD_ACCEPT;
|
sock->pmask |= FD_ACCEPT;
|
||||||
sock->errors[FD_ACCEPT_BIT] = sock_error( sock->fd );
|
sock->errors[FD_ACCEPT_BIT] = sock_error( sock->obj.fd );
|
||||||
sock->hmask |= FD_ACCEPT;
|
sock->hmask |= FD_ACCEPT;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
/* normal data flow */
|
/* normal data flow */
|
||||||
if (event & POLLIN)
|
if (event & POLLIN)
|
||||||
{
|
|
||||||
/* make sure there's data here */
|
|
||||||
int bytes = 0;
|
|
||||||
ioctl(sock->fd, FIONREAD, (char*)&bytes);
|
|
||||||
if (bytes)
|
|
||||||
{
|
{
|
||||||
/* incoming data */
|
/* incoming data */
|
||||||
sock->pmask |= FD_READ;
|
sock->pmask |= FD_READ;
|
||||||
sock->hmask |= FD_READ;
|
sock->hmask |= FD_READ;
|
||||||
sock->errors[FD_READ_BIT] = 0;
|
sock->errors[FD_READ_BIT] = 0;
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d has %d bytes\n", sock->fd, bytes);
|
fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 0 bytes readable == socket closed cleanly */
|
|
||||||
sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
|
|
||||||
sock->pmask |= FD_CLOSE;
|
|
||||||
sock->errors[FD_CLOSE_BIT] = 0;
|
|
||||||
if (debug_level)
|
|
||||||
fprintf(stderr, "socket %d is closing\n", sock->fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (event & POLLOUT)
|
if (event & POLLOUT)
|
||||||
{
|
{
|
||||||
|
@ -189,27 +157,24 @@ static void sock_select_event( int event, void *private )
|
||||||
sock->hmask |= FD_WRITE;
|
sock->hmask |= FD_WRITE;
|
||||||
sock->errors[FD_WRITE_BIT] = 0;
|
sock->errors[FD_WRITE_BIT] = 0;
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d is writable\n", sock->fd);
|
fprintf(stderr, "socket %d is writable\n", sock->obj.fd);
|
||||||
|
}
|
||||||
|
if (event & POLLPRI)
|
||||||
|
{
|
||||||
|
sock->pmask |= FD_OOB;
|
||||||
|
sock->hmask |= FD_OOB;
|
||||||
|
if (debug_level)
|
||||||
|
fprintf(stderr, "socket %d got OOB data\n", sock->obj.fd);
|
||||||
}
|
}
|
||||||
if (event & (POLLERR|POLLHUP))
|
if (event & (POLLERR|POLLHUP))
|
||||||
{
|
{
|
||||||
sock->errors[FD_CLOSE_BIT] = sock_error( sock->fd );
|
sock->errors[FD_CLOSE_BIT] = sock_error( sock->obj.fd );
|
||||||
if (sock->errors[FD_CLOSE_BIT])
|
|
||||||
{
|
|
||||||
/* we got an error, socket closing? */
|
/* we got an error, socket closing? */
|
||||||
sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
|
sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
|
||||||
sock->pmask |= FD_CLOSE;
|
sock->pmask |= FD_CLOSE;
|
||||||
if (debug_level)
|
if (debug_level)
|
||||||
fprintf(stderr, "socket %d aborted by error %d\n", sock->fd, sock->errors[FD_CLOSE_BIT]);
|
fprintf(stderr, "socket %d aborted by error %d\n",
|
||||||
}
|
sock->obj.fd, sock->errors[FD_CLOSE_BIT]);
|
||||||
else
|
|
||||||
{
|
|
||||||
/* no error, OOB data? */
|
|
||||||
sock->pmask |= FD_OOB;
|
|
||||||
sock->hmask |= FD_OOB;
|
|
||||||
if (debug_level)
|
|
||||||
fprintf(stderr, "socket %d got OOB data\n", sock->fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +182,7 @@ static void sock_select_event( int event, void *private )
|
||||||
/* wake up anyone waiting for whatever just happened */
|
/* wake up anyone waiting for whatever just happened */
|
||||||
emask = sock->pmask & sock->mask;
|
emask = sock->pmask & sock->mask;
|
||||||
if (debug_level && emask)
|
if (debug_level && emask)
|
||||||
fprintf(stderr, "socket %d pending events: %x\n", sock->fd, emask);
|
fprintf(stderr, "socket %d pending events: %x\n", sock->obj.fd, emask);
|
||||||
if (emask && sock->event) {
|
if (emask && sock->event) {
|
||||||
if (debug_level) fprintf(stderr, "signalling event ptr %p\n", sock->event);
|
if (debug_level) fprintf(stderr, "signalling event ptr %p\n", sock->event);
|
||||||
set_event(sock->event);
|
set_event(sock->event);
|
||||||
|
@ -233,34 +198,36 @@ static void sock_dump( struct object *obj, int verbose )
|
||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
printf( "Socket fd=%d, state=%x, mask=%x, pending=%x, held=%x\n",
|
printf( "Socket fd=%d, state=%x, mask=%x, pending=%x, held=%x\n",
|
||||||
sock->fd, sock->state,
|
sock->obj.fd, sock->state,
|
||||||
sock->mask, sock->pmask, sock->hmask );
|
sock->mask, sock->pmask, sock->hmask );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock_add_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
/* struct sock *sock = (struct sock *)obj; */
|
|
||||||
assert( obj->ops == &sock_ops );
|
|
||||||
|
|
||||||
add_queue( obj, entry );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sock_remove_queue( struct object *obj, struct wait_queue_entry *entry )
|
|
||||||
{
|
|
||||||
/* struct sock *sock = (struct sock *)grab_object(obj); */
|
|
||||||
assert( obj->ops == &sock_ops );
|
|
||||||
|
|
||||||
remove_queue( obj, entry );
|
|
||||||
/* release_object( obj ); */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sock_signaled( struct object *obj, struct thread *thread )
|
static int sock_signaled( struct object *obj, struct thread *thread )
|
||||||
{
|
{
|
||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
|
|
||||||
return check_select_events( sock->fd, sock_event( sock ) );
|
return check_select_events( sock->obj.fd, sock_get_poll_events( &sock->obj ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sock_get_poll_events( struct object *obj )
|
||||||
|
{
|
||||||
|
struct sock *sock = (struct sock *)obj;
|
||||||
|
unsigned int mask = sock->mask & sock->state & ~sock->hmask;
|
||||||
|
int ev = 0;
|
||||||
|
|
||||||
|
assert( obj->ops == &sock_ops );
|
||||||
|
|
||||||
|
if (sock->state & WS_FD_CONNECT)
|
||||||
|
/* connecting, wait for writable */
|
||||||
|
return POLLOUT;
|
||||||
|
if (sock->state & WS_FD_LISTENING)
|
||||||
|
/* listening, wait for readable */
|
||||||
|
return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN;
|
||||||
|
|
||||||
|
if (mask & FD_READ) ev |= POLLIN | POLLPRI;
|
||||||
|
if (mask & FD_WRITE) ev |= POLLOUT;
|
||||||
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock_get_fd( struct object *obj )
|
static int sock_get_fd( struct object *obj )
|
||||||
|
@ -268,7 +235,7 @@ static int sock_get_fd( struct object *obj )
|
||||||
struct sock *sock = (struct sock *)obj;
|
struct sock *sock = (struct sock *)obj;
|
||||||
int fd;
|
int fd;
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
fd = dup( sock->fd );
|
fd = dup( sock->obj.fd );
|
||||||
if (fd==-1)
|
if (fd==-1)
|
||||||
sock_set_error();
|
sock_set_error();
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -280,7 +247,6 @@ static void sock_destroy( struct object *obj )
|
||||||
assert( obj->ops == &sock_ops );
|
assert( obj->ops == &sock_ops );
|
||||||
|
|
||||||
/* FIXME: special socket shutdown stuff? */
|
/* FIXME: special socket shutdown stuff? */
|
||||||
remove_select_user( sock->select );
|
|
||||||
if (sock->event)
|
if (sock->event)
|
||||||
{
|
{
|
||||||
/* if the service thread was waiting for the event object,
|
/* if the service thread was waiting for the event object,
|
||||||
|
@ -307,21 +273,12 @@ static struct object *create_socket( int family, int type, int protocol )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
|
fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
|
||||||
if (!(sock = alloc_object( &sock_ops ))) {
|
if (!(sock = alloc_object( &sock_ops, sockfd ))) return NULL;
|
||||||
close( sockfd );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sock->fd = sockfd;
|
|
||||||
sock->state = (type!=SOCK_STREAM) ? WS_FD_READ|WS_FD_WRITE : 0;
|
sock->state = (type!=SOCK_STREAM) ? WS_FD_READ|WS_FD_WRITE : 0;
|
||||||
sock->mask = 0;
|
sock->mask = 0;
|
||||||
sock->hmask = 0;
|
sock->hmask = 0;
|
||||||
sock->pmask = 0;
|
sock->pmask = 0;
|
||||||
sock->event = NULL;
|
sock->event = NULL;
|
||||||
if ((sock->select = add_select_user( sockfd, sock_select_event, sock )) == -1)
|
|
||||||
{
|
|
||||||
release_object( sock );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sock_reselect( sock );
|
sock_reselect( sock );
|
||||||
clear_error();
|
clear_error();
|
||||||
return &sock->obj;
|
return &sock->obj;
|
||||||
|
@ -345,32 +302,23 @@ static struct object *accept_socket( int handle )
|
||||||
* return.
|
* return.
|
||||||
*/
|
*/
|
||||||
slen = sizeof(saddr);
|
slen = sizeof(saddr);
|
||||||
acceptfd = accept(sock->fd,&saddr,&slen);
|
acceptfd = accept(sock->obj.fd,&saddr,&slen);
|
||||||
if (acceptfd==-1) {
|
if (acceptfd==-1) {
|
||||||
sock_set_error();
|
sock_set_error();
|
||||||
release_object( sock );
|
release_object( sock );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!(acceptsock = alloc_object( &sock_ops )))
|
if (!(acceptsock = alloc_object( &sock_ops, acceptfd )))
|
||||||
{
|
{
|
||||||
close( acceptfd );
|
|
||||||
release_object( sock );
|
release_object( sock );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsock->fd = acceptfd;
|
|
||||||
acceptsock->state = WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE;
|
acceptsock->state = WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE;
|
||||||
acceptsock->mask = sock->mask;
|
acceptsock->mask = sock->mask;
|
||||||
acceptsock->hmask = 0;
|
acceptsock->hmask = 0;
|
||||||
acceptsock->pmask = 0;
|
acceptsock->pmask = 0;
|
||||||
acceptsock->event = NULL;
|
acceptsock->event = NULL;
|
||||||
acceptsock->select = add_select_user( acceptfd, sock_select_event, acceptsock );
|
|
||||||
if (acceptsock->select == -1)
|
|
||||||
{
|
|
||||||
release_object( acceptsock );
|
|
||||||
release_object( sock );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
|
if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event );
|
||||||
|
|
||||||
sock_reselect( acceptsock );
|
sock_reselect( acceptsock );
|
||||||
|
|
216
server/socket.c
216
server/socket.c
|
@ -1,216 +0,0 @@
|
||||||
/*
|
|
||||||
* Server-side socket communication functions
|
|
||||||
*
|
|
||||||
* Copyright (C) 1998 Alexandre Julliard
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#ifdef HAVE_SYS_SOCKET_H
|
|
||||||
# include <sys/socket.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/uio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "object.h"
|
|
||||||
#include "request.h"
|
|
||||||
|
|
||||||
/* Some versions of glibc don't define this */
|
|
||||||
#ifndef SCM_RIGHTS
|
|
||||||
#define SCM_RIGHTS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* client structure */
|
|
||||||
struct client
|
|
||||||
{
|
|
||||||
int fd; /* socket file descriptor */
|
|
||||||
int select; /* select user id */
|
|
||||||
unsigned int res; /* current result to send */
|
|
||||||
int pass_fd; /* fd to pass to and from the client */
|
|
||||||
struct thread *self; /* client thread (opaque pointer) */
|
|
||||||
struct timeout_user *timeout; /* current timeout (opaque pointer) */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* socket communication static structures */
|
|
||||||
static struct iovec myiovec;
|
|
||||||
static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
|
|
||||||
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
|
||||||
struct cmsg_fd
|
|
||||||
{
|
|
||||||
int len; /* sizeof structure */
|
|
||||||
int level; /* SOL_SOCKET */
|
|
||||||
int type; /* SCM_RIGHTS */
|
|
||||||
int fd; /* fd to pass */
|
|
||||||
};
|
|
||||||
static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
|
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
|
||||||
|
|
||||||
|
|
||||||
/* send a message to a client that is ready to receive something */
|
|
||||||
static int do_write( struct client *client )
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (client->pass_fd == -1)
|
|
||||||
{
|
|
||||||
ret = write( client->fd, &client->res, sizeof(client->res) );
|
|
||||||
if (ret == sizeof(client->res)) goto ok;
|
|
||||||
}
|
|
||||||
else /* we have an fd to send */
|
|
||||||
{
|
|
||||||
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
|
||||||
msghdr.msg_accrightslen = sizeof(int);
|
|
||||||
msghdr.msg_accrights = (void *)&client->pass_fd;
|
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
|
||||||
msghdr.msg_control = &cmsg;
|
|
||||||
msghdr.msg_controllen = sizeof(cmsg);
|
|
||||||
cmsg.fd = client->pass_fd;
|
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
|
||||||
|
|
||||||
myiovec.iov_base = (void *)&client->res;
|
|
||||||
myiovec.iov_len = sizeof(client->res);
|
|
||||||
|
|
||||||
ret = sendmsg( client->fd, &msghdr, 0 );
|
|
||||||
close( client->pass_fd );
|
|
||||||
client->pass_fd = -1;
|
|
||||||
if (ret == sizeof(client->res)) goto ok;
|
|
||||||
}
|
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
|
|
||||||
if (errno != EPIPE) perror("sendmsg");
|
|
||||||
}
|
|
||||||
else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(client->res) );
|
|
||||||
remove_client( client, BROKEN_PIPE );
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ok:
|
|
||||||
set_select_events( client->select, POLLIN );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* read a message from a client that has something to say */
|
|
||||||
static void do_read( struct client *client )
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
enum request req;
|
|
||||||
|
|
||||||
#ifdef HAVE_MSGHDR_ACCRIGHTS
|
|
||||||
msghdr.msg_accrightslen = sizeof(int);
|
|
||||||
msghdr.msg_accrights = (void *)&client->pass_fd;
|
|
||||||
#else /* HAVE_MSGHDR_ACCRIGHTS */
|
|
||||||
msghdr.msg_control = &cmsg;
|
|
||||||
msghdr.msg_controllen = sizeof(cmsg);
|
|
||||||
cmsg.fd = -1;
|
|
||||||
#endif /* HAVE_MSGHDR_ACCRIGHTS */
|
|
||||||
|
|
||||||
assert( client->pass_fd == -1 );
|
|
||||||
|
|
||||||
myiovec.iov_base = (void *)&req;
|
|
||||||
myiovec.iov_len = sizeof(req);
|
|
||||||
|
|
||||||
ret = recvmsg( client->fd, &msghdr, 0 );
|
|
||||||
#ifndef HAVE_MSGHDR_ACCRIGHTS
|
|
||||||
client->pass_fd = cmsg.fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ret == sizeof(req))
|
|
||||||
{
|
|
||||||
int pass_fd = client->pass_fd;
|
|
||||||
client->pass_fd = -1;
|
|
||||||
call_req_handler( client->self, req, pass_fd );
|
|
||||||
if (pass_fd != -1) close( pass_fd );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
perror("recvmsg");
|
|
||||||
remove_client( client, BROKEN_PIPE );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!ret) /* closed pipe */
|
|
||||||
{
|
|
||||||
remove_client( client, BROKEN_PIPE );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fatal_protocol_error( client->self, "partial message received %d/%d\n", ret, sizeof(req) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* handle a client event */
|
|
||||||
static void client_event( int event, void *private )
|
|
||||||
{
|
|
||||||
struct client *client = (struct client *)private;
|
|
||||||
if (event & (POLLERR | POLLHUP)) remove_client( client, BROKEN_PIPE );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (event & POLLOUT) do_write( client );
|
|
||||||
if (event & POLLIN) do_read( client );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************/
|
|
||||||
/* server-side exported functions */
|
|
||||||
|
|
||||||
/* add a client */
|
|
||||||
struct client *add_client( int fd, struct thread *self )
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
struct client *client = mem_alloc( sizeof(*client) );
|
|
||||||
if (!client) return NULL;
|
|
||||||
|
|
||||||
flags = fcntl( fd, F_GETFL, 0 );
|
|
||||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
|
|
||||||
|
|
||||||
client->fd = fd;
|
|
||||||
client->self = self;
|
|
||||||
client->timeout = NULL;
|
|
||||||
client->pass_fd = -1;
|
|
||||||
if ((client->select = add_select_user( fd, client_event, client )) == -1)
|
|
||||||
{
|
|
||||||
free( client );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
set_select_events( client->select, POLLIN );
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove a client */
|
|
||||||
void remove_client( struct client *client, int exit_code )
|
|
||||||
{
|
|
||||||
assert( client );
|
|
||||||
|
|
||||||
call_kill_handler( client->self, exit_code );
|
|
||||||
|
|
||||||
if (client->timeout) remove_timeout_user( client->timeout );
|
|
||||||
remove_select_user( client->select );
|
|
||||||
|
|
||||||
/* Purge messages */
|
|
||||||
if (client->pass_fd != -1) close( client->pass_fd );
|
|
||||||
free( client );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the fd to pass to the client */
|
|
||||||
void client_pass_fd( struct client *client, int pass_fd )
|
|
||||||
{
|
|
||||||
assert( client->pass_fd == -1 );
|
|
||||||
client->pass_fd = pass_fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send a reply to a client */
|
|
||||||
void client_reply( struct client *client, unsigned int res )
|
|
||||||
{
|
|
||||||
if (debug_level) trace_reply( client->self, res, client->pass_fd );
|
|
||||||
client->res = res;
|
|
||||||
if (!do_write( client )) set_select_events( client->select, POLLOUT );
|
|
||||||
}
|
|
|
@ -63,21 +63,24 @@ struct thread_apc
|
||||||
|
|
||||||
static void dump_thread( struct object *obj, int verbose );
|
static void dump_thread( struct object *obj, int verbose );
|
||||||
static int thread_signaled( struct object *obj, struct thread *thread );
|
static int thread_signaled( struct object *obj, struct thread *thread );
|
||||||
|
extern void thread_poll_event( struct object *obj, int event );
|
||||||
static void destroy_thread( struct object *obj );
|
static void destroy_thread( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops thread_ops =
|
static const struct object_ops thread_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct thread),
|
sizeof(struct thread), /* size */
|
||||||
dump_thread,
|
dump_thread, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
thread_signaled,
|
thread_signaled, /* signaled */
|
||||||
no_satisfied,
|
no_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
thread_poll_event, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
destroy_thread
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
destroy_thread /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct thread *first_thread;
|
static struct thread *first_thread;
|
||||||
|
@ -105,9 +108,11 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
int buf_fd;
|
int buf_fd;
|
||||||
|
|
||||||
if (!(thread = alloc_object( &thread_ops ))) return NULL;
|
int flags = fcntl( fd, F_GETFL, 0 );
|
||||||
|
fcntl( fd, F_SETFL, flags | O_NONBLOCK );
|
||||||
|
|
||||||
|
if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
|
||||||
|
|
||||||
thread->client = NULL;
|
|
||||||
thread->unix_pid = 0; /* not known yet */
|
thread->unix_pid = 0; /* not known yet */
|
||||||
thread->teb = NULL;
|
thread->teb = NULL;
|
||||||
thread->mutex = NULL;
|
thread->mutex = NULL;
|
||||||
|
@ -118,6 +123,7 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
||||||
thread->apc = NULL;
|
thread->apc = NULL;
|
||||||
thread->apc_count = 0;
|
thread->apc_count = 0;
|
||||||
thread->error = 0;
|
thread->error = 0;
|
||||||
|
thread->pass_fd = -1;
|
||||||
thread->state = RUNNING;
|
thread->state = RUNNING;
|
||||||
thread->attached = 0;
|
thread->attached = 0;
|
||||||
thread->exit_code = 0x103; /* STILL_ACTIVE */
|
thread->exit_code = 0x103; /* STILL_ACTIVE */
|
||||||
|
@ -142,11 +148,8 @@ static struct thread *create_thread( int fd, struct process *process, int suspen
|
||||||
add_process_thread( process, thread );
|
add_process_thread( process, thread );
|
||||||
|
|
||||||
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
|
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
|
||||||
if (!(thread->client = add_client( fd, thread )))
|
|
||||||
{
|
set_select_events( &thread->obj, POLLIN ); /* start listening to events */
|
||||||
close( buf_fd );
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
set_reply_fd( thread, buf_fd ); /* send the fd to the client */
|
set_reply_fd( thread, buf_fd ); /* send the fd to the client */
|
||||||
send_reply( thread );
|
send_reply( thread );
|
||||||
return thread;
|
return thread;
|
||||||
|
@ -164,6 +167,20 @@ void create_initial_thread( int fd )
|
||||||
select_loop();
|
select_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* handle a client event */
|
||||||
|
void thread_poll_event( struct object *obj, int event )
|
||||||
|
{
|
||||||
|
struct thread *thread = (struct thread *)obj;
|
||||||
|
assert( obj->ops == &thread_ops );
|
||||||
|
|
||||||
|
if (event & (POLLERR | POLLHUP)) kill_thread( thread, BROKEN_PIPE );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (event & POLLOUT) write_request( thread );
|
||||||
|
if (event & POLLIN) read_request( thread );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* destroy a thread when its refcount is 0 */
|
/* destroy a thread when its refcount is 0 */
|
||||||
static void destroy_thread( struct object *obj )
|
static void destroy_thread( struct object *obj )
|
||||||
{
|
{
|
||||||
|
@ -177,6 +194,7 @@ static void destroy_thread( struct object *obj )
|
||||||
else first_thread = thread->next;
|
else first_thread = thread->next;
|
||||||
if (thread->apc) free( thread->apc );
|
if (thread->apc) free( thread->apc );
|
||||||
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
|
if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
|
||||||
|
if (thread->pass_fd != -1) close( thread->pass_fd );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dump a thread on stdout for debugging purposes */
|
/* dump a thread on stdout for debugging purposes */
|
||||||
|
@ -499,21 +517,17 @@ static int thread_queue_apc( struct thread *thread, void *func, void *param )
|
||||||
void kill_thread( struct thread *thread, int exit_code )
|
void kill_thread( struct thread *thread, int exit_code )
|
||||||
{
|
{
|
||||||
if (thread->state == TERMINATED) return; /* already killed */
|
if (thread->state == TERMINATED) return; /* already killed */
|
||||||
remove_client( thread->client, exit_code ); /* this will call thread_killed */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a thread has been killed */
|
|
||||||
void thread_killed( struct thread *thread, int exit_code )
|
|
||||||
{
|
|
||||||
thread->state = TERMINATED;
|
thread->state = TERMINATED;
|
||||||
thread->exit_code = exit_code;
|
thread->exit_code = exit_code;
|
||||||
thread->client = NULL;
|
if (current == thread) current = NULL;
|
||||||
|
if (debug_level) trace_kill( thread );
|
||||||
if (thread->wait) end_wait( thread );
|
if (thread->wait) end_wait( thread );
|
||||||
debug_exit_thread( thread, exit_code );
|
debug_exit_thread( thread, exit_code );
|
||||||
abandon_mutexes( thread );
|
abandon_mutexes( thread );
|
||||||
remove_process_thread( thread->process, thread );
|
remove_process_thread( thread->process, thread );
|
||||||
wake_up( &thread->obj, 0 );
|
wake_up( &thread->obj, 0 );
|
||||||
detach_thread( thread );
|
detach_thread( thread );
|
||||||
|
remove_select_user( &thread->obj );
|
||||||
release_object( thread );
|
release_object( thread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,10 @@ struct thread
|
||||||
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 */
|
||||||
|
int pass_fd; /* fd to pass to the client */
|
||||||
enum run_state state; /* running state */
|
enum run_state state; /* running state */
|
||||||
int attached; /* is thread attached with ptrace? */
|
int attached; /* is thread attached with ptrace? */
|
||||||
int exit_code; /* thread exit code */
|
int exit_code; /* thread exit code */
|
||||||
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) */
|
void *teb; /* TEB address (in client address space) */
|
||||||
int priority; /* priority level */
|
int priority; /* priority level */
|
||||||
|
@ -74,7 +74,6 @@ extern void resume_all_threads( void );
|
||||||
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern int add_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
extern void remove_queue( struct object *obj, struct wait_queue_entry *entry );
|
||||||
extern void kill_thread( struct thread *thread, int exit_code );
|
extern void kill_thread( struct thread *thread, int exit_code );
|
||||||
extern void thread_killed( struct thread *thread, int exit_code );
|
|
||||||
extern void thread_timeout(void);
|
extern void thread_timeout(void);
|
||||||
extern void wake_up( struct object *obj, int max );
|
extern void wake_up( struct object *obj, int max );
|
||||||
|
|
||||||
|
|
|
@ -39,17 +39,19 @@ static void timer_destroy( struct object *obj );
|
||||||
|
|
||||||
static const struct object_ops timer_ops =
|
static const struct object_ops timer_ops =
|
||||||
{
|
{
|
||||||
sizeof(struct timer),
|
sizeof(struct timer), /* size */
|
||||||
timer_dump,
|
timer_dump, /* dump */
|
||||||
add_queue,
|
add_queue, /* add_queue */
|
||||||
remove_queue,
|
remove_queue, /* remove_queue */
|
||||||
timer_signaled,
|
timer_signaled, /* signaled */
|
||||||
timer_satisfied,
|
timer_satisfied, /* satisfied */
|
||||||
no_read_fd,
|
NULL, /* get_poll_events */
|
||||||
no_write_fd,
|
NULL, /* poll_event */
|
||||||
no_flush,
|
no_read_fd, /* get_read_fd */
|
||||||
no_get_file_info,
|
no_write_fd, /* get_write_fd */
|
||||||
timer_destroy
|
no_flush, /* flush */
|
||||||
|
no_get_file_info, /* get_file_info */
|
||||||
|
timer_destroy /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1341,22 +1341,22 @@ void trace_timeout(void)
|
||||||
fprintf( stderr, "%08x: *timeout*\n", (unsigned int)current );
|
fprintf( stderr, "%08x: *timeout*\n", (unsigned int)current );
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_kill( int exit_code )
|
void trace_kill( struct thread *thread )
|
||||||
{
|
{
|
||||||
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
|
fprintf( stderr,"%08x: *killed* exit_code=%d\n",
|
||||||
(unsigned int)current, exit_code );
|
(unsigned int)thread, thread->exit_code );
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_reply( struct thread *thread, unsigned int res, int pass_fd )
|
void trace_reply( struct thread *thread )
|
||||||
{
|
{
|
||||||
fprintf( stderr, "%08x: %s() = %d",
|
fprintf( stderr, "%08x: %s() = %d",
|
||||||
(unsigned int)thread, req_names[thread->last_req], res );
|
(unsigned int)thread, req_names[thread->last_req], thread->error );
|
||||||
if (reply_dumpers[thread->last_req])
|
if (reply_dumpers[thread->last_req])
|
||||||
{
|
{
|
||||||
fprintf( stderr, " {" );
|
fprintf( stderr, " {" );
|
||||||
reply_dumpers[thread->last_req]( thread->buffer );
|
reply_dumpers[thread->last_req]( thread->buffer );
|
||||||
fprintf( stderr, " }" );
|
fprintf( stderr, " }" );
|
||||||
}
|
}
|
||||||
if (pass_fd != -1) fprintf( stderr, " fd=%d\n", pass_fd );
|
if (thread->pass_fd != -1) fprintf( stderr, " fd=%d\n", thread->pass_fd );
|
||||||
else fprintf( stderr, "\n" );
|
else fprintf( stderr, "\n" );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue