Moved poll handling to the generic part of the server objects.
Fixed busy waiting on POLLERR events.
Merged struct client into struct thread.
diff --git a/server/Makefile.in b/server/Makefile.in
index 60aa6e0..b4ec97a 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -25,7 +25,6 @@
semaphore.c \
snapshot.c \
sock.c \
- socket.c \
thread.c \
timer.c \
trace.c \
diff --git a/server/change.c b/server/change.c
index 50f193e..8347651 100644
--- a/server/change.c
+++ b/server/change.c
@@ -27,24 +27,26 @@
static const struct object_ops change_ops =
{
- sizeof(struct change),
- change_dump,
- add_queue,
- remove_queue,
- change_signaled,
- no_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- no_destroy
+ sizeof(struct change), /* size */
+ change_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ change_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ no_destroy /* destroy */
};
static struct change *create_change_notification( int subtree, int filter )
{
struct change *change;
- if ((change = alloc_object( &change_ops )))
+ if ((change = alloc_object( &change_ops, -1 )))
{
change->subtree = subtree;
change->filter = filter;
diff --git a/server/console.c b/server/console.c
index d34fee6..f82528e 100644
--- a/server/console.c
+++ b/server/console.c
@@ -38,8 +38,6 @@
struct console_input
{
struct object obj; /* object header */
- int fd; /* file descriptor */
- int select; /* select user id */
int mode; /* input mode */
struct screen_buffer *output; /* associated screen buffer */
int recnum; /* number of input records */
@@ -49,8 +47,6 @@
struct screen_buffer
{
struct object obj; /* object header */
- int fd; /* file descriptor */
- int select; /* select user id */
int mode; /* output mode */
struct console_input *input; /* associated console input */
int cursor_size; /* size of cursor (percentage filled) */
@@ -61,16 +57,12 @@
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 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_poll_events( struct object *obj );
static int console_input_get_read_fd( struct object *obj );
static void console_input_destroy( struct object *obj );
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 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_poll_events( struct object *obj );
static int screen_buffer_get_write_fd( struct object *obj );
static void screen_buffer_destroy( struct object *obj );
@@ -79,32 +71,36 @@
static const struct object_ops console_input_ops =
{
- sizeof(struct console_input),
- console_input_dump,
- console_input_add_queue,
- console_input_remove_queue,
- console_input_signaled,
- no_satisfied,
- console_input_get_read_fd,
- no_write_fd,
- no_flush,
- console_get_info,
- console_input_destroy
+ sizeof(struct console_input), /* size */
+ console_input_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ console_input_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ console_input_get_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ console_get_info, /* get_file_info */
+ console_input_destroy /* destroy */
};
static const struct object_ops screen_buffer_ops =
{
- sizeof(struct screen_buffer),
- screen_buffer_dump,
- screen_buffer_add_queue,
- screen_buffer_remove_queue,
- screen_buffer_signaled,
- no_satisfied,
- no_read_fd,
- screen_buffer_get_write_fd,
- no_flush,
- console_get_info,
- screen_buffer_destroy
+ sizeof(struct screen_buffer), /* size */
+ screen_buffer_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ screen_buffer_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ screen_buffer_get_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ console_get_info, /* get_file_info */
+ screen_buffer_destroy /* destroy */
};
@@ -117,21 +113,13 @@
file_set_error();
return NULL;
}
- if ((console_input = alloc_object( &console_input_ops )))
- {
- console_input->fd = fd;
- console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
- ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
- console_input->output = NULL;
- console_input->recnum = 0;
- console_input->records = NULL;
- console_input->select = add_select_user( fd, default_select_event, console_input );
- if (console_input->select != -1) return &console_input->obj;
- release_object( console_input );
- return NULL;
- }
- close( fd );
- return NULL;
+ if (!(console_input = alloc_object( &console_input_ops, fd ))) return NULL;
+ console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+ ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
+ console_input->output = NULL;
+ console_input->recnum = 0;
+ console_input->records = NULL;
+ return &console_input->obj;
}
static struct object *create_console_output( int fd, struct object *input )
@@ -144,26 +132,15 @@
file_set_error();
return NULL;
}
- if ((screen_buffer = alloc_object( &screen_buffer_ops )))
- {
- screen_buffer->fd = fd;
- screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
- screen_buffer->input = console_input;
- screen_buffer->cursor_size = 100;
- screen_buffer->cursor_visible = 1;
- screen_buffer->pid = 0;
- screen_buffer->title = strdup( "Wine console" );
- 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;
- return &screen_buffer->obj;
- }
- close( fd );
- return NULL;
+ if (!(screen_buffer = alloc_object( &screen_buffer_ops, fd ))) return NULL;
+ screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
+ screen_buffer->input = console_input;
+ screen_buffer->cursor_size = 100;
+ screen_buffer->cursor_visible = 1;
+ screen_buffer->pid = 0;
+ screen_buffer->title = strdup( "Wine console" );
+ console_input->output = screen_buffer;
+ return &screen_buffer->obj;
}
/* allocate a console for this process */
@@ -223,10 +200,8 @@
assert( !input->obj.head );
assert( !output->obj.head );
- change_select_fd( input->select, fd_in );
- change_select_fd( output->select, fd_out );
- input->fd = fd_in;
- output->fd = fd_out;
+ change_select_fd( &input->obj, fd_in );
+ change_select_fd( &output->obj, fd_out );
output->pid = pid;
release_object( input );
release_object( output );
@@ -360,54 +335,19 @@
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- fprintf( stderr, "Console input fd=%d\n", console->fd );
+ fprintf( stderr, "Console input fd=%d\n", console->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;
- 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;
- }
+ return POLLIN;
}
static int console_input_get_read_fd( struct object *obj )
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- return dup( console->fd );
+ return dup( console->obj.fd );
}
static int console_get_info( struct object *obj, struct get_file_info_request *req )
@@ -429,7 +369,6 @@
{
struct console_input *console = (struct console_input *)obj;
assert( obj->ops == &console_input_ops );
- remove_select_user( console->select );
if (console->output) console->output->input = NULL;
}
@@ -437,61 +376,25 @@
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
+ fprintf( stderr, "Console screen buffer fd=%d\n", console->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;
- 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;
- }
+ return POLLOUT;
}
static int screen_buffer_get_write_fd( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- return dup( console->fd );
+ return dup( console->obj.fd );
}
static void screen_buffer_destroy( struct object *obj )
{
struct screen_buffer *console = (struct screen_buffer *)obj;
assert( obj->ops == &screen_buffer_ops );
- remove_select_user( console->select );
if (console->input) console->input->output = NULL;
if (console->title) free( console->title );
}
diff --git a/server/device.c b/server/device.c
index b9f488e..b2c038e 100644
--- a/server/device.c
+++ b/server/device.c
@@ -34,23 +34,25 @@
static const struct object_ops device_ops =
{
- sizeof(struct device),
- device_dump,
- no_add_queue,
- NULL, /* should never get called */
- NULL, /* should never get called */
- NULL, /* should never get called */
- no_read_fd,
- no_write_fd,
- no_flush,
- device_get_info,
- no_destroy
+ sizeof(struct device), /* size */
+ device_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ device_get_info, /* get_file_info */
+ no_destroy /* destroy */
};
static struct device *create_device( int id )
{
struct device *dev;
- if ((dev = alloc_object( &device_ops )))
+ if ((dev = alloc_object( &device_ops, -1 )))
{
dev->id = id;
}
diff --git a/server/event.c b/server/event.c
index db4a7a0..b5e3e3a 100644
--- a/server/event.c
+++ b/server/event.c
@@ -28,17 +28,19 @@
static const struct object_ops event_ops =
{
- sizeof(struct event),
- event_dump,
- add_queue,
- remove_queue,
- event_signaled,
- event_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- no_destroy
+ sizeof(struct event), /* size */
+ event_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ event_signaled, /* signaled */
+ event_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ no_destroy /* destroy */
};
diff --git a/server/file.c b/server/file.c
index c80ecce..3cc46bd 100644
--- a/server/file.c
+++ b/server/file.c
@@ -32,8 +32,6 @@
struct file
{
struct object obj; /* object header */
- int fd; /* file descriptor */
- int select; /* select user id */
struct file *next; /* next file in hashing list */
char *name; /* file name */
unsigned int access; /* file access (GENERIC_READ/WRITE) */
@@ -46,9 +44,7 @@
static struct file *file_hash[NAME_HASH_SIZE];
static void file_dump( struct object *obj, int verbose );
-static int file_add_queue( struct object *obj, struct wait_queue_entry *entry );
-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_poll_events( struct object *obj );
static int file_get_read_fd( struct object *obj );
static int file_get_write_fd( struct object *obj );
static int file_flush( struct object *obj );
@@ -57,17 +53,19 @@
static const struct object_ops file_ops =
{
- sizeof(struct file),
- file_dump,
- file_add_queue,
- file_remove_queue,
- file_signaled,
- no_satisfied,
- file_get_read_fd,
- file_get_write_fd,
- file_flush,
- file_get_info,
- file_destroy
+ sizeof(struct file), /* size */
+ file_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ file_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ file_get_read_fd, /* get_read_fd */
+ file_get_write_fd, /* get_write_fd */
+ file_flush, /* flush */
+ file_get_info, /* get_file_info */
+ file_destroy /* destroy */
};
@@ -103,23 +101,19 @@
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,
unsigned int attrs )
{
struct file *file;
- if ((file = alloc_object( &file_ops )))
+ if ((file = alloc_object( &file_ops, fd )))
{
file->name = NULL;
file->next = NULL;
- file->fd = fd;
file->access = access;
file->flags = attrs;
file->sharing = sharing;
- if ((file->select = add_select_user( fd, default_select_event, file )) == -1)
- {
- release_object( file );
- file = NULL;
- }
}
return file;
}
@@ -171,7 +165,11 @@
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->next = file_hash[hash];
file_hash[hash] = file;
@@ -212,81 +210,41 @@
/* Create a temp file for anonymous mappings */
struct file *create_temp_file( int access )
{
- struct file *file;
int fd;
if ((fd = create_anonymous_file()) == -1) return NULL;
- if (!(file = create_file_for_fd( fd, access, 0, 0 ))) close( fd );
- return file;
+ return create_file_for_fd( fd, access, 0, 0 );
}
static void file_dump( struct object *obj, int verbose )
{
struct file *file = (struct file *)obj;
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;
- assert( obj->ops == &file_ops );
- if (!obj->head) /* first on the queue */
- {
- int events = 0;
- if (file->access & GENERIC_READ) events |= POLLIN;
- if (file->access & GENERIC_WRITE) events |= POLLOUT;
- set_select_events( file->select, 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;
- }
+ return events;
}
static int file_get_read_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
- return dup( file->fd );
+ return dup( file->obj.fd );
}
static int file_get_write_fd( struct object *obj )
{
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
- return dup( file->fd );
+ return dup( file->obj.fd );
}
static int file_flush( struct object *obj )
@@ -295,7 +253,7 @@
struct file *file = (struct file *)grab_object(obj);
assert( obj->ops == &file_ops );
- ret = (fsync( file->fd ) != -1);
+ ret = (fsync( file->obj.fd ) != -1);
if (!ret) file_set_error();
release_object( file );
return ret;
@@ -307,13 +265,13 @@
struct file *file = (struct file *)obj;
assert( obj->ops == &file_ops );
- if (fstat( file->fd, &st ) == -1)
+ if (fstat( file->obj.fd, &st ) == -1)
{
file_set_error();
return 0;
}
if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
- S_ISSOCK(st.st_mode) || isatty(file->fd)) 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;
if (S_ISDIR(st.st_mode)) req->attr = FILE_ATTRIBUTE_DIRECTORY;
else req->attr = FILE_ATTRIBUTE_ARCHIVE;
@@ -344,7 +302,6 @@
if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
free( file->name );
}
- remove_select_user( file->select );
}
/* set the last error depending on errno */
@@ -379,7 +336,7 @@
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 )
@@ -396,7 +353,7 @@
if (!(file = get_file_obj( current->process, handle, 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 */
if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
@@ -418,8 +375,8 @@
if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
return 0;
- if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
- (ftruncate( file->fd, result ) == -1))
+ if (((result = lseek( file->obj.fd, 0, SEEK_CUR )) == -1) ||
+ (ftruncate( file->obj.fd, result ) == -1))
{
file_set_error();
release_object( file );
@@ -440,13 +397,13 @@
set_error( ERROR_INVALID_PARAMETER );
return 0;
}
- if (fstat( file->fd, &st ) == -1)
+ if (fstat( file->obj.fd, &st ) == -1)
{
file_set_error();
return 0;
}
if (st.st_size >= size_low) return 1; /* already large enough */
- if (ftruncate( file->fd, size_low ) != -1) return 1;
+ if (ftruncate( file->obj.fd, size_low ) != -1) return 1;
file_set_error();
return 0;
}
@@ -518,7 +475,6 @@
req->handle = alloc_handle( current->process, file, req->access, 0 );
release_object( file );
}
- else close( fd );
}
else file_set_error();
}
diff --git a/server/handle.c b/server/handle.c
index ea6d6c8..be81511 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -69,17 +69,19 @@
static const struct object_ops handle_table_ops =
{
- sizeof(struct handle_table),
- handle_table_dump,
- no_add_queue,
- NULL, /* should never get called */
- NULL, /* should never get called */
- NULL, /* should never get called */
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- handle_table_destroy
+ sizeof(struct handle_table), /* size */
+ handle_table_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ handle_table_destroy /* destroy */
};
/* dump a handle table */
@@ -127,7 +129,7 @@
struct handle_table *table;
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;
table->process = process;
table->count = count;
diff --git a/server/mapping.c b/server/mapping.c
index bf45e04..66fefd2 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -32,17 +32,19 @@
static const struct object_ops mapping_ops =
{
- sizeof(struct mapping),
- mapping_dump,
- no_add_queue,
- NULL, /* should never get called */
- NULL, /* should never get called */
- NULL, /* should never get called */
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- mapping_destroy
+ sizeof(struct mapping), /* size */
+ mapping_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ mapping_destroy /* destroy */
};
#ifdef __i386__
diff --git a/server/mutex.c b/server/mutex.c
index 1ce86f9..c818d8a 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -32,17 +32,19 @@
static const struct object_ops mutex_ops =
{
- sizeof(struct mutex),
- mutex_dump,
- add_queue,
- remove_queue,
- mutex_signaled,
- mutex_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- mutex_destroy
+ sizeof(struct mutex), /* size */
+ mutex_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ mutex_signaled, /* signaled */
+ mutex_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ mutex_destroy /* destroy */
};
diff --git a/server/object.c b/server/object.c
index 9d44965..28cfe67 100644
--- a/server/object.c
+++ b/server/object.c
@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "winerror.h"
#include "thread.h"
@@ -121,23 +122,34 @@
}
/* 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 );
if (obj)
{
obj->refcount = 1;
+ obj->fd = fd;
+ obj->select = -1;
obj->ops = ops;
obj->head = NULL;
obj->tail = NULL;
obj->name = NULL;
+ if ((fd != -1) && (add_select_user( obj ) == -1))
+ {
+ close( fd );
+ free( obj );
+ return NULL;
+ }
#ifdef DEBUG_OBJECTS
obj->prev = NULL;
if ((obj->next = first) != NULL) obj->next->prev = obj;
first = obj;
#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 )
@@ -145,7 +157,7 @@
struct object *obj;
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 ((obj = find_object( name_ptr->name, name_ptr->len )))
@@ -159,7 +171,7 @@
set_error( ERROR_INVALID_HANDLE );
return NULL;
}
- if ((obj = alloc_object( ops )))
+ if ((obj = alloc_object( ops, -1 )))
{
set_object_name( obj, name_ptr );
clear_error();
@@ -199,14 +211,16 @@
/* if the refcount is 0, nobody can be in the wait queue */
assert( !obj->head );
assert( !obj->tail );
+ obj->ops->destroy( 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
if (obj->next) obj->next->prev = obj->prev;
if (obj->prev) obj->prev->next = obj->next;
else first = obj->next;
-#endif
- obj->ops->destroy( obj );
memset( obj, 0xaa, obj->ops->size );
+#endif
free( obj );
}
}
@@ -224,7 +238,7 @@
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 )
{
@@ -265,9 +279,45 @@
{
}
-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;
- assert( obj );
+ if (!obj->head) /* first on the queue */
+ 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 );
}
diff --git a/server/object.h b/server/object.h
index d5335f1..5825dce 100644
--- a/server/object.h
+++ b/server/object.h
@@ -41,6 +41,10 @@
int (*signaled)(struct object *,struct thread *);
/* wait satisfied; return 1 if abandoned */
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 */
int (*get_read_fd)(struct object *);
/* return a Unix fd that can be used to write to the object */
@@ -55,7 +59,9 @@
struct object
{
- unsigned int refcount;
+ unsigned int refcount; /* reference count */
+ int fd; /* file descriptor */
+ int select; /* select() user id */
const struct object_ops *ops;
struct wait_queue_entry *head;
struct wait_queue_entry *tail;
@@ -68,7 +74,7 @@
extern void *mem_alloc( size_t size ); /* malloc wrapper */
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 *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 */
@@ -83,17 +89,20 @@
extern int no_flush( struct object *obj );
extern int no_get_file_info( struct object *obj, struct get_file_info_request *info );
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
extern void dump_objects(void);
#endif
/* select functions */
-extern int add_select_user( int fd, void (*func)(int, void *), void *private );
-extern void remove_select_user( int user );
-extern void change_select_fd( int user, int fd );
-extern void set_select_events( int user, int events );
+extern int add_select_user( struct object *obj );
+extern void remove_select_user( struct object *obj );
+extern void change_select_fd( struct object *obj, int fd );
+extern void set_select_events( struct object *obj, int events );
extern int check_select_events( int fd, int events );
extern void select_loop(void);
@@ -114,15 +123,6 @@
((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 */
struct event;
diff --git a/server/pipe.c b/server/pipe.c
index f449ca6..49ec7aa 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -33,15 +33,11 @@
{
struct object obj; /* object header */
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 */
};
static void pipe_dump( struct object *obj, int verbose );
-static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry );
-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_poll_events( 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_info( struct object *obj, struct get_file_info_request *req );
@@ -49,17 +45,19 @@
static const struct object_ops pipe_ops =
{
- sizeof(struct pipe),
- pipe_dump,
- pipe_add_queue,
- pipe_remove_queue,
- pipe_signaled,
- no_satisfied,
- pipe_get_read_fd,
- pipe_get_write_fd,
- no_flush,
- pipe_get_info,
- pipe_destroy
+ sizeof(struct pipe), /* size */
+ pipe_dump, /* dump */
+ default_poll_add_queue, /* add_queue */
+ default_poll_remove_queue, /* remove_queue */
+ default_poll_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ pipe_get_poll_events, /* get_poll_events */
+ default_poll_event, /* poll_event */
+ pipe_get_read_fd, /* get_read_fd */
+ pipe_get_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ pipe_get_info, /* get_file_info */
+ pipe_destroy /* destroy */
};
@@ -67,16 +65,10 @@
{
struct pipe *pipe;
- if ((pipe = alloc_object( &pipe_ops )))
+ if ((pipe = alloc_object( &pipe_ops, fd )))
{
- pipe->fd = fd;
pipe->other = NULL;
pipe->side = side;
- if ((pipe->select = add_select_user( fd, default_select_event, pipe )) == -1)
- {
- release_object( pipe );
- pipe = NULL;
- }
}
return pipe;
}
@@ -104,8 +96,7 @@
}
release_object( read_pipe );
}
- close( fd[0] );
- close( fd[1] );
+ else close( fd[1] );
return 0;
}
@@ -114,49 +105,14 @@
struct pipe *pipe = (struct pipe *)obj;
assert( obj->ops == &pipe_ops );
fprintf( stderr, "Pipe %s-side fd=%d\n",
- (pipe->side == READ_SIDE) ? "read" : "write", pipe->fd );
+ (pipe->side == READ_SIDE) ? "read" : "write", pipe->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;
assert( obj->ops == &pipe_ops );
- if (!obj->head) /* first on the queue */
- 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;
- }
+ return (pipe->side == READ_SIDE) ? POLLIN : POLLOUT;
}
static int pipe_get_read_fd( struct object *obj )
@@ -174,7 +130,7 @@
set_error( ERROR_ACCESS_DENIED );
return -1;
}
- return dup( pipe->fd );
+ return dup( pipe->obj.fd );
}
static int pipe_get_write_fd( struct object *obj )
@@ -192,7 +148,7 @@
set_error( ERROR_ACCESS_DENIED );
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 )
@@ -216,7 +172,6 @@
assert( obj->ops == &pipe_ops );
if (pipe->other) pipe->other->other = NULL;
- remove_select_user( pipe->select );
}
/* create an anonymous pipe */
diff --git a/server/process.c b/server/process.c
index 3bc200d..20892ba 100644
--- a/server/process.c
+++ b/server/process.c
@@ -36,17 +36,19 @@
static const struct object_ops process_ops =
{
- sizeof(struct process),
- process_dump,
- add_queue,
- remove_queue,
- process_signaled,
- no_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- process_destroy
+ sizeof(struct process), /* size */
+ process_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ process_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ process_destroy /* destroy */
};
@@ -56,7 +58,7 @@
{
struct process *process;
- if (!(process = alloc_object( &process_ops ))) return NULL;
+ if (!(process = alloc_object( &process_ops, -1 ))) return NULL;
process->next = NULL;
process->prev = NULL;
process->thread_list = NULL;
diff --git a/server/registry.c b/server/registry.c
index b28a2ce..e7dd55f 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -106,17 +106,19 @@
static const struct object_ops key_ops =
{
- sizeof(struct key),
- key_dump,
- no_add_queue,
- NULL, /* should never get called */
- NULL, /* should never get called */
- NULL, /* should never get called */
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- key_destroy
+ sizeof(struct key), /* size */
+ key_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ key_destroy /* destroy */
};
@@ -322,7 +324,7 @@
static struct key *alloc_key( const WCHAR *name, time_t modif )
{
struct key *key;
- if ((key = (struct key *)alloc_object( &key_ops )))
+ if ((key = (struct key *)alloc_object( &key_ops, -1 )))
{
key->name = NULL;
key->class = NULL;
diff --git a/server/request.c b/server/request.c
index 56b394d..62b15e9 100644
--- a/server/request.c
+++ b/server/request.c
@@ -4,13 +4,20 @@
* Copyright (C) 1998 Alexandre Julliard
*/
+#include "config.h"
+
#include <assert.h>
-#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <signal.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>
@@ -22,9 +29,30 @@
#include "server.h"
#define WANT_REQUEST_HANDLERS
#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 */
+
+/* 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 */
void fatal_protocol_error( struct thread *thread, const char *err, ... )
{
@@ -34,11 +62,11 @@
fprintf( stderr, "Protocol error:%p: ", thread );
vfprintf( stderr, err, args );
va_end( args );
- remove_client( thread->client, PROTOCOL_ERROR );
+ kill_thread( thread, PROTOCOL_ERROR );
}
/* 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;
clear_error();
@@ -65,31 +93,109 @@
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 */
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 */
void send_reply( struct thread *thread )
{
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 */
diff --git a/server/request.h b/server/request.h
index d34c798..766b924 100644
--- a/server/request.h
+++ b/server/request.h
@@ -26,17 +26,17 @@
/* 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 call_req_handler( struct thread *thread, enum request req, int fd );
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 send_reply( struct thread *thread );
extern void trace_request( enum request req, int fd );
extern void trace_timeout(void);
-extern void trace_kill( int exit_code );
-extern void trace_reply( struct thread *thread, unsigned int res, int pass_fd );
+extern void trace_kill( struct thread *thread );
+extern void trace_reply( struct thread *thread );
/* get the request buffer */
static inline void *get_req_ptr( struct thread *thread )
diff --git a/server/select.c b/server/select.c
index a1286cf..98b4817 100644
--- a/server/select.c
+++ b/server/select.c
@@ -19,12 +19,6 @@
#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 *next; /* next in sorted timeout list */
@@ -34,32 +28,31 @@
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 int nb_users; /* count of array entries actually in use */
static int active_users; /* current number of active users */
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_tail; /* sorted timeouts list tail */
/* 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;
if (freelist)
{
ret = freelist - poll_users;
- freelist = poll_users[ret].private;
- assert( !poll_users[ret].func );
+ freelist = (struct object **)poll_users[ret];
}
else
{
if (nb_users == allocated_users)
{
- struct poll_user *newusers;
+ struct object **newusers;
struct pollfd *newpoll;
int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
@@ -74,43 +67,53 @@
}
ret = nb_users++;
}
- pollfd[ret].fd = fd;
+ pollfd[ret].fd = obj->fd;
pollfd[ret].events = 0;
pollfd[ret].revents = 0;
- poll_users[ret].func = func;
- poll_users[ret].private = private;
+ poll_users[ret] = obj;
+ obj->select = ret;
active_users++;
return ret;
}
-/* remove a user and close its fd */
-void remove_select_user( int user )
+/* remove an object from the select list and close its fd */
+void remove_select_user( struct object *obj )
{
- if (user == -1) return; /* avoids checking in all callers */
- assert( poll_users[user].func );
- close( pollfd[user].fd );
+ int user = obj->select;
+ assert( poll_users[user] == obj );
pollfd[user].fd = -1;
pollfd[user].events = 0;
pollfd[user].revents = 0;
- poll_users[user].func = NULL;
- poll_users[user].private = freelist;
+ poll_users[user] = (struct object *)freelist;
freelist = &poll_users[user];
+ close( obj->fd );
+ obj->fd = -1;
+ obj->select = -1;
active_users--;
}
-/* change the fd of a select user (the old fd is closed) */
-void change_select_fd( int user, int fd )
+/* change the fd of an object (the old fd is closed) */
+void change_select_fd( struct object *obj, int fd )
{
- assert( poll_users[user].func );
- close( pollfd[user].fd );
+ int user = obj->select;
+ assert( poll_users[user] == obj );
pollfd[user].fd = fd;
+ close( obj->fd );
+ obj->fd = 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 );
- pollfd[user].events = events;
+ int user = obj->select;
+ 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 */
@@ -259,7 +262,7 @@
{
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;
}
}
diff --git a/server/semaphore.c b/server/semaphore.c
index 36656f4..221d533 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -28,17 +28,19 @@
static const struct object_ops semaphore_ops =
{
- sizeof(struct semaphore),
- semaphore_dump,
- add_queue,
- remove_queue,
- semaphore_signaled,
- semaphore_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- no_destroy
+ sizeof(struct semaphore), /* size */
+ semaphore_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ semaphore_signaled, /* signaled */
+ semaphore_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ no_destroy /* destroy */
};
diff --git a/server/snapshot.c b/server/snapshot.c
index 5ac30cc..173fb9d 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -33,17 +33,19 @@
static const struct object_ops snapshot_ops =
{
- sizeof(struct snapshot),
- snapshot_dump,
- no_add_queue,
- NULL, /* should never get called */
- NULL, /* should never get called */
- NULL, /* should never get called */
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- snapshot_destroy
+ sizeof(struct snapshot), /* size */
+ snapshot_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ snapshot_destroy /* destroy */
};
@@ -52,7 +54,7 @@
{
struct snapshot *snapshot;
- if ((snapshot = alloc_object( &snapshot_ops )))
+ if ((snapshot = alloc_object( &snapshot_ops, -1 )))
{
if (flags & TH32CS_SNAPPROCESS)
snapshot->process = process_snap( &snapshot->process_count );
diff --git a/server/sock.c b/server/sock.c
index cb9928f..531231b 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -42,8 +42,6 @@
struct sock
{
struct object obj; /* object header */
- int fd; /* file descriptor */
- int select; /* select user */
unsigned int state; /* status bits */
unsigned int mask; /* event mask */
unsigned int hmask; /* held (blocked) events */
@@ -53,51 +51,36 @@
};
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_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 void sock_destroy( struct object *obj );
static void sock_set_error(void);
static const struct object_ops sock_ops =
{
- sizeof(struct sock),
- sock_dump,
- sock_add_queue,
- sock_remove_queue,
- sock_signaled,
- no_satisfied,
- sock_get_fd,
- sock_get_fd,
- no_flush,
- no_get_file_info,
- sock_destroy
+ sizeof(struct sock), /* size */
+ sock_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ sock_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ sock_get_poll_events, /* get_poll_events */
+ sock_poll_event, /* poll_event */
+ sock_get_fd, /* get_read_fd */
+ sock_get_fd, /* get_write_fd */
+ 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 )
{
- int ev = sock_event( sock );
+ int ev = sock_get_poll_events( &sock->obj );
if (debug_level)
- fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->fd, ev);
- set_select_events( sock->select, ev );
+ fprintf(stderr,"sock_reselect(%d): new mask %x\n", sock->obj.fd, ev);
+ set_select_events( &sock->obj, ev );
}
inline static int sock_error(int s)
@@ -109,13 +92,13 @@
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;
assert( sock->obj.ops == &sock_ops );
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)
{
/* connecting */
@@ -127,16 +110,16 @@
sock->pmask |= FD_CONNECT;
sock->errors[FD_CONNECT_BIT] = 0;
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))
{
/* we didn't get connected? */
sock->state &= ~WS_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)
- fprintf(stderr, "socket %d connection failure\n", sock->fd);
+ fprintf(stderr, "socket %d connection failure\n", sock->obj.fd);
}
} else
if (sock->state & WS_FD_LISTENING)
@@ -153,7 +136,7 @@
{
/* failed incoming connection? */
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;
}
} else
@@ -161,27 +144,12 @@
/* normal data flow */
if (event & POLLIN)
{
- /* make sure there's data here */
- int bytes = 0;
- ioctl(sock->fd, FIONREAD, (char*)&bytes);
- if (bytes)
- {
- /* incoming data */
- sock->pmask |= FD_READ;
- sock->hmask |= FD_READ;
- sock->errors[FD_READ_BIT] = 0;
- if (debug_level)
- fprintf(stderr, "socket %d has %d bytes\n", sock->fd, bytes);
- }
- 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);
- }
+ /* incoming data */
+ sock->pmask |= FD_READ;
+ sock->hmask |= FD_READ;
+ sock->errors[FD_READ_BIT] = 0;
+ if (debug_level)
+ fprintf(stderr, "socket %d is readable\n", sock->obj.fd );
}
if (event & POLLOUT)
{
@@ -189,27 +157,24 @@
sock->hmask |= FD_WRITE;
sock->errors[FD_WRITE_BIT] = 0;
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))
{
- sock->errors[FD_CLOSE_BIT] = sock_error( sock->fd );
- if (sock->errors[FD_CLOSE_BIT])
- {
- /* we got an error, socket closing? */
- sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
- sock->pmask |= FD_CLOSE;
- if (debug_level)
- fprintf(stderr, "socket %d aborted by error %d\n", sock->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);
- }
+ sock->errors[FD_CLOSE_BIT] = sock_error( sock->obj.fd );
+ /* we got an error, socket closing? */
+ sock->state &= ~(WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE);
+ sock->pmask |= FD_CLOSE;
+ if (debug_level)
+ fprintf(stderr, "socket %d aborted by error %d\n",
+ sock->obj.fd, sock->errors[FD_CLOSE_BIT]);
}
}
@@ -217,7 +182,7 @@
/* wake up anyone waiting for whatever just happened */
emask = sock->pmask & sock->mask;
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 (debug_level) fprintf(stderr, "signalling event ptr %p\n", sock->event);
set_event(sock->event);
@@ -233,34 +198,36 @@
struct sock *sock = (struct sock *)obj;
assert( obj->ops == &sock_ops );
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 );
}
-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 )
{
struct sock *sock = (struct sock *)obj;
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 )
@@ -268,7 +235,7 @@
struct sock *sock = (struct sock *)obj;
int fd;
assert( obj->ops == &sock_ops );
- fd = dup( sock->fd );
+ fd = dup( sock->obj.fd );
if (fd==-1)
sock_set_error();
return fd;
@@ -280,7 +247,6 @@
assert( obj->ops == &sock_ops );
/* FIXME: special socket shutdown stuff? */
- remove_select_user( sock->select );
if (sock->event)
{
/* if the service thread was waiting for the event object,
@@ -307,21 +273,12 @@
return NULL;
}
fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
- if (!(sock = alloc_object( &sock_ops ))) {
- close( sockfd );
- return NULL;
- }
- sock->fd = sockfd;
+ if (!(sock = alloc_object( &sock_ops, sockfd ))) return NULL;
sock->state = (type!=SOCK_STREAM) ? WS_FD_READ|WS_FD_WRITE : 0;
sock->mask = 0;
sock->hmask = 0;
sock->pmask = 0;
sock->event = NULL;
- if ((sock->select = add_select_user( sockfd, sock_select_event, sock )) == -1)
- {
- release_object( sock );
- return NULL;
- }
sock_reselect( sock );
clear_error();
return &sock->obj;
@@ -345,32 +302,23 @@
* return.
*/
slen = sizeof(saddr);
- acceptfd = accept(sock->fd,&saddr,&slen);
+ acceptfd = accept(sock->obj.fd,&saddr,&slen);
if (acceptfd==-1) {
sock_set_error();
release_object( sock );
return NULL;
}
- if (!(acceptsock = alloc_object( &sock_ops )))
+ if (!(acceptsock = alloc_object( &sock_ops, acceptfd )))
{
- close( acceptfd );
release_object( sock );
return NULL;
}
- acceptsock->fd = acceptfd;
acceptsock->state = WS_FD_CONNECTED|WS_FD_READ|WS_FD_WRITE;
acceptsock->mask = sock->mask;
acceptsock->hmask = 0;
acceptsock->pmask = 0;
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 );
sock_reselect( acceptsock );
diff --git a/server/socket.c b/server/socket.c
deleted file mode 100644
index fb3345a..0000000
--- a/server/socket.c
+++ /dev/null
@@ -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 );
-}
diff --git a/server/thread.c b/server/thread.c
index e319f51..baaff4c 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -63,21 +63,24 @@
static void dump_thread( struct object *obj, int verbose );
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 const struct object_ops thread_ops =
{
- sizeof(struct thread),
- dump_thread,
- add_queue,
- remove_queue,
- thread_signaled,
- no_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- destroy_thread
+ sizeof(struct thread), /* size */
+ dump_thread, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ thread_signaled, /* signaled */
+ no_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ thread_poll_event, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ destroy_thread /* destroy */
};
static struct thread *first_thread;
@@ -105,9 +108,11 @@
struct thread *thread;
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 );
- thread->client = NULL;
+ if (!(thread = alloc_object( &thread_ops, fd ))) return NULL;
+
thread->unix_pid = 0; /* not known yet */
thread->teb = NULL;
thread->mutex = NULL;
@@ -118,6 +123,7 @@
thread->apc = NULL;
thread->apc_count = 0;
thread->error = 0;
+ thread->pass_fd = -1;
thread->state = RUNNING;
thread->attached = 0;
thread->exit_code = 0x103; /* STILL_ACTIVE */
@@ -142,11 +148,8 @@
add_process_thread( process, thread );
if ((buf_fd = alloc_client_buffer( thread )) == -1) goto error;
- if (!(thread->client = add_client( fd, thread )))
- {
- close( buf_fd );
- goto error;
- }
+
+ set_select_events( &thread->obj, POLLIN ); /* start listening to events */
set_reply_fd( thread, buf_fd ); /* send the fd to the client */
send_reply( thread );
return thread;
@@ -164,6 +167,20 @@
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 */
static void destroy_thread( struct object *obj )
{
@@ -177,6 +194,7 @@
else first_thread = thread->next;
if (thread->apc) free( thread->apc );
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 */
@@ -499,21 +517,17 @@
void kill_thread( struct thread *thread, int exit_code )
{
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->exit_code = exit_code;
- thread->client = NULL;
+ if (current == thread) current = NULL;
+ if (debug_level) trace_kill( thread );
if (thread->wait) end_wait( thread );
debug_exit_thread( thread, exit_code );
abandon_mutexes( thread );
remove_process_thread( thread->process, thread );
wake_up( &thread->obj, 0 );
detach_thread( thread );
+ remove_select_user( &thread->obj );
release_object( thread );
}
diff --git a/server/thread.h b/server/thread.h
index bfe9bf4..f847fc4 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -46,10 +46,10 @@
struct thread_apc *apc; /* list of async procedure calls */
int apc_count; /* number of outstanding APCs */
int error; /* current error code */
+ int pass_fd; /* fd to pass to the client */
enum run_state state; /* running state */
int attached; /* is thread attached with ptrace? */
int exit_code; /* thread exit code */
- struct client *client; /* client for socket communications */
int unix_pid; /* Unix pid of client */
void *teb; /* TEB address (in client address space) */
int priority; /* priority level */
@@ -74,7 +74,6 @@
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 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 wake_up( struct object *obj, int max );
diff --git a/server/timer.c b/server/timer.c
index d228d16..9ded7bd 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -39,17 +39,19 @@
static const struct object_ops timer_ops =
{
- sizeof(struct timer),
- timer_dump,
- add_queue,
- remove_queue,
- timer_signaled,
- timer_satisfied,
- no_read_fd,
- no_write_fd,
- no_flush,
- no_get_file_info,
- timer_destroy
+ sizeof(struct timer), /* size */
+ timer_dump, /* dump */
+ add_queue, /* add_queue */
+ remove_queue, /* remove_queue */
+ timer_signaled, /* signaled */
+ timer_satisfied, /* satisfied */
+ NULL, /* get_poll_events */
+ NULL, /* poll_event */
+ no_read_fd, /* get_read_fd */
+ no_write_fd, /* get_write_fd */
+ no_flush, /* flush */
+ no_get_file_info, /* get_file_info */
+ timer_destroy /* destroy */
};
diff --git a/server/trace.c b/server/trace.c
index 0e436f2..c9643e9 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1341,22 +1341,22 @@
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",
- (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",
- (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])
{
fprintf( stderr, " {" );
reply_dumpers[thread->last_req]( thread->buffer );
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" );
}