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.
diff --git a/server/async.c b/server/async.c
index 027dd25..e0877b2 100644
--- a/server/async.c
+++ b/server/async.c
@@ -193,6 +193,7 @@
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 @@
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 25917ae..3a044b2 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -168,6 +168,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 5f5349d..edc92f7 100644
--- a/server/file.c
+++ b/server/file.c
@@ -76,8 +76,8 @@
{
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 3514022..096b9df 100644
--- a/server/file.h
+++ b/server/file.h
@@ -63,9 +63,8 @@
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 89af2bf..2898d1a 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -74,8 +74,8 @@
{
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 0a4ab96..a736d83 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -143,8 +143,8 @@
{
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 @@
{
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 f2b88c1..8dc1d18 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -89,8 +89,8 @@
{
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 */