Adapted to new select interface.
Fixed bug in *_signaled routines that could cause busy-waiting in the
select loop.

diff --git a/server/file.c b/server/file.c
index 00f1c60..041c67c 100644
--- a/server/file.c
+++ b/server/file.c
@@ -26,13 +26,13 @@
 
 struct file
 {
-    struct object  obj;             /* object header */
-    struct file   *next;            /* next file in hashing list */
-    char          *name;            /* file name */
-    int            fd;              /* Unix file descriptor */
-    unsigned int   access;          /* file access (GENERIC_READ/WRITE) */
-    unsigned int   flags;           /* flags (FILE_FLAG_*) */
-    unsigned int   sharing;         /* file sharing mode */
+    struct object       obj;        /* object header */
+    struct select_user  select;     /* select user */
+    struct file        *next;       /* next file in hashing list */
+    char               *name;       /* file name */
+    unsigned int        access;     /* file access (GENERIC_READ/WRITE) */
+    unsigned int        flags;      /* flags (FILE_FLAG_*) */
+    unsigned int        sharing;    /* file sharing mode */
 };
 
 #define NAME_HASH_SIZE 37
@@ -63,12 +63,6 @@
     file_destroy
 };
 
-static const struct select_ops select_ops =
-{
-    default_select_event,
-    NULL   /* we never set a timeout on a file */
-};
-
 
 static int get_name_hash( const char *name )
 {
@@ -194,10 +188,13 @@
         file->next = NULL;
     }
     init_object( &file->obj, &file_ops, NULL );
-    file->fd      = fd;
-    file->access  = access;
-    file->flags   = attrs;
-    file->sharing = sharing;
+    file->select.fd      = fd;
+    file->select.func    = default_select_event;
+    file->select.private = file;
+    file->access         = access;
+    file->flags          = attrs;
+    file->sharing        = sharing;
+    register_select_user( &file->select );
     CLEAR_ERROR();
     return &file->obj;
 }
@@ -231,12 +228,15 @@
         return NULL;
     }
     init_object( &file->obj, &file_ops, NULL );
-    file->name    = NULL;
-    file->next    = NULL;
-    file->fd      = fd;
-    file->access  = access;
-    file->flags   = 0;
-    file->sharing = 0;
+    file->name           = NULL;
+    file->next           = NULL;
+    file->select.fd      = fd;
+    file->select.func    = default_select_event;
+    file->select.private = file;
+    file->access         = access;
+    file->flags          = 0;
+    file->sharing        = 0;
+    register_select_user( &file->select );
     CLEAR_ERROR();
     return file;
 }
@@ -246,7 +246,7 @@
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
     printf( "File fd=%d flags=%08x name='%s'\n",
-            file->fd, file->flags, file->name );
+            file->select.fd, file->flags, file->name );
 }
 
 static int file_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -255,11 +255,10 @@
     assert( obj->ops == &file_ops );
     if (!obj->head)  /* first on the queue */
     {
-        if (!add_select_user( file->fd, READ_EVENT | WRITE_EVENT, &select_ops, file ))
-        {
-            SET_ERROR( ERROR_OUTOFMEMORY );
-            return 0;
-        }
+        int events = 0;
+        if (file->access & GENERIC_READ) events |= READ_EVENT;
+        if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
+        set_select_events( &file->select, events );
     }
     add_queue( obj, entry );
     return 1;
@@ -272,37 +271,44 @@
 
     remove_queue( obj, entry );
     if (!obj->head)  /* last on the queue is gone */
-        remove_select_user( file->fd );
+        set_select_events( &file->select, 0 );
     release_object( obj );
 }
 
 static int file_signaled( struct object *obj, struct thread *thread )
 {
-    fd_set read_fds, write_fds;
-    struct timeval tv = { 0, 0 };
-
+    int events = 0;
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
 
-    FD_ZERO( &read_fds );
-    FD_ZERO( &write_fds );
-    if (file->access & GENERIC_READ) FD_SET( file->fd, &read_fds );
-    if (file->access & GENERIC_WRITE) FD_SET( file->fd, &write_fds );
-    return select( file->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0;
+    if (file->access & GENERIC_READ) events |= READ_EVENT;
+    if (file->access & GENERIC_WRITE) events |= WRITE_EVENT;
+    if (check_select_events( &file->select, events ))
+    {
+        /* stop waiting on select() if we are signaled */
+        set_select_events( &file->select, 0 );
+        return 1;
+    }
+    else
+    {
+        /* restart waiting on select() if we are no longer signaled */
+        if (obj->head) set_select_events( &file->select, events );
+        return 0;
+    }
 }
 
 static int file_get_read_fd( struct object *obj )
 {
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
-    return dup( file->fd );
+    return dup( file->select.fd );
 }
 
 static int file_get_write_fd( struct object *obj )
 {
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
-    return dup( file->fd );
+    return dup( file->select.fd );
 }
 
 static int file_flush( struct object *obj )
@@ -311,7 +317,7 @@
     struct file *file = (struct file *)grab_object(obj);
     assert( obj->ops == &file_ops );
 
-    ret = (fsync( file->fd ) != -1);
+    ret = (fsync( file->select.fd ) != -1);
     if (!ret) file_set_error();
     release_object( file );
     return ret;
@@ -323,13 +329,13 @@
     struct file *file = (struct file *)obj;
     assert( obj->ops == &file_ops );
 
-    if (fstat( file->fd, &st ) == -1)
+    if (fstat( file->select.fd, &st ) == -1)
     {
         file_set_error();
         return 0;
     }
     if (S_ISCHR(st.st_mode) || S_ISFIFO(st.st_mode) ||
-        S_ISSOCK(st.st_mode) || isatty(file->fd)) reply->type = FILE_TYPE_CHAR;
+        S_ISSOCK(st.st_mode) || isatty(file->select.fd)) reply->type = FILE_TYPE_CHAR;
     else reply->type = FILE_TYPE_DISK;
     if (S_ISDIR(st.st_mode)) reply->attr = FILE_ATTRIBUTE_DIRECTORY;
     else reply->attr = FILE_ATTRIBUTE_ARCHIVE;
@@ -360,7 +366,8 @@
         if (file->flags & FILE_FLAG_DELETE_ON_CLOSE) unlink( file->name );
         free( file->name );
     }
-    close( file->fd );
+    unregister_select_user( &file->select );
+    close( file->select.fd );
     free( file );
 }
 
@@ -397,7 +404,7 @@
 
 int file_get_mmap_fd( struct file *file )
 {
-    return dup( file->fd );
+    return dup( file->select.fd );
 }
 
 static int set_file_pointer( int handle, int *low, int *high, int whence )
@@ -414,7 +421,7 @@
 
     if (!(file = get_file_obj( current->process, handle, 0 )))
         return 0;
-    if ((result = lseek( file->fd, *low, whence )) == -1)
+    if ((result = lseek( file->select.fd, *low, whence )) == -1)
     {
         /* Check for seek before start of file */
         if ((errno == EINVAL) && (whence != SEEK_SET) && (*low < 0))
@@ -436,8 +443,8 @@
 
     if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
         return 0;
-    if (((result = lseek( file->fd, 0, SEEK_CUR )) == -1) ||
-        (ftruncate( file->fd, result ) == -1))
+    if (((result = lseek( file->select.fd, 0, SEEK_CUR )) == -1) ||
+        (ftruncate( file->select.fd, result ) == -1))
     {
         file_set_error();
         release_object( file );
@@ -458,13 +465,13 @@
         SET_ERROR( ERROR_INVALID_PARAMETER );
         return 0;
     }
-    if (fstat( file->fd, &st ) == -1)
+    if (fstat( file->select.fd, &st ) == -1)
     {
         file_set_error();
         return 0;
     }
     if (st.st_size >= size_low) return 1;  /* already large enough */
-    if (ftruncate( file->fd, size_low ) != -1) return 1;
+    if (ftruncate( file->select.fd, size_low ) != -1) return 1;
     file_set_error();
     return 0;
 }