diff --git a/server/Makefile.in b/server/Makefile.in index bfdc29b9012..6e4daa9369b 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -31,7 +31,6 @@ C_SRCS = \ queue.c \ registry.c \ request.c \ - select.c \ semaphore.c \ serial.c \ smb.c \ diff --git a/server/async.c b/server/async.c index 2249fa1f889..039833e1b29 100644 --- a/server/async.c +++ b/server/async.c @@ -28,6 +28,7 @@ #include #include "handle.h" +#include "file.h" #include "thread.h" #include "request.h" diff --git a/server/atom.c b/server/atom.c index 78378cf5c76..e14c05eff2b 100644 --- a/server/atom.c +++ b/server/atom.c @@ -101,7 +101,7 @@ static struct atom_table *create_table(int entries_count) { struct atom_table *table; - if ((table = alloc_object( &atom_table_ops, -1 ))) + if ((table = alloc_object( &atom_table_ops ))) { if ((entries_count < MIN_HASH_SIZE) || (entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE; diff --git a/server/change.c b/server/change.c index 0edb34bbc17..b1e69e0dd2e 100644 --- a/server/change.c +++ b/server/change.c @@ -54,7 +54,7 @@ static const struct object_ops change_ops = static struct change *create_change_notification( int subtree, int filter ) { struct change *change; - if ((change = alloc_object( &change_ops, -1 ))) + if ((change = alloc_object( &change_ops ))) { change->subtree = subtree; change->filter = filter; diff --git a/server/console.c b/server/console.c index 4dbdc37500c..a907227e46e 100644 --- a/server/console.c +++ b/server/console.c @@ -199,7 +199,7 @@ static struct console_input_events *create_console_input_events(void) { struct console_input_events* evt; - if (!(evt = alloc_object( &console_input_events_ops, -1 ))) return NULL; + if (!(evt = alloc_object( &console_input_events_ops ))) return NULL; evt->num_alloc = evt->num_used = 0; evt->events = NULL; return evt; @@ -209,7 +209,7 @@ static struct object *create_console_input( struct thread* renderer ) { struct console_input *console_input; - if (!(console_input = alloc_object( &console_input_ops, -1 ))) return NULL; + if (!(console_input = alloc_object( &console_input_ops ))) return NULL; console_input->renderer = renderer; console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; @@ -239,7 +239,7 @@ static struct screen_buffer *create_console_output( struct console_input *consol struct console_renderer_event evt; int i; - if (!(screen_buffer = alloc_object( &screen_buffer_ops, -1 ))) return NULL; + if (!(screen_buffer = alloc_object( &screen_buffer_ops ))) return NULL; screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; screen_buffer->input = console_input; screen_buffer->cursor_size = 100; diff --git a/server/debugger.c b/server/debugger.c index 200c6923657..fdd74616e33 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -374,7 +374,7 @@ static struct debug_event *alloc_debug_event( struct thread *thread, int code, assert( debugger->process != thread->process ); /* build the event */ - if (!(event = alloc_object( &debug_event_ops, -1 ))) return NULL; + if (!(event = alloc_object( &debug_event_ops ))) return NULL; event->next = NULL; event->prev = NULL; event->state = EVENT_QUEUED; @@ -537,7 +537,7 @@ int set_process_debugger( struct process *process, struct thread *debugger ) if (!debugger->debug_ctx) /* need to allocate a context */ { - if (!(debug_ctx = alloc_object( &debug_ctx_ops, -1 ))) return 0; + if (!(debug_ctx = alloc_object( &debug_ctx_ops ))) return 0; debug_ctx->event_head = NULL; debug_ctx->event_tail = NULL; debug_ctx->kill_on_exit = 1; diff --git a/server/device.c b/server/device.c index 7e06b994286..1a637124055 100644 --- a/server/device.c +++ b/server/device.c @@ -59,7 +59,7 @@ static const struct object_ops device_ops = static struct device *create_device( int id ) { struct device *dev; - if ((dev = alloc_object( &device_ops, -1 ))) + if ((dev = alloc_object( &device_ops ))) { dev->id = id; } diff --git a/server/fd.c b/server/fd.c index 6c2a49ac485..388c807e5f7 100644 --- a/server/fd.c +++ b/server/fd.c @@ -22,9 +22,15 @@ #include "config.h" #include +#include #include #include #include +#ifdef HAVE_SYS_POLL_H +#include +#endif +#include +#include #include #include "object.h" @@ -40,6 +46,7 @@ struct fd const struct fd_ops *fd_ops; /* file descriptor operations */ struct object *user; /* object using this file descriptor */ int unix_fd; /* unix file descriptor */ + int poll_index; /* index of fd in poll array */ int mode; /* file protection mode */ }; @@ -54,11 +61,259 @@ static const struct object_ops fd_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ - default_get_fd, /* get_fd */ + no_get_fd, /* get_fd */ fd_destroy /* destroy */ }; +/****************************************************************/ +/* timeouts support */ + +struct timeout_user +{ + struct timeout_user *next; /* next in sorted timeout list */ + struct timeout_user *prev; /* prev in sorted timeout list */ + struct timeval when; /* timeout expiry (absolute time) */ + timeout_callback callback; /* callback function */ + void *private; /* callback private data */ +}; + +static struct timeout_user *timeout_head; /* sorted timeouts list head */ +static struct timeout_user *timeout_tail; /* sorted timeouts list tail */ + +/* add a timeout user */ +struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private ) +{ + struct timeout_user *user; + struct timeout_user *pos; + + if (!(user = mem_alloc( sizeof(*user) ))) return NULL; + user->when = *when; + user->callback = func; + user->private = private; + + /* Now insert it in the linked list */ + + for (pos = timeout_head; pos; pos = pos->next) + if (!time_before( &pos->when, when )) break; + + if (pos) /* insert it before 'pos' */ + { + if ((user->prev = pos->prev)) user->prev->next = user; + else timeout_head = user; + user->next = pos; + pos->prev = user; + } + else /* insert it at the tail */ + { + user->next = NULL; + if (timeout_tail) timeout_tail->next = user; + else timeout_head = user; + user->prev = timeout_tail; + timeout_tail = user; + } + return user; +} + +/* remove a timeout user */ +void remove_timeout_user( struct timeout_user *user ) +{ + if (user->next) user->next->prev = user->prev; + else timeout_tail = user->prev; + if (user->prev) user->prev->next = user->next; + else timeout_head = user->next; + free( user ); +} + +/* add a timeout in milliseconds to an absolute time */ +void add_timeout( struct timeval *when, int timeout ) +{ + if (timeout) + { + long sec = timeout / 1000; + if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000) + { + when->tv_usec -= 1000000; + when->tv_sec++; + } + when->tv_sec += sec; + } +} + +/* handle the next expired timeout */ +inline static void handle_timeout(void) +{ + struct timeout_user *user = timeout_head; + timeout_head = user->next; + if (user->next) user->next->prev = user->prev; + else timeout_tail = user->prev; + user->callback( user->private ); + free( user ); +} + + +/****************************************************************/ +/* poll support */ + +static struct fd **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 fd **freelist; /* list of free entries in the array */ + +/* add a user in the poll array and return its index, or -1 on failure */ +static int add_poll_user( struct fd *fd ) +{ + int ret; + if (freelist) + { + ret = freelist - poll_users; + freelist = (struct fd **)poll_users[ret]; + } + else + { + if (nb_users == allocated_users) + { + struct fd **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; + if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) ))) + { + if (allocated_users) + poll_users = newusers; + else + free( newusers ); + return -1; + } + poll_users = newusers; + pollfd = newpoll; + allocated_users = new_count; + } + ret = nb_users++; + } + pollfd[ret].fd = -1; + pollfd[ret].events = 0; + pollfd[ret].revents = 0; + poll_users[ret] = fd; + active_users++; + return ret; +} + +/* remove a user from the poll list */ +static void remove_poll_user( struct fd *fd, int user ) +{ + assert( user >= 0 ); + assert( poll_users[user] == fd ); + pollfd[user].fd = -1; + pollfd[user].events = 0; + pollfd[user].revents = 0; + poll_users[user] = (struct fd *)freelist; + freelist = &poll_users[user]; + active_users--; +} + + +/* SIGHUP handler */ +static void sighup_handler() +{ +#ifdef DEBUG_OBJECTS + dump_objects(); +#endif +} + +/* SIGTERM handler */ +static void sigterm_handler() +{ + flush_registry(); + exit(1); +} + +/* SIGINT handler */ +static void sigint_handler() +{ + kill_all_processes( NULL, 1 ); + flush_registry(); + exit(1); +} + +/* server main poll() loop */ +void main_loop(void) +{ + int ret; + sigset_t sigset; + struct sigaction action; + + /* block the signals we use */ + sigemptyset( &sigset ); + sigaddset( &sigset, SIGCHLD ); + sigaddset( &sigset, SIGHUP ); + sigaddset( &sigset, SIGINT ); + sigaddset( &sigset, SIGQUIT ); + sigaddset( &sigset, SIGTERM ); + sigprocmask( SIG_BLOCK, &sigset, NULL ); + + /* set the handlers */ + action.sa_mask = sigset; + action.sa_flags = 0; + action.sa_handler = sigchld_handler; + sigaction( SIGCHLD, &action, NULL ); + action.sa_handler = sighup_handler; + sigaction( SIGHUP, &action, NULL ); + action.sa_handler = sigint_handler; + sigaction( SIGINT, &action, NULL ); + action.sa_handler = sigterm_handler; + sigaction( SIGQUIT, &action, NULL ); + sigaction( SIGTERM, &action, NULL ); + + while (active_users) + { + long diff = -1; + if (timeout_head) + { + struct timeval now; + gettimeofday( &now, NULL ); + while (timeout_head) + { + if (!time_before( &now, &timeout_head->when )) handle_timeout(); + else + { + diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000 + + (timeout_head->when.tv_usec - now.tv_usec) / 1000; + break; + } + } + if (!active_users) break; /* last user removed by a timeout */ + } + + sigprocmask( SIG_UNBLOCK, &sigset, NULL ); + + /* Note: we assume that the signal handlers do not manipulate the pollfd array + * or the timeout list, otherwise there is a race here. + */ + ret = poll( pollfd, nb_users, diff ); + + sigprocmask( SIG_BLOCK, &sigset, NULL ); + + if (ret > 0) + { + int i; + for (i = 0; i < nb_users; i++) + { + if (pollfd[i].revents) + { + fd_poll_event( poll_users[i], pollfd[i].revents ); + if (!--ret) break; + } + } + } + } +} + +/****************************************************************/ +/* file descriptor functions */ + static void fd_dump( struct object *obj, int verbose ) { struct fd *fd = (struct fd *)obj; @@ -67,32 +322,53 @@ static void fd_dump( struct object *obj, int verbose ) static void fd_destroy( struct object *obj ) { -#if 0 struct fd *fd = (struct fd *)obj; + + if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index ); close( fd->unix_fd ); -#endif } -/* allocate an object that has an associated fd */ -void *alloc_fd_object( const struct object_ops *ops, - const struct fd_ops *fd_user_ops, int unix_fd ) +/* set the events that select waits for on this fd */ +void set_fd_events( struct fd *fd, int events ) { - struct object *user; - struct fd *fd = alloc_object( &fd_ops, -1 ); + int user = fd->poll_index; + assert( poll_users[user] == fd ); + if (events == -1) /* stop waiting on this fd completely */ + { + pollfd[user].fd = -1; + pollfd[user].events = POLLERR; + pollfd[user].revents = 0; + } + else if (pollfd[user].fd != -1 || !pollfd[user].events) + { + pollfd[user].fd = fd->unix_fd; + pollfd[user].events = events; + } +} - if (!fd) return NULL; - if (!(user = alloc_object( ops, unix_fd ))) +/* allocate an fd object */ +/* if the function fails the unix fd is closed */ +struct fd *alloc_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user ) +{ + struct fd *fd = alloc_object( &fd_ops ); + + if (!fd) + { + close( unix_fd ); + return NULL; + } + fd->fd_ops = fd_user_ops; + fd->user = user; + fd->unix_fd = unix_fd; + fd->poll_index = -1; + fd->mode = 0; + + if ((unix_fd != -1) && ((fd->poll_index = add_poll_user( fd )) == -1)) { release_object( fd ); return NULL; } - fd->fd_ops = fd_user_ops; - fd->user = user; - fd->unix_fd = unix_fd; - fd->mode = 0; - - user->fd_obj = fd; - return user; + return fd; } /* retrieve the object that is using an fd */ @@ -104,26 +380,12 @@ void *get_fd_user( struct fd *fd ) /* retrieve the unix fd for an object */ int get_unix_fd( struct fd *fd ) { - if (fd) return fd->unix_fd; - return -1; -} - -/* set the unix fd for an object; can only be done once */ -void set_unix_fd( struct object *obj, int unix_fd ) -{ - struct fd *fd = obj->fd_obj; - - assert( fd ); - assert( fd->unix_fd == -1 ); - - fd->unix_fd = unix_fd; - obj->fd = unix_fd; + return fd->unix_fd; } /* callback for event happening in the main poll() loop */ -void fd_poll_event( struct object *obj, int event ) +void fd_poll_event( struct fd *fd, int event ) { - struct fd *fd = obj->fd_obj; return fd->fd_ops->poll_event( fd, event ); } @@ -141,46 +403,50 @@ int check_fd_events( struct fd *fd, int events ) /* default add_queue() routine for objects that poll() on an fd */ int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry ) { - struct fd *fd = obj->fd_obj; + struct fd *fd = get_obj_fd( obj ); + if (!fd) return 0; if (!obj->head) /* first on the queue */ - set_select_events( obj, fd->fd_ops->get_poll_events( fd ) ); + set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) ); add_queue( obj, entry ); + release_object( fd ); return 1; } /* default remove_queue() routine for objects that poll() on an fd */ void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry ) { + struct fd *fd = get_obj_fd( obj ); + grab_object( obj ); remove_queue( obj, entry ); if (!obj->head) /* last on the queue is gone */ - set_select_events( obj, 0 ); + set_fd_events( fd, 0 ); release_object( obj ); + release_object( fd ); } /* default signaled() routine for objects that poll() on an fd */ int default_fd_signaled( struct object *obj, struct thread *thread ) { - struct fd *fd = obj->fd_obj; + struct fd *fd = get_obj_fd( obj ); int events = fd->fd_ops->get_poll_events( fd ); + int ret = check_fd_events( fd, events ) != 0; - if (check_fd_events( 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; + if (ret) + set_fd_events( fd, 0 ); /* stop waiting on select() if we are signaled */ + else if (obj->head) + set_fd_events( fd, events ); /* restart waiting on poll() if we are no longer signaled */ + + release_object( fd ); + return ret; } /* default handler for poll() events */ void default_poll_event( struct fd *fd, int event ) { /* an error occurred, stop polling this fd to avoid busy-looping */ - if (event & (POLLERR | POLLHUP)) set_select_events( fd->user, -1 ); + if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); wake_up( fd->user, 0 ); } @@ -214,8 +480,7 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl if ((obj = get_handle_obj( process, handle, access, NULL ))) { - if (obj->fd_obj) fd = (struct fd *)grab_object( obj->fd_obj ); - else set_error( STATUS_OBJECT_TYPE_MISMATCH ); + if (!(fd = get_obj_fd( obj ))) set_error( STATUS_OBJECT_TYPE_MISMATCH ); release_object( obj ); } return fd; diff --git a/server/file.c b/server/file.c index 7518a09a8c1..2544bbaf019 100644 --- a/server/file.c +++ b/server/file.c @@ -51,6 +51,7 @@ struct file { struct object obj; /* object header */ + struct fd *fd; /* file descriptor for this file */ struct file *next; /* next file in hashing list */ char *name; /* file name */ unsigned int access; /* file access (GENERIC_READ/WRITE) */ @@ -66,6 +67,7 @@ struct file static struct file *file_hash[NAME_HASH_SIZE]; static void file_dump( struct object *obj, int verbose ); +static struct fd *file_get_fd( struct object *obj ); static void file_destroy( struct object *obj ); static int file_get_poll_events( struct fd *fd ); @@ -82,7 +84,7 @@ static const struct object_ops file_ops = default_fd_remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ - default_get_fd, /* get_fd */ + file_get_fd, /* get_fd */ file_destroy /* destroy */ }; @@ -134,7 +136,7 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in { struct file *file; - if ((file = alloc_fd_object( &file_ops, &file_fd_ops, fd ))) + if ((file = alloc_object( &file_ops ))) { file->name = NULL; file->next = NULL; @@ -147,6 +149,11 @@ static struct file *create_file_for_fd( int fd, unsigned int access, unsigned in init_async_queue (&file->read_q); init_async_queue (&file->write_q); } + if (!(file->fd = alloc_fd( &file_fd_ops, fd, &file->obj ))) + { + release_object( file ); + return NULL; + } } return file; } @@ -264,7 +271,7 @@ static void file_dump( struct object *obj, int verbose ) { struct file *file = (struct file *)obj; assert( obj->ops == &file_ops ); - fprintf( stderr, "File fd=%p flags=%08x name='%s'\n", file->obj.fd_obj, file->flags, file->name ); + fprintf( stderr, "File fd=%p flags=%08x name='%s'\n", file->fd, file->flags, file->name ); } static int file_get_poll_events( struct fd *fd ) @@ -395,7 +402,14 @@ static void file_queue_async(struct fd *fd, void *ptr, unsigned int status, int else if ( async ) destroy_async ( async ); else set_error ( STATUS_INVALID_PARAMETER ); - set_select_events( &file->obj, file_get_poll_events( fd )); + set_fd_events( fd, file_get_poll_events( fd )); +} + +static struct fd *file_get_fd( struct object *obj ) +{ + struct file *file = (struct file *)obj; + assert( obj->ops == &file_ops ); + return (struct fd *)grab_object( file->fd ); } static void file_destroy( struct object *obj ) @@ -418,6 +432,7 @@ static void file_destroy( struct object *obj ) destroy_async_queue (&file->read_q); destroy_async_queue (&file->write_q); } + if (file->fd) release_object( file->fd ); } /* set the last error depending on errno */ @@ -453,7 +468,7 @@ struct file *get_file_obj( struct process *process, obj_handle_t handle, unsigne int get_file_unix_fd( struct file *file ) { - return get_unix_fd( file->obj.fd_obj ); + return get_unix_fd( file->fd ); } static int set_file_pointer( obj_handle_t handle, unsigned int *low, int *high, int whence ) diff --git a/server/file.h b/server/file.h index 351c62e0c6d..55fc3a46e0f 100644 --- a/server/file.h +++ b/server/file.h @@ -42,13 +42,12 @@ struct fd_ops /* file descriptor functions */ -extern void *alloc_fd_object( const struct object_ops *ops, - const struct fd_ops *fd_user_ops, int unix_fd ); +extern struct fd *alloc_fd( const struct fd_ops *fd_ops, int unix_fd, struct object *user ); extern void *get_fd_user( struct fd *fd ); extern int get_unix_fd( struct fd *fd ); -extern void set_unix_fd( struct object *obj, int unix_fd ); -extern void fd_poll_event( struct object *obj, int event ); +extern void fd_poll_event( struct fd *fd, int event ); extern int check_fd_events( struct fd *fd, int events ); +extern void set_fd_events( struct fd *fd, int events ); extern int default_fd_add_queue( struct object *obj, struct wait_queue_entry *entry ); extern void default_fd_remove_queue( struct object *obj, struct wait_queue_entry *entry ); @@ -57,9 +56,27 @@ extern void default_poll_event( struct fd *fd, int event ); extern int no_flush( struct fd *fd ); extern int no_get_file_info( struct fd *fd, struct get_file_info_reply *info, int *flags ); extern void no_queue_async( struct fd *fd, void* ptr, unsigned int status, int type, int count ); +extern void main_loop(void); inline static struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); } +/* timeout functions */ + +struct timeout_user; + +typedef void (*timeout_callback)( void *private ); + +extern struct timeout_user *add_timeout_user( struct timeval *when, + timeout_callback func, void *private ); +extern void remove_timeout_user( struct timeout_user *user ); +extern void add_timeout( struct timeval *when, int timeout ); +/* return 1 if t1 is before t2 */ +static inline int time_before( struct timeval *t1, struct timeval *t2 ) +{ + return ((t1->tv_sec < t2->tv_sec) || + ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec))); +} + /* file functions */ extern struct file *get_file_obj( struct process *process, obj_handle_t handle, diff --git a/server/handle.c b/server/handle.c index 6fa8f713da5..4a2b4ef57eb 100644 --- a/server/handle.c +++ b/server/handle.c @@ -154,7 +154,7 @@ struct handle_table *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, -1 ))) + if (!(table = alloc_object( &handle_table_ops ))) return NULL; table->process = process; table->count = count; diff --git a/server/hook.c b/server/hook.c index b69b1ccdcf0..83b540b99f2 100644 --- a/server/hook.c +++ b/server/hook.c @@ -79,7 +79,7 @@ static struct hook_table *alloc_hook_table(void) struct hook_table *table; int i; - if ((table = alloc_object( &hook_table_ops, -1 ))) + if ((table = alloc_object( &hook_table_ops ))) { for (i = 0; i < NB_HOOKS; i++) { diff --git a/server/main.c b/server/main.c index 032cb65c811..0089c3526d4 100644 --- a/server/main.c +++ b/server/main.c @@ -28,6 +28,7 @@ #include #include "object.h" +#include "file.h" #include "thread.h" #include "request.h" @@ -126,7 +127,7 @@ int main( int argc, char *argv[] ) if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); init_registry(); - select_loop(); + main_loop(); #ifdef DEBUG_OBJECTS dump_objects(); /* dump any remaining objects */ diff --git a/server/mapping.c b/server/mapping.c index 4c3903456d4..26180d4bddb 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -50,6 +50,7 @@ struct mapping }; static void mapping_dump( struct object *obj, int verbose ); +static struct fd *mapping_get_fd( struct object *obj ); static void mapping_destroy( struct object *obj ); static const struct object_ops mapping_ops = @@ -60,7 +61,7 @@ static const struct object_ops mapping_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* satisfied */ - default_get_fd, /* get_fd */ + mapping_get_fd, /* get_fd */ mapping_destroy /* destroy */ }; @@ -190,8 +191,7 @@ static int get_image_params( struct mapping *mapping ) /* load the headers */ - if (!(fd = get_obj_fd( (struct object *)mapping->file ))) return 0; - mapping->obj.fd_obj = fd; + if (!(fd = mapping_get_fd( &mapping->obj ))) return 0; unix_fd = get_unix_fd( fd ); filepos = lseek( unix_fd, 0, SEEK_SET ); if (read( unix_fd, &dos, sizeof(dos) ) != sizeof(dos)) goto error; @@ -231,11 +231,13 @@ static int get_image_params( struct mapping *mapping ) lseek( unix_fd, filepos, SEEK_SET ); free( sec ); + release_object( fd ); return 1; error: lseek( unix_fd, filepos, SEEK_SET ); if (sec) free( sec ); + release_object( fd ); set_error( STATUS_INVALID_FILE_FOR_SECTION ); return 0; } @@ -301,7 +303,6 @@ static struct object *create_mapping( int size_high, int size_low, int protect, if (!(mapping->file = create_temp_file( access ))) goto error; if (!grow_file( mapping->file, size_high, size_low )) goto error; } - mapping->obj.fd_obj = get_obj_fd( (struct object *)mapping->file ); mapping->size_high = size_high; mapping->size_low = ROUND_SIZE( 0, size_low ); mapping->protect = protect; @@ -324,6 +325,12 @@ static void mapping_dump( struct object *obj, int verbose ) fputc( '\n', stderr ); } +static struct fd *mapping_get_fd( struct object *obj ) +{ + struct mapping *mapping = (struct mapping *)obj; + return get_obj_fd( (struct object *)mapping->file ); +} + static void mapping_destroy( struct object *obj ) { struct mapping *mapping = (struct mapping *)obj; diff --git a/server/named_pipe.c b/server/named_pipe.c index 29c76143771..b1e2e66d772 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -61,6 +61,7 @@ struct named_pipe; struct pipe_user { struct object obj; + struct fd *fd; enum pipe_state state; struct pipe_user *other; struct named_pipe *pipe; @@ -98,7 +99,10 @@ static const struct object_ops named_pipe_ops = }; static void pipe_user_dump( struct object *obj, int verbose ); +static struct fd *pipe_user_get_fd( struct object *obj ); static void pipe_user_destroy( struct object *obj); + +static int pipe_user_get_poll_events( struct fd *fd ); static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ); static const struct object_ops pipe_user_ops = @@ -109,13 +113,13 @@ static const struct object_ops pipe_user_ops = default_fd_remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ - default_get_fd, /* get_fd */ + pipe_user_get_fd, /* get_fd */ pipe_user_destroy /* destroy */ }; static const struct fd_ops pipe_user_fd_ops = { - NULL, /* get_poll_events */ + pipe_user_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ no_flush, /* flush */ pipe_user_get_info, /* get_file_info */ @@ -156,6 +160,12 @@ static void notify_waiter( struct pipe_user *user, unsigned int status) user->overlapped=NULL; } +static struct fd *pipe_user_get_fd( struct object *obj ) +{ + struct pipe_user *user = (struct pipe_user *)obj; + return (struct fd *)grab_object( user->fd ); +} + static void pipe_user_destroy( struct object *obj) { struct pipe_user *user = (struct pipe_user *)obj; @@ -167,8 +177,8 @@ static void pipe_user_destroy( struct object *obj) if(user->other) { - release_object( user->other->obj.fd_obj ); - user->other->obj.fd_obj = NULL; + release_object( user->other->fd ); + user->other->fd = NULL; switch(user->other->state) { case ps_connected_server: @@ -191,6 +201,12 @@ static void pipe_user_destroy( struct object *obj) else user->pipe->users = user->next; if (user->thread) release_object(user->thread); release_object(user->pipe); + if (user->fd) release_object( user->fd ); +} + +static int pipe_user_get_poll_events( struct fd *fd ) +{ + return POLLIN | POLLOUT; /* FIXME */ } static int pipe_user_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ) @@ -227,20 +243,36 @@ static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len ) return pipe; } +static struct named_pipe *open_named_pipe( const WCHAR *name, size_t len ) +{ + struct object *obj; + + if ((obj = find_object( sync_namespace, name, len ))) + { + if (obj->ops == &named_pipe_ops) return (struct named_pipe *)obj; + release_object( obj ); + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + } + else set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + + return NULL; +} + static struct pipe_user *get_pipe_user_obj( struct process *process, obj_handle_t handle, unsigned int access ) { return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops ); } -static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd ) +static struct pipe_user *create_pipe_user( struct named_pipe *pipe ) { struct pipe_user *user; - user = alloc_fd_object( &pipe_user_ops, &pipe_user_fd_ops, fd ); + user = alloc_object( &pipe_user_ops ); if(!user) return NULL; + user->fd = NULL; user->pipe = pipe; user->state = ps_none; user->other = NULL; @@ -293,7 +325,7 @@ DECL_HANDLER(create_named_pipe) pipe->pipemode = req->pipemode; } - user = create_pipe_user (pipe, -1); + user = create_pipe_user( pipe ); if(user) { @@ -307,54 +339,46 @@ DECL_HANDLER(create_named_pipe) DECL_HANDLER(open_named_pipe) { + struct pipe_user *user, *partner; struct named_pipe *pipe; reply->handle = 0; - pipe = create_named_pipe( get_req_data(), get_req_data_size() ); - if(!pipe) + + if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() ))) + { + set_error( STATUS_NO_SUCH_FILE ); return; - - if (get_error() == STATUS_OBJECT_NAME_COLLISION) + } + if (!(partner = find_partner(pipe, ps_wait_open))) { - struct pipe_user *partner; + release_object(pipe); + set_error( STATUS_PIPE_NOT_AVAILABLE ); + return; + } + if ((user = create_pipe_user( pipe ))) + { + int fds[2]; - if ((partner = find_partner(pipe, ps_wait_open))) + if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) { - int fds[2]; - - if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) + user->fd = alloc_fd( &pipe_user_fd_ops, fds[1], &user->obj ); + partner->fd = alloc_fd( &pipe_user_fd_ops, fds[0], &partner->obj ); + if (user->fd && partner->fd) { - struct pipe_user *user; - - if( (user = create_pipe_user (pipe, fds[1])) ) - { - set_unix_fd( &partner->obj, fds[0] ); - notify_waiter(partner,STATUS_SUCCESS); - partner->state = ps_connected_server; - partner->other = user; - user->state = ps_connected_client; - user->other = partner; - reply->handle = alloc_handle( current->process, user, req->access, 0 ); - release_object(user); - } - else - { - close(fds[0]); - } + notify_waiter(partner,STATUS_SUCCESS); + partner->state = ps_connected_server; + partner->other = user; + user->state = ps_connected_client; + user->other = partner; + reply->handle = alloc_handle( current->process, user, req->access, 0 ); } - release_object( partner ); } - else - { - set_error(STATUS_PIPE_NOT_AVAILABLE); - } - } - else - { - set_error(STATUS_NO_SUCH_FILE); - } + else file_set_error(); - release_object(pipe); + release_object( user ); + } + release_object( partner ); + release_object( pipe ); } DECL_HANDLER(connect_named_pipe) @@ -381,7 +405,6 @@ DECL_HANDLER(connect_named_pipe) { notify_waiter(partner,STATUS_SUCCESS); release_object(partner); - release_object(partner); } } @@ -391,44 +414,35 @@ DECL_HANDLER(connect_named_pipe) DECL_HANDLER(wait_named_pipe) { struct named_pipe *pipe; + struct pipe_user *partner; - pipe = create_named_pipe( get_req_data(), get_req_data_size() ); - if( pipe ) + if (!(pipe = open_named_pipe( get_req_data(), get_req_data_size() ))) { - /* only wait if the pipe already exists */ - if(get_error() == STATUS_OBJECT_NAME_COLLISION) - { - struct pipe_user *partner; - - set_error(STATUS_SUCCESS); - if( (partner = find_partner(pipe,ps_wait_open)) ) - { - /* this should use notify_waiter, - but no pipe_user object exists now... */ - thread_queue_apc(current,NULL,req->func, - APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS); - release_object(partner); - } - else - { - struct pipe_user *user; - - if( (user = create_pipe_user (pipe, -1)) ) - { - user->state = ps_wait_connect; - user->thread = (struct thread *)grab_object(current); - user->func = req->func; - user->overlapped = req->overlapped; - /* don't release it */ - } - } - } - else - { - set_error(STATUS_PIPE_NOT_AVAILABLE); - } - release_object(pipe); + set_error( STATUS_PIPE_NOT_AVAILABLE ); + return; } + if( (partner = find_partner(pipe,ps_wait_open)) ) + { + /* this should use notify_waiter, + but no pipe_user object exists now... */ + thread_queue_apc(current,NULL,req->func, + APC_ASYNC,1,2,req->overlapped,STATUS_SUCCESS); + release_object(partner); + } + else + { + struct pipe_user *user; + + if( (user = create_pipe_user( pipe )) ) + { + user->state = ps_wait_connect; + user->thread = (struct thread *)grab_object(current); + user->func = req->func; + user->overlapped = req->overlapped; + /* don't release it */ + } + } + release_object(pipe); } DECL_HANDLER(disconnect_named_pipe) @@ -441,13 +455,13 @@ DECL_HANDLER(disconnect_named_pipe) if( (user->state == ps_connected_server) && (user->other->state == ps_connected_client) ) { - release_object( user->other->obj.fd_obj ); - user->other->obj.fd_obj = NULL; + release_object( user->other->fd ); + user->other->fd = NULL; user->other->state = ps_disconnected; user->other->other = NULL; - release_object( user->obj.fd_obj ); - user->obj.fd_obj = NULL; + release_object( user->fd ); + user->fd = NULL; user->state = ps_idle_server; user->other = NULL; } diff --git a/server/object.c b/server/object.c index 20fa2324219..8ad76fcb196 100644 --- a/server/object.c +++ b/server/object.c @@ -131,32 +131,21 @@ static void set_object_name( struct namespace *namespace, } /* allocate and initialize an object */ -/* if the function fails the fd is closed */ -void *alloc_object( const struct object_ops *ops, int fd ) +void *alloc_object( const struct object_ops *ops ) { struct object *obj = mem_alloc( ops->size ); if (obj) { obj->refcount = 1; - obj->fd_obj = NULL; - 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 list_add_head( &object_list, &obj->obj_list ); #endif return obj; } - if (fd != -1) close( fd ); return NULL; } @@ -166,7 +155,7 @@ void *create_named_object( struct namespace *namespace, const struct object_ops struct object *obj; struct object_name *name_ptr; - if (!name || !len) return alloc_object( ops, -1 ); + if (!name || !len) return alloc_object( ops ); if ((obj = find_object( namespace, name, len ))) { @@ -179,7 +168,7 @@ void *create_named_object( struct namespace *namespace, const struct object_ops return NULL; } if (!(name_ptr = alloc_name( name, len ))) return NULL; - if ((obj = alloc_object( ops, -1 ))) + if ((obj = alloc_object( ops ))) { set_object_name( namespace, obj, name_ptr ); clear_error(); @@ -220,10 +209,7 @@ void release_object( void *ptr ) assert( !obj->head ); assert( !obj->tail ); obj->ops->destroy( obj ); - if (obj->fd_obj) release_object( obj->fd_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 list_remove( &obj->obj_list ); memset( obj, 0xaa, obj->ops->size ); @@ -296,13 +282,6 @@ struct fd *no_get_fd( struct object *obj ) return NULL; } -struct fd *default_get_fd( struct object *obj ) -{ - if (obj->fd_obj) return (struct fd *)grab_object( obj->fd_obj ); - set_error( STATUS_OBJECT_TYPE_MISMATCH ); - return NULL; -} - void no_destroy( struct object *obj ) { } diff --git a/server/object.h b/server/object.h index 54d082f564a..c72b873cef6 100644 --- a/server/object.h +++ b/server/object.h @@ -67,9 +67,6 @@ struct object_ops struct object { unsigned int refcount; /* reference count */ - struct fd *fd_obj; /* file descriptor */ - int fd; /* file descriptor */ - int select; /* select() user id */ const struct object_ops *ops; struct wait_queue_entry *head; struct wait_queue_entry *tail; @@ -89,7 +86,7 @@ struct wait_queue_entry 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, int fd ); +extern void *alloc_object( const struct object_ops *ops ); extern void dump_object_name( struct object *obj ); extern void *create_named_object( struct namespace *namespace, const struct object_ops *ops, const WCHAR *name, size_t len ); @@ -102,37 +99,11 @@ extern struct object *find_object( const struct namespace *namespace, const WCHA extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry ); extern int no_satisfied( struct object *obj, struct thread *thread ); extern struct fd *no_get_fd( struct object *obj ); -extern struct fd *default_get_fd( struct object *obj ); extern void no_destroy( struct object *obj ); #ifdef DEBUG_OBJECTS extern void dump_objects(void); #endif -/* select functions */ - -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, int events ); -extern void set_select_events( struct object *obj, int events ); -extern void select_loop(void); - -/* timeout functions */ - -struct timeout_user; - -typedef void (*timeout_callback)( void *private ); - -extern struct timeout_user *add_timeout_user( struct timeval *when, - timeout_callback func, void *private ); -extern void remove_timeout_user( struct timeout_user *user ); -extern void add_timeout( struct timeval *when, int timeout ); -/* return 1 if t1 is before t2 */ -static inline int time_before( struct timeval *t1, struct timeval *t2 ) -{ - return ((t1->tv_sec < t2->tv_sec) || - ((t1->tv_sec == t2->tv_sec) && (t1->tv_usec < t2->tv_usec))); -} - /* event functions */ struct event; diff --git a/server/pipe.c b/server/pipe.c index 79074e57886..3e01ee9ae2b 100644 --- a/server/pipe.c +++ b/server/pipe.c @@ -42,6 +42,7 @@ enum side { READ_SIDE, WRITE_SIDE }; struct pipe { struct object obj; /* object header */ + struct fd *fd; /* pipe file descriptor */ struct pipe *other; /* the pipe other end */ enum side side; /* which side of the pipe is this */ }; @@ -79,11 +80,16 @@ static struct pipe *create_pipe_side( int fd, int side ) { struct pipe *pipe; - if ((pipe = alloc_fd_object( &pipe_ops, &pipe_fd_ops, fd ))) + if ((pipe = alloc_object( &pipe_ops ))) { pipe->other = NULL; pipe->side = side; } + if (!(pipe->fd = alloc_fd( &pipe_fd_ops, fd, &pipe->obj ))) + { + release_object( pipe ); + return NULL; + } return pipe; } @@ -119,7 +125,7 @@ static void pipe_dump( struct object *obj, int verbose ) struct pipe *pipe = (struct pipe *)obj; assert( obj->ops == &pipe_ops ); fprintf( stderr, "Pipe %s-side fd=%p\n", - (pipe->side == READ_SIDE) ? "read" : "write", pipe->obj.fd_obj ); + (pipe->side == READ_SIDE) ? "read" : "write", pipe->fd ); } static int pipe_get_poll_events( struct fd *fd ) @@ -139,7 +145,7 @@ static struct fd *pipe_get_fd( struct object *obj ) set_error( STATUS_PIPE_BROKEN ); return NULL; } - return (struct fd *)grab_object( pipe->obj.fd_obj ); + return (struct fd *)grab_object( pipe->fd ); } static int pipe_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ) @@ -167,6 +173,7 @@ static void pipe_destroy( struct object *obj ) assert( obj->ops == &pipe_ops ); if (pipe->other) pipe->other->other = NULL; + if (pipe->fd) release_object( pipe->fd ); } /* create an anonymous pipe */ diff --git a/server/process.c b/server/process.c index 5d808dcb807..d616d42cab2 100644 --- a/server/process.c +++ b/server/process.c @@ -263,13 +263,14 @@ struct thread *create_process( int fd ) struct thread *thread = NULL; int request_pipe[2]; - if (!(process = alloc_fd_object( &process_ops, &process_fd_ops, fd ))) goto error; + if (!(process = alloc_object( &process_ops ))) goto error; process->next = NULL; process->prev = NULL; process->parent = NULL; process->thread_list = NULL; process->debugger = NULL; process->handles = NULL; + process->msg_fd = NULL; process->exit_code = STILL_ACTIVE; process->running_threads = 0; process->priority = NORMAL_PRIORITY_CLASS; @@ -297,6 +298,7 @@ struct thread *create_process( int fd ) first_process = process; if (!(process->id = alloc_ptid( process ))) goto error; + if (!(process->msg_fd = alloc_fd( &process_fd_ops, fd, &process->obj ))) goto error; /* create the main thread */ if (pipe( request_pipe ) == -1) @@ -313,7 +315,7 @@ struct thread *create_process( int fd ) close( request_pipe[1] ); if (!(thread = create_thread( request_pipe[0], process ))) goto error; - set_select_events( &process->obj, POLLIN ); /* start listening to events */ + set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */ release_object( process ); return thread; @@ -404,6 +406,7 @@ static void process_destroy( struct object *obj ) set_process_startup_state( process, STARTUP_ABORTED ); if (process->console) release_object( process->console ); if (process->parent) release_object( process->parent ); + if (process->msg_fd) release_object( process->msg_fd ); if (process->next) process->next->prev = process->prev; if (process->prev) process->prev->next = process->next; else first_process = process->next; @@ -431,13 +434,12 @@ static int process_signaled( struct object *obj, struct thread *thread ) return !process->running_threads; } - static void process_poll_event( struct fd *fd, int event ) { struct process *process = get_fd_user( fd ); assert( process->obj.ops == &process_ops ); - if (event & (POLLERR | POLLHUP)) set_select_events( &process->obj, -1 ); + if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); else if (event & POLLIN) receive_fd( process ); } @@ -883,7 +885,7 @@ DECL_HANDLER(new_process) } /* build the startup info for a new process */ - if (!(info = alloc_object( &startup_info_ops, -1 ))) return; + if (!(info = alloc_object( &startup_info_ops ))) return; info->inherit_all = req->inherit_all; info->use_handles = req->use_handles; info->create_flags = req->create_flags; diff --git a/server/process.h b/server/process.h index 55bda89bbab..cd65153e0ae 100644 --- a/server/process.h +++ b/server/process.h @@ -56,6 +56,7 @@ struct process struct thread *thread_list; /* head of the thread list */ struct thread *debugger; /* thread debugging this process */ struct handle_table *handles; /* handle entries */ + struct fd *msg_fd; /* fd for sendmsg/recvmsg */ process_id_t id; /* id of the process */ process_id_t group_id; /* group id of the process */ int exit_code; /* process exit code */ diff --git a/server/queue.c b/server/queue.c index 32caefec244..48edb235224 100644 --- a/server/queue.c +++ b/server/queue.c @@ -30,6 +30,7 @@ #include "winuser.h" #include "handle.h" +#include "file.h" #include "thread.h" #include "process.h" #include "request.h" @@ -181,7 +182,7 @@ static struct thread_input *create_thread_input(void) { struct thread_input *input; - if ((input = alloc_object( &thread_input_ops, -1 ))) + if ((input = alloc_object( &thread_input_ops ))) { input->focus = 0; input->capture = 0; @@ -204,7 +205,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ int i; if (!input && !(input = create_thread_input())) return NULL; - if ((queue = alloc_object( &msg_queue_ops, -1 ))) + if ((queue = alloc_object( &msg_queue_ops ))) { queue->wake_bits = 0; queue->wake_mask = 0; diff --git a/server/registry.c b/server/registry.c index 2262f5925ef..b7663082d08 100644 --- a/server/registry.c +++ b/server/registry.c @@ -434,7 +434,7 @@ static WCHAR *req_strdupW( const void *req, const WCHAR *str, size_t len ) static struct key *alloc_key( const WCHAR *name, time_t modif ) { struct key *key; - if ((key = (struct key *)alloc_object( &key_ops, -1 ))) + if ((key = alloc_object( &key_ops ))) { key->class = NULL; key->flags = 0; diff --git a/server/request.c b/server/request.c index d13c761b7b6..a47827bd4d4 100644 --- a/server/request.c +++ b/server/request.c @@ -73,11 +73,13 @@ static const char * const server_lock_name = "lock"; /* name of the server struct master_socket { - struct object obj; /* object header */ + struct object obj; /* object header */ + struct fd *fd; /* file descriptor of the master socket */ struct timeout_user *timeout; /* timeout on last process exit */ }; static void master_socket_dump( struct object *obj, int verbose ); +static void master_socket_destroy( struct object *obj ); static void master_socket_poll_event( struct fd *fd, int event ); static const struct object_ops master_socket_ops = @@ -89,7 +91,7 @@ static const struct object_ops master_socket_ops = NULL, /* signaled */ NULL, /* satisfied */ no_get_fd, /* get_fd */ - no_destroy /* destroy */ + master_socket_destroy /* destroy */ }; static const struct fd_ops master_socket_fd_ops = @@ -188,7 +190,7 @@ void write_reply( struct thread *thread ) { int ret; - if ((ret = write( thread->reply_fd, + if ((ret = write( get_unix_fd( thread->reply_fd ), (char *)thread->reply_data + thread->reply_size - thread->reply_towrite, thread->reply_towrite )) >= 0) { @@ -197,7 +199,8 @@ void write_reply( struct thread *thread ) free( thread->reply_data ); thread->reply_data = NULL; /* sent everything, can go back to waiting for requests */ - change_select_fd( &thread->obj, thread->request_fd, POLLIN ); + set_fd_events( thread->request_fd, POLLIN ); + set_fd_events( thread->reply_fd, 0 ); } return; } @@ -214,7 +217,8 @@ static void send_reply( union generic_reply *reply ) if (!current->reply_size) { - if ((ret = write( current->reply_fd, reply, sizeof(*reply) )) != sizeof(*reply)) goto error; + if ((ret = write( get_unix_fd( current->reply_fd ), + reply, sizeof(*reply) )) != sizeof(*reply)) goto error; } else { @@ -225,12 +229,13 @@ static void send_reply( union generic_reply *reply ) vec[1].iov_base = current->reply_data; vec[1].iov_len = current->reply_size; - if ((ret = writev( current->reply_fd, vec, 2 )) < sizeof(*reply)) goto error; + if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error; if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply)))) { /* couldn't write it all, wait for POLLOUT */ - change_select_fd( ¤t->obj, current->reply_fd, POLLOUT ); + set_fd_events( current->reply_fd, POLLOUT ); + set_fd_events( current->request_fd, 0 ); return; } } @@ -286,7 +291,7 @@ void read_request( struct thread *thread ) if (!thread->req_toread) /* no pending request */ { - if ((ret = read( thread->obj.fd, &thread->req, + if ((ret = read( get_unix_fd( thread->request_fd ), &thread->req, sizeof(thread->req) )) != sizeof(thread->req)) goto error; if (!(thread->req_toread = thread->req.request_header.request_size)) { @@ -301,8 +306,9 @@ void read_request( struct thread *thread ) /* read the variable sized data */ for (;;) { - ret = read( thread->obj.fd, ((char *)thread->req_data + - thread->req.request_header.request_size - thread->req_toread), + ret = read( get_unix_fd( thread->request_fd ), + (char *)thread->req_data + thread->req.request_header.request_size + - thread->req_toread, thread->req_toread ); if (ret <= 0) break; if (!(thread->req_toread -= ret)) @@ -341,7 +347,7 @@ int receive_fd( struct process *process ) myiovec.iov_base = (void *)&data; myiovec.iov_len = sizeof(data); - ret = recvmsg( process->obj.fd, &msghdr, 0 ); + ret = recvmsg( get_unix_fd( process->msg_fd ), &msghdr, 0 ); #ifndef HAVE_MSGHDR_ACCRIGHTS fd = cmsg.fd; #endif @@ -411,7 +417,7 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) myiovec.iov_base = (void *)&handle; myiovec.iov_len = sizeof(handle); - ret = sendmsg( process->obj.fd, &msghdr, 0 ); + ret = sendmsg( get_unix_fd( process->msg_fd ), &msghdr, 0 ); if (ret == sizeof(handle)) return 0; @@ -445,7 +451,14 @@ static void master_socket_dump( struct object *obj, int verbose ) { struct master_socket *sock = (struct master_socket *)obj; assert( obj->ops == &master_socket_ops ); - fprintf( stderr, "Master socket fd=%p\n", sock->obj.fd_obj ); + fprintf( stderr, "Master socket fd=%p\n", sock->fd ); +} + +static void master_socket_destroy( struct object *obj ) +{ + struct master_socket *sock = (struct master_socket *)obj; + assert( obj->ops == &master_socket_ops ); + release_object( sock->fd ); } /* handle a socket event */ @@ -466,7 +479,7 @@ static void master_socket_poll_event( struct fd *fd, int event ) { struct sockaddr_un dummy; int len = sizeof(dummy); - int client = accept( master_socket->obj.fd, (struct sockaddr *) &dummy, &len ); + int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len ); if (client == -1) return; if (sock->timeout) { @@ -682,10 +695,11 @@ static void acquire_lock(void) chmod( server_socket_name, 0600 ); /* make sure no other user can connect */ if (listen( fd, 5 ) == -1) fatal_perror( "listen" ); - if (!(master_socket = alloc_fd_object( &master_socket_ops, &master_socket_fd_ops, fd ))) + if (!(master_socket = alloc_object( &master_socket_ops )) || + !(master_socket->fd = alloc_fd( &master_socket_fd_ops, fd, &master_socket->obj ))) fatal_error( "out of memory\n" ); master_socket->timeout = NULL; - set_select_events( &master_socket->obj, POLLIN ); + set_fd_events( master_socket->fd, POLLIN ); } /* open the master server socket and start waiting for new clients */ @@ -748,7 +762,7 @@ static void close_socket_timeout( void *arg ) flush_registry(); /* if a new client is waiting, we keep on running */ - if (check_fd_events( master_socket->obj.fd_obj, POLLIN )) return; + if (check_fd_events( master_socket->fd, POLLIN )) return; if (debug_level) fprintf( stderr, "wineserver: exiting (pid=%ld)\n", (long) getpid() ); @@ -783,5 +797,5 @@ void close_master_socket(void) /* lock/unlock the master socket to stop accepting new clients */ void lock_master_socket( int locked ) { - set_select_events( &master_socket->obj, locked ? 0 : POLLIN ); + set_fd_events( master_socket->fd, locked ? 0 : POLLIN ); } diff --git a/server/select.c b/server/select.c deleted file mode 100644 index f02e917fed3..00000000000 --- a/server/select.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Server main select() loop - * - * Copyright (C) 1998 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_POLL_H -#include -#endif -#include -#include -#include - -#include "file.h" -#include "thread.h" -#include "process.h" - -struct timeout_user -{ - struct timeout_user *next; /* next in sorted timeout list */ - struct timeout_user *prev; /* prev in sorted timeout list */ - struct timeval when; /* timeout expiry (absolute time) */ - timeout_callback callback; /* callback function */ - void *private; /* callback private data */ -}; - -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 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( struct object *obj ) -{ - int ret; - if (freelist) - { - ret = freelist - poll_users; - freelist = (struct object **)poll_users[ret]; - } - else - { - if (nb_users == allocated_users) - { - 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; - if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) ))) - { - if (allocated_users) - poll_users = newusers; - else - free( newusers ); - obj->select = -1; - return -1; - } - poll_users = newusers; - pollfd = newpoll; - allocated_users = new_count; - } - ret = nb_users++; - } - pollfd[ret].fd = obj->fd; - pollfd[ret].events = 0; - pollfd[ret].revents = 0; - poll_users[ret] = obj; - obj->select = ret; - active_users++; - return ret; -} - -/* remove an object from the select list and close its fd */ -void remove_select_user( struct object *obj ) -{ - int user = obj->select; - assert( user >= 0 ); - assert( poll_users[user] == obj ); - pollfd[user].fd = -1; - pollfd[user].events = 0; - pollfd[user].revents = 0; - poll_users[user] = (struct object *)freelist; - freelist = &poll_users[user]; - close( obj->fd ); - obj->fd = -1; - obj->select = -1; - active_users--; -} - -/* change the fd and events of an object */ -void change_select_fd( struct object *obj, int fd, int events ) -{ - int user = obj->select; - assert( poll_users[user] == obj ); - pollfd[user].fd = fd; - pollfd[user].events = events; - obj->fd = fd; -} - -/* set the events that select waits for on this fd */ -void set_select_events( struct object *obj, int 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; -} - -/* add a timeout user */ -struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private ) -{ - struct timeout_user *user; - struct timeout_user *pos; - - if (!(user = mem_alloc( sizeof(*user) ))) return NULL; - user->when = *when; - user->callback = func; - user->private = private; - - /* Now insert it in the linked list */ - - for (pos = timeout_head; pos; pos = pos->next) - if (!time_before( &pos->when, when )) break; - - if (pos) /* insert it before 'pos' */ - { - if ((user->prev = pos->prev)) user->prev->next = user; - else timeout_head = user; - user->next = pos; - pos->prev = user; - } - else /* insert it at the tail */ - { - user->next = NULL; - if (timeout_tail) timeout_tail->next = user; - else timeout_head = user; - user->prev = timeout_tail; - timeout_tail = user; - } - return user; -} - -/* remove a timeout user */ -void remove_timeout_user( struct timeout_user *user ) -{ - if (user->next) user->next->prev = user->prev; - else timeout_tail = user->prev; - if (user->prev) user->prev->next = user->next; - else timeout_head = user->next; - free( user ); -} - -/* add a timeout in milliseconds to an absolute time */ -void add_timeout( struct timeval *when, int timeout ) -{ - if (timeout) - { - long sec = timeout / 1000; - if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000) - { - when->tv_usec -= 1000000; - when->tv_sec++; - } - when->tv_sec += sec; - } -} - -/* handle the next expired timeout */ -static void handle_timeout(void) -{ - struct timeout_user *user = timeout_head; - timeout_head = user->next; - if (user->next) user->next->prev = user->prev; - else timeout_tail = user->prev; - user->callback( user->private ); - free( user ); -} - -/* SIGHUP handler */ -static void sighup_handler() -{ -#ifdef DEBUG_OBJECTS - dump_objects(); -#endif -} - -/* SIGTERM handler */ -static void sigterm_handler() -{ - flush_registry(); - exit(1); -} - -/* SIGINT handler */ -static void sigint_handler() -{ - kill_all_processes( NULL, 1 ); - flush_registry(); - exit(1); -} - -/* server main loop */ -void select_loop(void) -{ - int ret; - sigset_t sigset; - struct sigaction action; - - /* block the signals we use */ - sigemptyset( &sigset ); - sigaddset( &sigset, SIGCHLD ); - sigaddset( &sigset, SIGHUP ); - sigaddset( &sigset, SIGINT ); - sigaddset( &sigset, SIGQUIT ); - sigaddset( &sigset, SIGTERM ); - sigprocmask( SIG_BLOCK, &sigset, NULL ); - - /* set the handlers */ - action.sa_mask = sigset; - action.sa_flags = 0; - action.sa_handler = sigchld_handler; - sigaction( SIGCHLD, &action, NULL ); - action.sa_handler = sighup_handler; - sigaction( SIGHUP, &action, NULL ); - action.sa_handler = sigint_handler; - sigaction( SIGINT, &action, NULL ); - action.sa_handler = sigterm_handler; - sigaction( SIGQUIT, &action, NULL ); - sigaction( SIGTERM, &action, NULL ); - - while (active_users) - { - long diff = -1; - if (timeout_head) - { - struct timeval now; - gettimeofday( &now, NULL ); - while (timeout_head) - { - if (!time_before( &now, &timeout_head->when )) handle_timeout(); - else - { - diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000 - + (timeout_head->when.tv_usec - now.tv_usec) / 1000; - break; - } - } - if (!active_users) break; /* last user removed by a timeout */ - } - - sigprocmask( SIG_UNBLOCK, &sigset, NULL ); - - /* Note: we assume that the signal handlers do not manipulate the pollfd array - * or the timeout list, otherwise there is a race here. - */ - ret = poll( pollfd, nb_users, diff ); - - sigprocmask( SIG_BLOCK, &sigset, NULL ); - - if (ret > 0) - { - int i; - for (i = 0; i < nb_users; i++) - { - if (pollfd[i].revents) - { - fd_poll_event( poll_users[i], pollfd[i].revents ); - if (!--ret) break; - } - } - } - } -} diff --git a/server/serial.c b/server/serial.c index 06b07cb032d..2f9130b089d 100644 --- a/server/serial.c +++ b/server/serial.c @@ -52,6 +52,7 @@ #include "async.h" static void serial_dump( struct object *obj, int verbose ); +static struct fd *serial_get_fd( struct object *obj ); static void serial_destroy(struct object *obj); static int serial_get_poll_events( struct fd *fd ); @@ -63,6 +64,7 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in struct serial { struct object obj; + struct fd *fd; unsigned int access; unsigned int attrib; @@ -93,7 +95,7 @@ static const struct object_ops serial_ops = default_fd_remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ - default_get_fd, /* get_fd */ + serial_get_fd, /* get_fd */ serial_destroy /* destroy */ }; @@ -148,7 +150,7 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i if(0>fcntl(fd, F_SETFL, 0)) perror("fcntl"); - if ((serial = alloc_fd_object( &serial_ops, &serial_fd_ops, fd ))) + if ((serial = alloc_object( &serial_ops ))) { serial->attrib = attributes; serial->access = access; @@ -162,10 +164,21 @@ static struct serial *create_serial( const char *nameptr, size_t len, unsigned i init_async_queue(&serial->read_q); init_async_queue(&serial->write_q); init_async_queue(&serial->wait_q); + if (!(serial->fd = alloc_fd( &serial_fd_ops, fd, &serial->obj ))) + { + release_object( serial ); + return NULL; + } } return serial; } +static struct fd *serial_get_fd( struct object *obj ) +{ + struct serial *serial = (struct serial *)obj; + return (struct fd *)grab_object( serial->fd ); +} + static void serial_destroy( struct object *obj) { struct serial *serial = (struct serial *)obj; @@ -173,16 +186,17 @@ static void serial_destroy( struct object *obj) destroy_async_queue(&serial->read_q); destroy_async_queue(&serial->write_q); destroy_async_queue(&serial->wait_q); + if (serial->fd) release_object( serial->fd ); } static void serial_dump( struct object *obj, int verbose ) { struct serial *serial = (struct serial *)obj; assert( obj->ops == &serial_ops ); - fprintf( stderr, "Port fd=%p mask=%x\n", serial->obj.fd_obj, serial->eventmask ); + fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask ); } -struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access ) +static struct serial *get_serial_obj( struct process *process, obj_handle_t handle, unsigned int access ) { return (struct serial *)get_handle_obj( process, handle, access, &serial_ops ); } @@ -249,7 +263,7 @@ static void serial_poll_event(struct fd *fd, int event) if(IS_READY(serial->wait_q) && (POLLIN & event) ) async_notify(serial->wait_q.head,STATUS_ALERTED); - set_select_events( &serial->obj, serial_get_poll_events(fd) ); + set_fd_events( fd, serial_get_poll_events(fd) ); } static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, int type, int count) @@ -310,7 +324,7 @@ static void serial_queue_async(struct fd *fd, void *ptr, unsigned int status, in else if ( async ) destroy_async ( async ); else set_error ( STATUS_INVALID_PARAMETER ); - set_select_events ( &serial->obj, serial_get_poll_events( fd )); + set_fd_events ( fd, serial_get_poll_events( fd )); } static int serial_flush( struct fd *fd ) diff --git a/server/smb.c b/server/smb.c index 4bb777478cf..ef94dd5f6e1 100644 --- a/server/smb.c +++ b/server/smb.c @@ -52,6 +52,7 @@ #include "request.h" static void smb_dump( struct object *obj, int verbose ); +static struct fd *smb_get_fd( struct object *obj ); static void smb_destroy(struct object *obj); static int smb_get_info( struct fd *fd, struct get_file_info_reply *reply, int *flags ); @@ -60,6 +61,7 @@ static int smb_get_poll_events( struct fd *fd ); struct smb { struct object obj; + struct fd *fd; unsigned int tree_id; unsigned int user_id; unsigned int dialect; @@ -75,7 +77,7 @@ static const struct object_ops smb_ops = default_fd_remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ - default_get_fd, /* get_fd */ + smb_get_fd, /* get_fd */ smb_destroy /* destroy */ }; @@ -88,20 +90,27 @@ static const struct fd_ops smb_fd_ops = no_queue_async /* queue_async */ }; +static struct fd *smb_get_fd( struct object *obj ) +{ + struct smb *smb = (struct smb *)obj; + return (struct fd *)grab_object( smb->fd ); +} + static void smb_destroy( struct object *obj) { - /* struct smb *smb = (struct smb *)obj; */ + struct smb *smb = (struct smb *)obj; assert( obj->ops == &smb_ops ); + if (smb->fd) release_object( smb->fd ); } static void smb_dump( struct object *obj, int verbose ) { struct smb *smb = (struct smb *)obj; assert( obj->ops == &smb_ops ); - fprintf( stderr, "Smb file fd=%p\n", smb->obj.fd_obj ); + fprintf( stderr, "Smb file fd=%p\n", smb->fd ); } -struct smb *get_smb_obj( struct process *process, obj_handle_t handle, unsigned int access ) +static struct smb *get_smb_obj( struct process *process, obj_handle_t handle, unsigned int access ) { return (struct smb *)get_handle_obj( process, handle, access, &smb_ops ); } @@ -158,7 +167,7 @@ DECL_HANDLER(create_smb) return; } - smb = alloc_fd_object( &smb_ops, &smb_fd_ops, fd ); + smb = alloc_object( &smb_ops ); if (smb) { smb->tree_id = req->tree_id; @@ -166,6 +175,11 @@ DECL_HANDLER(create_smb) smb->dialect = req->dialect; smb->file_id = req->file_id; smb->offset = 0; + if (!(smb->fd = alloc_fd( &smb_fd_ops, fd, &smb->obj ))) + { + release_object( smb ); + return; + } reply->handle = alloc_handle( current->process, smb, GENERIC_READ, 0); release_object( smb ); } diff --git a/server/snapshot.c b/server/snapshot.c index 8a65ef52628..fda8355b77f 100644 --- a/server/snapshot.c +++ b/server/snapshot.c @@ -79,7 +79,7 @@ static struct snapshot *create_snapshot( process_id_t pid, int flags ) else if (!(process = get_process_from_id( pid ))) return NULL; } - if (!(snapshot = alloc_object( &snapshot_ops, -1 ))) + if (!(snapshot = alloc_object( &snapshot_ops ))) { if (process) release_object( process ); return NULL; diff --git a/server/sock.c b/server/sock.c index 44e0088b04c..51d7ec70f1b 100644 --- a/server/sock.c +++ b/server/sock.c @@ -65,11 +65,13 @@ struct sock { struct object obj; /* object header */ + struct fd *fd; /* socket file descriptor */ unsigned int state; /* status bits */ unsigned int mask; /* event mask */ unsigned int hmask; /* held (blocked) events */ unsigned int pmask; /* pending events */ unsigned int flags; /* socket flags */ + int polling; /* is socket being polled? */ unsigned short type; /* socket type */ unsigned short family; /* socket family */ struct event *event; /* event object */ @@ -84,6 +86,7 @@ struct sock static void sock_dump( struct object *obj, int verbose ); static int sock_signaled( struct object *obj, struct thread *thread ); +static struct fd *sock_get_fd( struct object *obj ); static void sock_destroy( struct object *obj ); static int sock_get_poll_events( struct fd *fd ); @@ -102,7 +105,7 @@ static const struct object_ops sock_ops = remove_queue, /* remove_queue */ sock_signaled, /* signaled */ no_satisfied, /* satisfied */ - default_get_fd, /* get_fd */ + sock_get_fd, /* get_fd */ sock_destroy /* destroy */ }; @@ -193,19 +196,20 @@ void sock_init(void) static int sock_reselect( struct sock *sock ) { - int ev = sock_get_poll_events( sock->obj.fd_obj ); + int ev = sock_get_poll_events( sock->fd ); if (debug_level) fprintf(stderr,"sock_reselect(%p): new mask %x\n", sock, ev); - if (sock->obj.select == -1) { + if (!sock->polling) /* FIXME: should find a better way to do this */ + { /* previously unconnected socket, is this reselect supposed to connect it? */ if (!(sock->state & ~FD_WINE_NONBLOCKING)) return 0; /* ok, it is, attach it to the wineserver's main poll loop */ - add_select_user( &sock->obj ); + sock->polling = 1; } /* update condition mask */ - set_select_events( &sock->obj, ev ); + set_fd_events( sock->fd, ev ); return ev; } @@ -213,11 +217,11 @@ static int sock_reselect( struct sock *sock ) This function is used to signal pending events nevertheless */ static void sock_try_event ( struct sock *sock, int event ) { - event = check_fd_events( sock->obj.fd_obj, event ); + event = check_fd_events( sock->fd, event ); if (event) { if ( debug_level ) fprintf ( stderr, "sock_try_event: %x\n", event ); - sock_poll_event ( sock->obj.fd_obj, event ); + sock_poll_event ( sock->fd, event ); } } @@ -413,7 +417,7 @@ static void sock_poll_event( struct fd *fd, int event ) { if ( debug_level ) fprintf ( stderr, "removing socket %p from select loop\n", sock ); - set_select_events( &sock->obj, -1 ); + set_fd_events( sock->fd, -1 ); } else sock_reselect( sock ); @@ -431,7 +435,7 @@ static void sock_dump( struct object *obj, int verbose ) struct sock *sock = (struct sock *)obj; assert( obj->ops == &sock_ops ); printf( "Socket fd=%p, state=%x, mask=%x, pending=%x, held=%x\n", - sock->obj.fd_obj, sock->state, + sock->fd, sock->state, sock->mask, sock->pmask, sock->hmask ); } @@ -440,7 +444,7 @@ static int sock_signaled( struct object *obj, struct thread *thread ) struct sock *sock = (struct sock *)obj; assert( obj->ops == &sock_ops ); - return check_fd_events( sock->obj.fd_obj, sock_get_poll_events( sock->obj.fd_obj ) ) != 0; + return check_fd_events( sock->fd, sock_get_poll_events( sock->fd ) ) != 0; } static int sock_get_poll_events( struct fd *fd ) @@ -555,6 +559,12 @@ static void sock_queue_async(struct fd *fd, void *ptr, unsigned int status, int if ( pollev ) sock_try_event ( sock, pollev ); } +static struct fd *sock_get_fd( struct object *obj ) +{ + struct sock *sock = (struct sock *)obj; + return (struct fd *)grab_object( sock->fd ); +} + static void sock_destroy( struct object *obj ) { struct sock *sock = (struct sock *)obj; @@ -571,6 +581,7 @@ static void sock_destroy( struct object *obj ) destroy_async_queue ( &sock->write_q ); } if (sock->event) release_object( sock->event ); + if (sock->fd) release_object( sock->fd ); } /* create a new and unconnected socket */ @@ -587,12 +598,16 @@ static struct object *create_socket( int family, int type, int protocol, unsigne return NULL; } fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ - if (!(sock = alloc_fd_object( &sock_ops, &sock_fd_ops, -1 ))) return NULL; - set_unix_fd( &sock->obj, sockfd ); + if (!(sock = alloc_object( &sock_ops ))) + { + close( sockfd ); + return NULL; + } sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0; sock->mask = 0; sock->hmask = 0; sock->pmask = 0; + sock->polling = 0; sock->flags = flags; sock->type = type; sock->family = family; @@ -601,6 +616,11 @@ static struct object *create_socket( int family, int type, int protocol, unsigne sock->message = 0; sock->wparam = 0; sock->deferred = NULL; + if (!(sock->fd = alloc_fd( &sock_fd_ops, sockfd, &sock->obj ))) + { + release_object( sock ); + return NULL; + } if (sock->flags & WSA_FLAG_OVERLAPPED) { init_async_queue (&sock->read_q); @@ -635,14 +655,15 @@ static struct sock *accept_socket( obj_handle_t handle ) * return. */ slen = sizeof(saddr); - acceptfd = accept( get_unix_fd(sock->obj.fd_obj), &saddr, &slen); + acceptfd = accept( get_unix_fd(sock->fd), &saddr, &slen); if (acceptfd==-1) { sock_set_error(); release_object( sock ); return NULL; } - if (!(acceptsock = alloc_fd_object( &sock_ops, &sock_fd_ops, acceptfd ))) + if (!(acceptsock = alloc_object( &sock_ops ))) { + close( acceptfd ); release_object( sock ); return NULL; } @@ -655,6 +676,7 @@ static struct sock *accept_socket( obj_handle_t handle ) acceptsock->mask = sock->mask; acceptsock->hmask = 0; acceptsock->pmask = 0; + acceptsock->polling = 0; acceptsock->type = sock->type; acceptsock->family = sock->family; acceptsock->event = NULL; @@ -664,6 +686,12 @@ static struct sock *accept_socket( obj_handle_t handle ) if (sock->event) acceptsock->event = (struct event *)grab_object( sock->event ); acceptsock->flags = sock->flags; acceptsock->deferred = 0; + if (!(acceptsock->fd = alloc_fd( &sock_fd_ops, acceptfd, &acceptsock->obj ))) + { + release_object( acceptsock ); + release_object( sock ); + return NULL; + } if ( acceptsock->flags & WSA_FLAG_OVERLAPPED ) { init_async_queue ( &acceptsock->read_q ); diff --git a/server/thread.c b/server/thread.c index 8b3ca12a868..1c8dbcea65a 100644 --- a/server/thread.c +++ b/server/thread.c @@ -127,8 +127,9 @@ inline static void init_thread_structure( struct thread *thread ) thread->req_toread = 0; thread->reply_data = NULL; thread->reply_towrite = 0; - thread->reply_fd = -1; - thread->wait_fd = -1; + thread->request_fd = NULL; + thread->reply_fd = NULL; + thread->wait_fd = NULL; thread->state = RUNNING; thread->attached = 0; thread->exit_code = 0; @@ -149,12 +150,11 @@ struct thread *create_thread( int fd, struct process *process ) { struct thread *thread; - if (!(thread = alloc_fd_object( &thread_ops, &thread_fd_ops, fd ))) return NULL; + if (!(thread = alloc_object( &thread_ops ))) return NULL; init_thread_structure( thread ); thread->process = (struct process *)grab_object( process ); - thread->request_fd = fd; if (!current) current = thread; if (!booting_thread) /* first thread ever */ @@ -171,8 +171,13 @@ struct thread *create_thread( int fd, struct process *process ) release_object( thread ); return NULL; } + if (!(thread->request_fd = alloc_fd( &thread_fd_ops, fd, &thread->obj ))) + { + release_object( thread ); + return NULL; + } - set_select_events( &thread->obj, POLLIN ); /* start listening to events */ + set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */ add_process_thread( thread->process, thread ); return thread; } @@ -198,9 +203,9 @@ static void cleanup_thread( struct thread *thread ) while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc ); if (thread->req_data) free( thread->req_data ); if (thread->reply_data) free( thread->reply_data ); - if (thread->request_fd != -1) close( thread->request_fd ); - if (thread->reply_fd != -1) close( thread->reply_fd ); - if (thread->wait_fd != -1) close( thread->wait_fd ); + if (thread->request_fd) release_object( thread->request_fd ); + if (thread->reply_fd) release_object( thread->reply_fd ); + if (thread->wait_fd) release_object( thread->wait_fd ); if (thread->hooks) release_object( thread->hooks ); free_msg_queue( thread ); destroy_thread_windows( thread ); @@ -214,9 +219,9 @@ static void cleanup_thread( struct thread *thread ) } thread->req_data = NULL; thread->reply_data = NULL; - thread->request_fd = -1; - thread->reply_fd = -1; - thread->wait_fd = -1; + thread->request_fd = NULL; + thread->reply_fd = NULL; + thread->wait_fd = NULL; thread->hooks = NULL; if (thread == booting_thread) /* killing booting thread */ @@ -449,7 +454,8 @@ static int send_thread_wakeup( struct thread *thread, void *cookie, int signaled reply.cookie = cookie; reply.signaled = signaled; - if ((ret = write( thread->wait_fd, &reply, sizeof(reply) )) == sizeof(reply)) return 0; + if ((ret = write( get_unix_fd( thread->wait_fd ), &reply, sizeof(reply) )) == sizeof(reply)) + return 0; if (ret >= 0) fatal_protocol_error( thread, "partial wakeup write %d\n", ret ); else if (errno == EPIPE) @@ -738,9 +744,6 @@ void kill_thread( struct thread *thread, int violent_death ) remove_process_thread( thread->process, thread ); wake_up( &thread->obj, 0 ); detach_thread( thread, violent_death ? SIGTERM : 0 ); - if (thread->request_fd == thread->obj.fd) thread->request_fd = -1; - if (thread->reply_fd == thread->obj.fd) thread->reply_fd = -1; - remove_select_user( &thread->obj ); cleanup_thread( thread ); release_object( thread ); } @@ -828,11 +831,12 @@ DECL_HANDLER(init_thread) fatal_protocol_error( current, "bad wait fd\n" ); goto error; } + current->reply_fd = alloc_fd( &thread_fd_ops, reply_fd, ¤t->obj ); + current->wait_fd = alloc_fd( &thread_fd_ops, wait_fd, ¤t->obj ); + if (!current->reply_fd || !current->wait_fd) return; current->unix_pid = req->unix_pid; current->teb = req->teb; - current->reply_fd = reply_fd; - current->wait_fd = wait_fd; if (current->suspend + current->process->suspend > 0) stop_thread( current ); if (current->process->running_threads > 1) diff --git a/server/thread.h b/server/thread.h index cc37f25134d..314ceabdbfa 100644 --- a/server/thread.h +++ b/server/thread.h @@ -81,9 +81,9 @@ struct thread void *reply_data; /* variable-size data for reply */ unsigned int reply_size; /* size of reply data */ unsigned int reply_towrite; /* amount of data still to write in reply */ - int request_fd; /* fd for receiving client requests */ - int reply_fd; /* fd to send a reply to a client */ - int wait_fd; /* fd to use to wake a sleeping client */ + struct fd *request_fd; /* fd for receiving client requests */ + struct fd *reply_fd; /* fd to send a reply to a client */ + struct fd *wait_fd; /* fd to use to wake a sleeping client */ enum run_state state; /* running state */ int attached; /* is thread attached with ptrace? */ int exit_code; /* thread exit code */ diff --git a/server/timer.c b/server/timer.c index 22e4e7906bc..4ca7793bb62 100644 --- a/server/timer.c +++ b/server/timer.c @@ -28,6 +28,8 @@ #include #include "windef.h" + +#include "file.h" #include "handle.h" #include "request.h"