From 1dca5e24c70fe2e42a6ffb49f79d2578561a6e44 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 1 Jan 2000 00:56:27 +0000 Subject: [PATCH] Moved poll handling to the generic part of the server objects. Fixed busy waiting on POLLERR events. Merged struct client into struct thread. --- server/Makefile.in | 1 - server/change.c | 26 +++--- server/console.c | 205 ++++++++++++------------------------------ server/device.c | 26 +++--- server/event.c | 24 ++--- server/file.c | 118 ++++++++----------------- server/handle.c | 26 +++--- server/mapping.c | 24 ++--- server/mutex.c | 24 ++--- server/object.c | 70 ++++++++++++--- server/object.h | 32 +++---- server/pipe.c | 87 +++++------------- server/process.c | 26 +++--- server/registry.c | 26 +++--- server/request.c | 148 ++++++++++++++++++++++++++----- server/request.h | 8 +- server/select.c | 63 ++++++------- server/semaphore.c | 24 ++--- server/snapshot.c | 26 +++--- server/sock.c | 198 +++++++++++++++-------------------------- server/socket.c | 216 --------------------------------------------- server/thread.c | 64 ++++++++------ server/thread.h | 3 +- server/timer.c | 24 ++--- server/trace.c | 10 +-- 25 files changed, 619 insertions(+), 880 deletions(-) delete mode 100644 server/socket.c diff --git a/server/Makefile.in b/server/Makefile.in index 60aa6e0f647..b4ec97ab179 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -25,7 +25,6 @@ C_SRCS = \ 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 50f193eded7..8347651da20 100644 --- a/server/change.c +++ b/server/change.c @@ -27,24 +27,26 @@ static int change_signaled( struct object *obj, struct thread *thread ); 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 d34fee6660b..f82528ed7d8 100644 --- a/server/console.c +++ b/server/console.c @@ -38,8 +38,6 @@ struct screen_buffer; 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 console_input 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 @@ struct screen_buffer 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 int console_get_info( struct object *obj, struct get_file_info_request *r 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 @@ static struct object *create_console_input( int fd ) 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 @@ static struct object *create_console_output( int fd, struct object *input ) 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 @@ static int set_console_fd( int handle, int fd_in, int fd_out, int pid ) 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 @@ static void console_input_dump( struct object *obj, int verbose ) { struct console_input *console = (struct console_input *)obj; assert( obj->ops == &console_input_ops ); - fprintf( stderr, "Console input fd=%d\n", console->fd ); + fprintf( stderr, "Console input fd=%d\n", console->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 @@ static void console_input_destroy( struct object *obj ) { 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 @@ static void screen_buffer_dump( struct object *obj, int verbose ) { struct screen_buffer *console = (struct screen_buffer *)obj; assert( obj->ops == &screen_buffer_ops ); - fprintf( stderr, "Console screen buffer fd=%d\n", console->fd ); + fprintf( stderr, "Console screen buffer fd=%d\n", console->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 b9f488e7cb8..b2c038e1c88 100644 --- a/server/device.c +++ b/server/device.c @@ -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 = { - 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 db4a7a04fef..b5e3e3a9e69 100644 --- a/server/event.c +++ b/server/event.c @@ -28,17 +28,19 @@ static int event_satisfied( struct object *obj, struct thread *thread ); 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 c80ecceccc1..3cc46bd1d6b 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 @@ struct file 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 void file_destroy( struct object *obj ); 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 @@ static int check_sharing( const char *name, int hash, unsigned int access, 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 @@ static struct file *create_file( const char *nameptr, size_t len, unsigned int a 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 @@ int create_anonymous_file(void) /* 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 @@ static int file_flush( struct object *obj ) struct file *file = (struct file *)grab_object(obj); assert( obj->ops == &file_ops ); - ret = (fsync( file->fd ) != -1); + ret = (fsync( file->obj.fd ) != -1); if (!ret) file_set_error(); release_object( file ); 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; 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 @@ static void file_destroy( struct object *obj ) 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 @@ struct file *get_file_obj( struct process *process, int handle, unsigned int acc 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 @@ static int set_file_pointer( int handle, int *low, int *high, int whence ) if (!(file = get_file_obj( current->process, handle, 0 ))) return 0; - if ((result = lseek( file->fd, *low, whence )) == -1) + if ((result = lseek( file->obj.fd, *low, whence )) == -1) { /* Check for seek before start of file */ 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 ))) 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 @@ int grow_file( struct file *file, int size_high, int size_low ) set_error( ERROR_INVALID_PARAMETER ); return 0; } - if (fstat( file->fd, &st ) == -1) + if (fstat( file->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 @@ DECL_HANDLER(alloc_file_handle) 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 ea6d6c89f1e..be8151104b0 100644 --- a/server/handle.c +++ b/server/handle.c @@ -69,17 +69,19 @@ static void handle_table_destroy( struct object *obj ); 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 object *alloc_handle_table( struct process *process, int count ) 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 bf45e047e3f..66fefd250c5 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -32,17 +32,19 @@ static void mapping_destroy( struct object *obj ); 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 1ce86f9ec0b..c818d8a6e25 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -32,17 +32,19 @@ static void mutex_destroy( struct object *obj ); 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 9d44965eef2..28cfe67e91f 100644 --- a/server/object.c +++ b/server/object.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "winerror.h" #include "thread.h" @@ -121,23 +122,34 @@ static void set_object_name( struct object *obj, struct object_name *ptr ) } /* 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 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size 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 @@ void *create_named_object( const struct object_ops *ops, const WCHAR *name, size 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 @@ void release_object( void *ptr ) /* 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 @@ struct object *find_object( const WCHAR *name, size_t len ) 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 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; - 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 d5335f114d5..5825dceaff2 100644 --- a/server/object.h +++ b/server/object.h @@ -41,6 +41,10 @@ struct object_ops 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_ops 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 @@ struct object 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_write_fd( 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 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 @@ static inline int time_before( struct timeval *t1, struct timeval *t2 ) ((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 f449ca679db..49ec7aa91fd 100644 --- a/server/pipe.c +++ b/server/pipe.c @@ -33,15 +33,11 @@ struct pipe { 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 void pipe_destroy( struct object *obj ); 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 @@ static struct pipe *create_pipe_side( int fd, int side ) { 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 @@ static int create_pipe( struct object *obj[2] ) } release_object( read_pipe ); } - close( fd[0] ); - close( fd[1] ); + else close( fd[1] ); return 0; } @@ -114,49 +105,14 @@ static void pipe_dump( struct object *obj, int verbose ) struct pipe *pipe = (struct pipe *)obj; assert( obj->ops == &pipe_ops ); fprintf( stderr, "Pipe %s-side fd=%d\n", - (pipe->side == READ_SIDE) ? "read" : "write", pipe->fd ); + (pipe->side == READ_SIDE) ? "read" : "write", pipe->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 @@ static int pipe_get_read_fd( struct object *obj ) 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 @@ static int pipe_get_write_fd( struct object *obj ) 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 @@ static void pipe_destroy( struct object *obj ) 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 3bc200dbce8..20892bac678 100644 --- a/server/process.c +++ b/server/process.c @@ -36,17 +36,19 @@ static void process_destroy( struct object *obj ); 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 @@ static struct process *create_process( struct process *parent, struct new_proces { 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 b28a2cece6e..e7dd55ffa6c 100644 --- a/server/registry.c +++ b/server/registry.c @@ -106,17 +106,19 @@ static void key_destroy( struct object *obj ); 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 WCHAR *req_strdupW( const WCHAR *str ) 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 56b394d72de..62b15e9a4c5 100644 --- a/server/request.c +++ b/server/request.c @@ -4,13 +4,20 @@ * Copyright (C) 1998 Alexandre Julliard */ +#include "config.h" + #include -#include +#include +#include #include -#include #include -#include +#include +#include +#include #include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif #include #include @@ -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 @@ void fatal_protocol_error( struct thread *thread, const char *err, ... ) 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 @@ void call_timeout_handler( void *thread ) 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 d34c7986395..766b9247b51 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 a1286cf1730..98b4817e982 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 @@ struct timeout_user 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 @@ int add_select_user( int fd, void (*func)(int, void *), void *private ) } 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 @@ void select_loop(void) { 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 36656f4c6e8..221d5333afb 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -28,17 +28,19 @@ static int semaphore_satisfied( struct object *obj, struct thread *thread ); 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 5ac30ccd6a4..173fb9d6edd 100644 --- a/server/snapshot.c +++ b/server/snapshot.c @@ -33,17 +33,19 @@ static void snapshot_destroy( struct object *obj ); 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 @@ static struct snapshot *create_snapshot( int flags ) { 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 cb9928f173d..531231b2cfa 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 @@ struct sock }; 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 @@ inline static int sock_error(int s) 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 @@ static void sock_select_event( int event, void *private ) 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 @@ static void sock_select_event( int event, void *private ) { /* 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 @@ static void sock_select_event( int event, void *private ) /* 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 @@ static void sock_select_event( int event, void *private ) 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 @@ static void sock_select_event( int event, void *private ) /* 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 @@ static void sock_dump( struct object *obj, int verbose ) 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 @@ static int sock_get_fd( struct object *obj ) 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 @@ static void sock_destroy( struct object *obj ) 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 @@ static struct object *create_socket( int family, int type, int protocol ) 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 @@ static struct object *accept_socket( int handle ) * 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 fb3345a976b..00000000000 --- a/server/socket.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Server-side socket communication functions - * - * Copyright (C) 1998 Alexandre Julliard - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#include -#include - -#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 e319f510ae2..baaff4c2556 100644 --- a/server/thread.c +++ b/server/thread.c @@ -63,21 +63,24 @@ struct thread_apc 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 @@ static struct thread *create_thread( int fd, struct process *process, int suspen 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 ); + + if (!(thread = alloc_object( &thread_ops, fd ))) return NULL; - thread->client = NULL; thread->unix_pid = 0; /* not known yet */ thread->teb = 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_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 @@ static struct thread *create_thread( int fd, struct process *process, int suspen 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 @@ void create_initial_thread( int fd ) 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 @@ static void destroy_thread( struct object *obj ) 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 @@ static int thread_queue_apc( struct thread *thread, void *func, void *param ) 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 bfe9bf4c88e..f847fc4981d 100644 --- a/server/thread.h +++ b/server/thread.h @@ -46,10 +46,10 @@ struct thread 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 void resume_all_threads( void ); 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 d228d16e8e2..9ded7bd5c89 100644 --- a/server/timer.c +++ b/server/timer.c @@ -39,17 +39,19 @@ static void timer_destroy( struct object *obj ); 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 0e436f2f8ba..c9643e94527 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1341,22 +1341,22 @@ void trace_timeout(void) 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" ); }