Commit ba896e75 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent 072698c9
...@@ -193,6 +193,7 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co ...@@ -193,6 +193,7 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co
list_add_tail( &queue->queue, &async->queue_entry ); list_add_tail( &queue->queue, &async->queue_entry );
grab_object( async ); grab_object( async );
if (queue->fd) set_fd_signaled( queue->fd, 0 );
if (event) reset_event( event ); if (event) reset_event( event );
return async; return async;
} }
...@@ -230,6 +231,7 @@ void async_set_result( struct object *obj, unsigned int status ) ...@@ -230,6 +231,7 @@ void async_set_result( struct object *obj, unsigned int status )
thread_queue_apc( async->thread, NULL, &data ); thread_queue_apc( async->thread, NULL, &data );
} }
if (async->event) set_event( async->event ); if (async->event) set_event( async->event );
else if (async->queue->fd) set_fd_signaled( async->queue->fd, 1 );
} }
} }
......
...@@ -168,6 +168,7 @@ struct fd ...@@ -168,6 +168,7 @@ struct fd
unsigned int access; /* file access (FILE_READ_DATA etc.) */ unsigned int access; /* file access (FILE_READ_DATA etc.) */
unsigned int sharing; /* file sharing mode */ unsigned int sharing; /* file sharing mode */
int unix_fd; /* unix file descriptor */ 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 fs_locks :1; /* can we use filesystem locks for this fd? */
int unmounted :1;/* has the device been unmounted? */ int unmounted :1;/* has the device been unmounted? */
int poll_index; /* index of fd in poll array */ int poll_index; /* index of fd in poll array */
...@@ -1360,6 +1361,7 @@ static struct fd *alloc_fd_object(void) ...@@ -1360,6 +1361,7 @@ static struct fd *alloc_fd_object(void)
fd->access = 0; fd->access = 0;
fd->sharing = 0; fd->sharing = 0;
fd->unix_fd = -1; fd->unix_fd = -1;
fd->signaled = 1;
fd->fs_locks = 1; fd->fs_locks = 1;
fd->unmounted = 0; fd->unmounted = 0;
fd->poll_index = -1; fd->poll_index = -1;
...@@ -1391,6 +1393,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use ...@@ -1391,6 +1393,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
fd->access = 0; fd->access = 0;
fd->sharing = 0; fd->sharing = 0;
fd->unix_fd = -1; fd->unix_fd = -1;
fd->signaled = 0;
fd->fs_locks = 0; fd->fs_locks = 0;
fd->unmounted = 0; fd->unmounted = 0;
fd->poll_index = -1; fd->poll_index = -1;
...@@ -1610,6 +1613,13 @@ int is_fd_removable( struct fd *fd ) ...@@ -1610,6 +1613,13 @@ int is_fd_removable( struct fd *fd )
return (fd->inode && fd->inode->device->removable); 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 */ /* 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 ) 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 ) ...@@ -1635,55 +1645,11 @@ int check_fd_events( struct fd *fd, int events )
return pfd.revents; 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 */ /* default signaled() routine for objects that poll() on an fd */
int default_fd_signaled( struct object *obj, struct thread *thread ) int default_fd_signaled( struct object *obj, struct thread *thread )
{ {
int events, ret;
struct fd *fd = get_obj_fd( obj ); struct fd *fd = get_obj_fd( obj );
int ret = fd->signaled;
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 );
}
}
release_object( fd ); release_object( fd );
return ret; return ret;
} }
...@@ -1705,7 +1671,7 @@ void default_poll_event( struct fd *fd, int event ) ...@@ -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 an error occurred, stop polling this fd to avoid busy-looping */
if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); 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 ) struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count )
......
...@@ -76,8 +76,8 @@ static const struct object_ops file_ops = ...@@ -76,8 +76,8 @@ static const struct object_ops file_ops =
{ {
sizeof(struct file), /* size */ sizeof(struct file), /* size */
file_dump, /* dump */ file_dump, /* dump */
default_fd_add_queue, /* add_queue */ add_queue, /* add_queue */
default_fd_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_fd_signaled, /* signaled */ default_fd_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
no_signal, /* signal */ no_signal, /* signal */
......
...@@ -63,9 +63,8 @@ extern int check_fd_events( struct fd *fd, int events ); ...@@ -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 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 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 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_signaled( struct object *obj, struct thread *thread );
extern int default_fd_get_poll_events( struct fd *fd ); extern int default_fd_get_poll_events( struct fd *fd );
extern void default_poll_event( struct fd *fd, int event ); extern void default_poll_event( struct fd *fd, int event );
......
...@@ -74,8 +74,8 @@ static const struct object_ops mailslot_ops = ...@@ -74,8 +74,8 @@ static const struct object_ops mailslot_ops =
{ {
sizeof(struct mailslot), /* size */ sizeof(struct mailslot), /* size */
mailslot_dump, /* dump */ mailslot_dump, /* dump */
default_fd_add_queue, /* add_queue */ add_queue, /* add_queue */
default_fd_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_fd_signaled, /* signaled */ default_fd_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
no_signal, /* signal */ no_signal, /* signal */
......
...@@ -143,8 +143,8 @@ static const struct object_ops pipe_server_ops = ...@@ -143,8 +143,8 @@ static const struct object_ops pipe_server_ops =
{ {
sizeof(struct pipe_server), /* size */ sizeof(struct pipe_server), /* size */
pipe_server_dump, /* dump */ pipe_server_dump, /* dump */
default_fd_add_queue, /* add_queue */ add_queue, /* add_queue */
default_fd_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_fd_signaled, /* signaled */ default_fd_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
no_signal, /* signal */ no_signal, /* signal */
...@@ -177,8 +177,8 @@ static const struct object_ops pipe_client_ops = ...@@ -177,8 +177,8 @@ static const struct object_ops pipe_client_ops =
{ {
sizeof(struct pipe_client), /* size */ sizeof(struct pipe_client), /* size */
pipe_client_dump, /* dump */ pipe_client_dump, /* dump */
default_fd_add_queue, /* add_queue */ add_queue, /* add_queue */
default_fd_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_fd_signaled, /* signaled */ default_fd_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
no_signal, /* signal */ no_signal, /* signal */
......
...@@ -89,8 +89,8 @@ static const struct object_ops serial_ops = ...@@ -89,8 +89,8 @@ static const struct object_ops serial_ops =
{ {
sizeof(struct serial), /* size */ sizeof(struct serial), /* size */
serial_dump, /* dump */ serial_dump, /* dump */
default_fd_add_queue, /* add_queue */ add_queue, /* add_queue */
default_fd_remove_queue, /* remove_queue */ remove_queue, /* remove_queue */
default_fd_signaled, /* signaled */ default_fd_signaled, /* signaled */
no_satisfied, /* satisfied */ no_satisfied, /* satisfied */
no_signal, /* signal */ no_signal, /* signal */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment