Moved all references to file descriptors out of the generic object
structure.
Changed the poll()-related routines to deal with file descriptors
instead of objects and integrated poll support into fd.c.

diff --git a/server/Makefile.in b/server/Makefile.in
index bfdc29b..6e4daa9 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -31,7 +31,6 @@
 	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 2249fa1..039833e 100644
--- a/server/async.c
+++ b/server/async.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 
 #include "handle.h"
+#include "file.h"
 #include "thread.h"
 #include "request.h"
 
diff --git a/server/atom.c b/server/atom.c
index 78378cf..e14c05e 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -101,7 +101,7 @@
 {
     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 0edb34b..b1e69e0 100644
--- a/server/change.c
+++ b/server/change.c
@@ -54,7 +54,7 @@
 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 4dbdc37..a907227 100644
--- a/server/console.c
+++ b/server/console.c
@@ -199,7 +199,7 @@
 {
     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 @@
 {
     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 @@
     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 200c692..fdd7461 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -374,7 +374,7 @@
     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 @@
 
     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 7e06b99..1a63712 100644
--- a/server/device.c
+++ b/server/device.c
@@ -59,7 +59,7 @@
 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 6c2a49a..388c807 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -22,9 +22,15 @@
 #include "config.h"
 
 #include <assert.h>
+#include <signal.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "object.h"
@@ -40,6 +46,7 @@
     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 @@
     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_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 @@
 /* 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 @@
 /* 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 @@
 
     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 7518a09..2544bba 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 @@
 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 @@
     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 @@
 {
     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 @@
             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 @@
 {
     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 @@
     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 @@
         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 @@
 
 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 351c62e..55fc3a4 100644
--- a/server/file.h
+++ b/server/file.h
@@ -42,13 +42,12 @@
 
 /* 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 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 6fa8f71..4a2b4ef 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -154,7 +154,7 @@
     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 b69b1cc..83b540b 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -79,7 +79,7 @@
     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 032cb65..0089c35 100644
--- a/server/main.c
+++ b/server/main.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 
 #include "object.h"
+#include "file.h"
 #include "thread.h"
 #include "request.h"
 
@@ -126,7 +127,7 @@
 
     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 4c39034..26180d4 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -50,6 +50,7 @@
 };
 
 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 @@
     NULL,                        /* remove_queue */
     NULL,                        /* signaled */
     NULL,                        /* satisfied */
-    default_get_fd,              /* get_fd */
+    mapping_get_fd,              /* get_fd */
     mapping_destroy              /* destroy */
 };
 
@@ -190,8 +191,7 @@
 
     /* 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 @@
 
     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 @@
         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 @@
     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 29c7614..b1e2e66 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -61,6 +61,7 @@
 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 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 @@
     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 @@
     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 @@
 
     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 @@
     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 @@
     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 @@
         pipe->pipemode = req->pipemode;
     }
 
-    user = create_pipe_user (pipe, -1);
+    user = create_pipe_user( pipe );
 
     if(user)
     {
@@ -307,54 +339,46 @@
 
 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 @@
         {
             notify_waiter(partner,STATUS_SUCCESS);
             release_object(partner);
-            release_object(partner);
         }
     }
 
@@ -391,44 +414,35 @@
 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 @@
     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 20fa232..8ad76fc 100644
--- a/server/object.c
+++ b/server/object.c
@@ -131,32 +131,21 @@
 }
 
 /* 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 @@
     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 @@
         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 @@
         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 @@
     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 54d082f..c72b873 100644
--- a/server/object.h
+++ b/server/object.h
@@ -67,9 +67,6 @@
 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 @@
 
 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 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 79074e5..3e01ee9 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -42,6 +42,7 @@
 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 @@
 {
     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 @@
     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 @@
         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 @@
     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 5d808dc..d616d42 100644
--- a/server/process.c
+++ b/server/process.c
@@ -263,13 +263,14 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     }
 
     /* 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 55bda89..cd65153 100644
--- a/server/process.h
+++ b/server/process.h
@@ -56,6 +56,7 @@
     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 32caefe..48edb23 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 @@
 {
     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 @@
     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 2262f59..b766308 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -434,7 +434,7 @@
 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 d13c761..a47827b 100644
--- a/server/request.c
+++ b/server/request.c
@@ -73,11 +73,13 @@
 
 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 @@
     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 @@
 {
     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 @@
             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 @@
 
     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 @@
         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( &current->obj, current->reply_fd, POLLOUT );
+            set_fd_events( current->reply_fd, POLLOUT );
+            set_fd_events( current->request_fd, 0 );
             return;
         }
     }
@@ -286,7 +291,7 @@
 
     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 @@
     /* 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 @@
     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 @@
     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 @@
 {
     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 @@
     {
         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 @@
     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 @@
     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 @@
 /* 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 f02e917..0000000
--- 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 <assert.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#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 06b07cb..2f9130b 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 @@
 struct serial
 {
     struct object       obj;
+    struct fd          *fd;
     unsigned int        access;
     unsigned int        attrib;
 
@@ -93,7 +95,7 @@
     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 @@
        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 @@
         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 @@
     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 @@
     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 @@
     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 4bb7774..ef94dd5 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 @@
 struct smb
 {
     struct object       obj;
+    struct fd          *fd;
     unsigned int        tree_id;
     unsigned int        user_id;
     unsigned int        dialect;
@@ -75,7 +77,7 @@
     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 @@
     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 @@
         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 @@
         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 8a65ef5..fda8355 100644
--- a/server/snapshot.c
+++ b/server/snapshot.c
@@ -79,7 +79,7 @@
         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 44e0088..51d7ec7 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 @@
 
 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 @@
     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 @@
 
 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 @@
    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 @@
     {
         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 @@
     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 @@
     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 @@
     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 @@
         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 @@
         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 @@
     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 @@
          * 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 @@
         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 @@
         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 8b3ca12..1c8dbce 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -127,8 +127,9 @@
     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 *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 @@
         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 @@
     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 @@
     }
     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 @@
 
     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 @@
     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 @@
         fatal_protocol_error( current, "bad wait fd\n" );
         goto error;
     }
+    current->reply_fd = alloc_fd( &thread_fd_ops, reply_fd, &current->obj );
+    current->wait_fd  = alloc_fd( &thread_fd_ops, wait_fd, &current->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 cc37f25..314ceab 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -81,9 +81,9 @@
     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 22e4e79..4ca7793 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -28,6 +28,8 @@
 #include <sys/types.h>
 
 #include "windef.h"
+
+#include "file.h"
 #include "handle.h"
 #include "request.h"