From ba896e75d7fce68e5183007b65eae7e35490ccd4 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 4 Apr 2007 19:39:29 +0200 Subject: [PATCH] server: Fix the handling of the signaled status for file descriptors. File handles are signaled when an I/O operation completes, and reset when another operation is queued. --- server/async.c | 2 ++ server/fd.c | 58 ++++++++++----------------------------------- server/file.c | 4 ++-- server/file.h | 3 +-- server/mailslot.c | 4 ++-- server/named_pipe.c | 8 +++---- server/serial.c | 4 ++-- 7 files changed, 25 insertions(+), 58 deletions(-) diff --git a/server/async.c b/server/async.c index 027dd25a3b1..e0877b2e062 100644 --- a/server/async.c +++ b/server/async.c @@ -193,6 +193,7 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co list_add_tail( &queue->queue, &async->queue_entry ); grab_object( async ); + if (queue->fd) set_fd_signaled( queue->fd, 0 ); if (event) reset_event( event ); return async; } @@ -230,6 +231,7 @@ void async_set_result( struct object *obj, unsigned int status ) thread_queue_apc( async->thread, NULL, &data ); } if (async->event) set_event( async->event ); + else if (async->queue->fd) set_fd_signaled( async->queue->fd, 1 ); } } diff --git a/server/fd.c b/server/fd.c index 25917aea75f..3a044b21832 100644 --- a/server/fd.c +++ b/server/fd.c @@ -168,6 +168,7 @@ struct fd unsigned int access; /* file access (FILE_READ_DATA etc.) */ unsigned int sharing; /* file sharing mode */ int unix_fd; /* unix file descriptor */ + int signaled :1; /* is the fd signaled? */ int fs_locks :1; /* can we use filesystem locks for this fd? */ int unmounted :1;/* has the device been unmounted? */ int poll_index; /* index of fd in poll array */ @@ -1360,6 +1361,7 @@ static struct fd *alloc_fd_object(void) fd->access = 0; fd->sharing = 0; fd->unix_fd = -1; + fd->signaled = 1; fd->fs_locks = 1; fd->unmounted = 0; fd->poll_index = -1; @@ -1391,6 +1393,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->access = 0; fd->sharing = 0; fd->unix_fd = -1; + fd->signaled = 0; fd->fs_locks = 0; fd->unmounted = 0; fd->poll_index = -1; @@ -1610,6 +1613,13 @@ int is_fd_removable( struct fd *fd ) return (fd->inode && fd->inode->device->removable); } +/* set or clear the fd signaled state */ +void set_fd_signaled( struct fd *fd, int signaled ) +{ + fd->signaled = signaled; + if (signaled) wake_up( fd->user, 0 ); +} + /* handler for close_handle that refuses to close fd-associated handles in other processes */ int fd_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) { @@ -1635,55 +1645,11 @@ int check_fd_events( struct fd *fd, int events ) return pfd.revents; } -/* 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 = get_obj_fd( obj ); - - if (!fd) return 0; - if (!fd->inode && list_empty( &obj->wait_queue )) /* first on the queue */ - 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 (!fd->inode && list_empty( &obj->wait_queue )) /* last on the queue is gone */ - 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 ) { - int events, ret; struct fd *fd = get_obj_fd( obj ); - - if (fd->inode) ret = 1; /* regular files are always signaled */ - else - { - events = fd->fd_ops->get_poll_events( fd ); - ret = check_fd_events( fd, events ) != 0; - - if (ret) - { - /* stop waiting on select() if we are signaled */ - set_fd_events( fd, 0 ); - } - else if (!list_empty( &obj->wait_queue )) - { - /* restart waiting on poll() if we are no longer signaled */ - set_fd_events( fd, events ); - } - } + int ret = fd->signaled; release_object( fd ); return ret; } @@ -1705,7 +1671,7 @@ void default_poll_event( struct fd *fd, int event ) /* if an error occurred, stop polling this fd to avoid busy-looping */ if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); - wake_up( fd->user, 0 ); + else set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) ); } struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) diff --git a/server/file.c b/server/file.c index 5f5349d4fb1..edc92f72a59 100644 --- a/server/file.c +++ b/server/file.c @@ -76,8 +76,8 @@ static const struct object_ops file_ops = { sizeof(struct file), /* size */ file_dump, /* dump */ - default_fd_add_queue, /* add_queue */ - default_fd_remove_queue, /* remove_queue */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ diff --git a/server/file.h b/server/file.h index 3514022cac7..096b9df7741 100644 --- a/server/file.h +++ b/server/file.h @@ -63,9 +63,8 @@ extern int check_fd_events( struct fd *fd, int events ); extern void set_fd_events( struct fd *fd, int events ); extern obj_handle_t lock_fd( struct fd *fd, file_pos_t offset, file_pos_t count, int shared, int wait ); extern void unlock_fd( struct fd *fd, file_pos_t offset, file_pos_t count ); +extern void set_fd_signaled( struct fd *fd, int signaled ); -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 ); extern int default_fd_signaled( struct object *obj, struct thread *thread ); extern int default_fd_get_poll_events( struct fd *fd ); extern void default_poll_event( struct fd *fd, int event ); diff --git a/server/mailslot.c b/server/mailslot.c index 89af2bfb1d2..2898d1a8070 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -74,8 +74,8 @@ static const struct object_ops mailslot_ops = { sizeof(struct mailslot), /* size */ mailslot_dump, /* dump */ - default_fd_add_queue, /* add_queue */ - default_fd_remove_queue, /* remove_queue */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ diff --git a/server/named_pipe.c b/server/named_pipe.c index 0a4ab964367..a736d83e453 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -143,8 +143,8 @@ static const struct object_ops pipe_server_ops = { sizeof(struct pipe_server), /* size */ pipe_server_dump, /* dump */ - default_fd_add_queue, /* add_queue */ - default_fd_remove_queue, /* remove_queue */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ @@ -177,8 +177,8 @@ static const struct object_ops pipe_client_ops = { sizeof(struct pipe_client), /* size */ pipe_client_dump, /* dump */ - default_fd_add_queue, /* add_queue */ - default_fd_remove_queue, /* remove_queue */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ diff --git a/server/serial.c b/server/serial.c index f2b88c14d69..8dc1d189a86 100644 --- a/server/serial.c +++ b/server/serial.c @@ -89,8 +89,8 @@ static const struct object_ops serial_ops = { sizeof(struct serial), /* size */ serial_dump, /* dump */ - default_fd_add_queue, /* add_queue */ - default_fd_remove_queue, /* remove_queue */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */