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

diff --git a/server/console.c b/server/console.c
index d067c21..774e65f 100644
--- a/server/console.c
+++ b/server/console.c
@@ -33,7 +33,7 @@
 struct console_input
 {
     struct object         obj;           /* object header */
-    int                   fd;            /* Unix file descriptor */
+    struct select_user    select;        /* select user */
     int                   mode;          /* input mode */
     struct screen_buffer *output;        /* associated screen buffer */
     int                   recnum;        /* number of input records */
@@ -43,7 +43,7 @@
 struct screen_buffer
 {
     struct object         obj;           /* object header */
-    int                   fd;            /* Unix file descriptor */
+    struct select_user    select;        /* select user */
     int                   mode;          /* output mode */
     struct console_input *input;         /* associated console input */
     int                   cursor_size;   /* size of cursor (percentage filled) */
@@ -98,11 +98,6 @@
     screen_buffer_destroy
 };
 
-static const struct select_ops select_ops =
-{
-    default_select_event,
-    NULL   /* we never set a timeout on a console */
-};
 
 int create_console( int fd, struct object *obj[2] )
 {
@@ -136,19 +131,25 @@
     }
     init_object( &console_input->obj, &console_input_ops, NULL );
     init_object( &screen_buffer->obj, &screen_buffer_ops, NULL );
-    console_input->fd             = read_fd;
+    console_input->select.fd      = read_fd;
+    console_input->select.func    = default_select_event;
+    console_input->select.private = console_input;
     console_input->mode           = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
                                     ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
     console_input->output         = screen_buffer;
     console_input->recnum         = 0;
     console_input->records        = NULL;
-    screen_buffer->fd             = write_fd;
+    screen_buffer->select.fd      = write_fd;
+    screen_buffer->select.func    = default_select_event;
+    screen_buffer->select.private = screen_buffer;
     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
     screen_buffer->input          = console_input;
     screen_buffer->cursor_size    = 100;
     screen_buffer->cursor_visible = 1;
     screen_buffer->pid            = 0;
     screen_buffer->title          = strdup( "Wine console" );
+    register_select_user( &console_input->select );
+    register_select_user( &screen_buffer->select );
     CLEAR_ERROR();
     obj[0] = &console_input->obj;
     obj[1] = &screen_buffer->obj;
@@ -183,6 +184,10 @@
         return 0;
     }
 
+    /* can't change the fd if someone is waiting on it */
+    assert( !input->obj.head );
+    assert( !output->obj.head );
+
     if ((fd_in = dup(fd)) == -1)
     {
         file_set_error();
@@ -198,11 +203,15 @@
         release_object( output );
         return 0;
     }
-    close( input->fd );
-    close( output->fd );
-    input->fd = fd_in;
-    output->fd = fd_out;
-    output->pid = pid;
+    unregister_select_user( &input->select );
+    unregister_select_user( &output->select );
+    close( input->select.fd );
+    close( output->select.fd );
+    input->select.fd  = fd_in;
+    output->select.fd = fd_out;
+    output->pid       = pid;
+    register_select_user( &input->select );
+    register_select_user( &output->select );
     release_object( input );
     release_object( output );
     return 1;
@@ -346,7 +355,7 @@
 {
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
-    fprintf( stderr, "Console input fd=%d\n", console->fd );
+    fprintf( stderr, "Console input fd=%d\n", console->select.fd );
 }
 
 static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -354,13 +363,7 @@
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
     if (!obj->head)  /* first on the queue */
-    {
-        if (!add_select_user( console->fd, READ_EVENT, &select_ops, console ))
-        {
-            SET_ERROR( ERROR_OUTOFMEMORY );
-            return 0;
-        }
-    }
+        set_select_events( &console->select, READ_EVENT );
     add_queue( obj, entry );
     return 1;
 }
@@ -372,27 +375,34 @@
 
     remove_queue( obj, entry );
     if (!obj->head)  /* last on the queue is gone */
-        remove_select_user( console->fd );
+        set_select_events( &console->select, 0 );
     release_object( obj );
 }
 
 static int console_input_signaled( struct object *obj, struct thread *thread )
 {
-    fd_set fds;
-    struct timeval tv = { 0, 0 };
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
 
-    FD_ZERO( &fds );
-    FD_SET( console->fd, &fds );
-    return select( console->fd + 1, &fds, NULL, NULL, &tv ) > 0;
+    if (check_select_events( &console->select, READ_EVENT ))
+    {
+        /* stop waiting on select() if we are signaled */
+        set_select_events( &console->select, 0 );
+        return 1;
+    }
+    else
+    {
+        /* restart waiting on select() if we are no longer signaled */
+        if (obj->head) set_select_events( &console->select, READ_EVENT );
+        return 0;
+    }
 }
 
 static int console_input_get_read_fd( struct object *obj )
 {
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
-    return dup( console->fd );
+    return dup( console->select.fd );
 }
 
 static int console_get_info( struct object *obj, struct get_file_info_reply *reply )
@@ -406,7 +416,8 @@
 {
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
-    close( console->fd );
+    unregister_select_user( &console->select );
+    close( console->select.fd );
     if (console->output) console->output->input = NULL;
     free( console );
 }
@@ -415,7 +426,7 @@
 {
     struct screen_buffer *console = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
-    fprintf( stderr, "Console screen buffer fd=%d\n", console->fd );
+    fprintf( stderr, "Console screen buffer fd=%d\n", console->select.fd );
 }
 
 static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -423,13 +434,7 @@
     struct screen_buffer *console = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
     if (!obj->head)  /* first on the queue */
-    {
-        if (!add_select_user( console->fd, WRITE_EVENT, &select_ops, console ))
-        {
-            SET_ERROR( ERROR_OUTOFMEMORY );
-            return 0;
-        }
-    }
+        set_select_events( &console->select, WRITE_EVENT );
     add_queue( obj, entry );
     return 1;
 }
@@ -441,34 +446,42 @@
 
     remove_queue( obj, entry );
     if (!obj->head)  /* last on the queue is gone */
-        remove_select_user( console->fd );
+        set_select_events( &console->select, 0 );
     release_object( obj );
 }
 
 static int screen_buffer_signaled( struct object *obj, struct thread *thread )
 {
-    fd_set fds;
-    struct timeval tv = { 0, 0 };
     struct screen_buffer *console = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
 
-    FD_ZERO( &fds );
-    FD_SET( console->fd, &fds );
-    return select( console->fd + 1, NULL, &fds, NULL, &tv ) > 0;
+    if (check_select_events( &console->select, WRITE_EVENT ))
+    {
+        /* stop waiting on select() if we are signaled */
+        set_select_events( &console->select, 0 );
+        return 1;
+    }
+    else
+    {
+        /* restart waiting on select() if we are no longer signaled */
+        if (obj->head) set_select_events( &console->select, WRITE_EVENT );
+        return 0;
+    }
 }
 
 static int screen_buffer_get_write_fd( struct object *obj )
 {
     struct screen_buffer *console = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
-    return dup( console->fd );
+    return dup( console->select.fd );
 }
 
 static void screen_buffer_destroy( struct object *obj )
 {
     struct screen_buffer *console = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
-    close( console->fd );
+    unregister_select_user( &console->select );
+    close( console->select.fd );
     if (console->input) console->input->output = NULL;
     if (console->pid) kill( console->pid, SIGTERM );
     if (console->title) free( console->title );
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;
 }
diff --git a/server/pipe.c b/server/pipe.c
index 575f6f2..368c782 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -26,10 +26,10 @@
 
 struct pipe
 {
-    struct object obj;             /* object header */
-    struct pipe  *other;           /* the pipe other end */
-    int           fd;              /* Unix file descriptor */
-    enum side     side;            /* which side of the pipe is this */
+    struct object       obj;         /* object header */
+    struct pipe        *other;       /* the pipe other end */
+    struct select_user  select;      /* select user */
+    enum side           side;        /* which side of the pipe is this */
 };
 
 static void pipe_dump( struct object *obj, int verbose );
@@ -55,11 +55,6 @@
     pipe_destroy
 };
 
-static const struct select_ops select_ops =
-{
-    default_select_event,
-    NULL   /* we never set a timeout on a pipe */
-};
 
 static int create_pipe( struct object *obj[2] )
 {
@@ -86,14 +81,20 @@
     }
     init_object( &newpipe[0]->obj, &pipe_ops, NULL );
     init_object( &newpipe[1]->obj, &pipe_ops, NULL );
-    newpipe[0]->fd    = fd[0];
-    newpipe[0]->other = newpipe[1];
-    newpipe[0]->side  = READ_SIDE;
-    newpipe[1]->fd    = fd[1];
-    newpipe[1]->other = newpipe[0];
-    newpipe[1]->side  = WRITE_SIDE;
+    newpipe[0]->select.fd      = fd[0];
+    newpipe[0]->select.func    = default_select_event;
+    newpipe[0]->select.private = newpipe[0];
+    newpipe[0]->other          = newpipe[1];
+    newpipe[0]->side           = READ_SIDE;
+    newpipe[1]->select.fd      = fd[1];
+    newpipe[1]->select.func    = default_select_event;
+    newpipe[1]->select.private = newpipe[1];
+    newpipe[1]->other          = newpipe[0];
+    newpipe[1]->side           = WRITE_SIDE;
     obj[0] = &newpipe[0]->obj;
     obj[1] = &newpipe[1]->obj;
+    register_select_user( &newpipe[0]->select );
+    register_select_user( &newpipe[1]->select );
     CLEAR_ERROR();
     return 1;
 }
@@ -103,7 +104,7 @@
     struct pipe *pipe = (struct pipe *)obj;
     assert( obj->ops == &pipe_ops );
     fprintf( stderr, "Pipe %s-side fd=%d\n",
-             (pipe->side == READ_SIDE) ? "read" : "write", pipe->fd );
+             (pipe->side == READ_SIDE) ? "read" : "write", pipe->select.fd );
 }
 
 static int pipe_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -111,15 +112,8 @@
     struct pipe *pipe = (struct pipe *)obj;
     assert( obj->ops == &pipe_ops );
     if (!obj->head)  /* first on the queue */
-    {
-        if (!add_select_user( pipe->fd,
-                              (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT,
-                              &select_ops, pipe ))
-        {
-            SET_ERROR( ERROR_OUTOFMEMORY );
-            return 0;
-        }
-    }
+        set_select_events( &pipe->select,
+                           (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT );
     add_queue( obj, entry );
     return 1;
 }
@@ -131,23 +125,29 @@
 
     remove_queue( obj, entry );
     if (!obj->head)  /* last on the queue is gone */
-        remove_select_user( pipe->fd );
+        set_select_events( &pipe->select, 0 );
     release_object( obj );
 }
 
 static int pipe_signaled( struct object *obj, struct thread *thread )
 {
+    int event;
     struct pipe *pipe = (struct pipe *)obj;
-    struct timeval tv = { 0, 0 };
-    fd_set fds;
-
     assert( obj->ops == &pipe_ops );
-    FD_ZERO( &fds );
-    FD_SET( pipe->fd, &fds );
-    if (pipe->side == READ_SIDE)
-        return select( pipe->fd + 1, &fds, NULL, NULL, &tv ) > 0;
+
+    event = (pipe->side == READ_SIDE) ? READ_EVENT : WRITE_EVENT;
+    if (check_select_events( &pipe->select, event ))
+    {
+        /* stop waiting on select() if we are signaled */
+        set_select_events( &pipe->select, 0 );
+        return 1;
+    }
     else
-        return select( pipe->fd + 1, NULL, &fds, NULL, &tv ) > 0;
+    {
+        /* restart waiting on select() if we are no longer signaled */
+        if (obj->head) set_select_events( &pipe->select, event );
+        return 0;
+    }
 }
 
 static int pipe_get_read_fd( struct object *obj )
@@ -165,7 +165,7 @@
         SET_ERROR( ERROR_ACCESS_DENIED );
         return -1;
     }
-    return dup( pipe->fd );
+    return dup( pipe->select.fd );
 }
 
 static int pipe_get_write_fd( struct object *obj )
@@ -183,7 +183,7 @@
         SET_ERROR( ERROR_ACCESS_DENIED );
         return -1;
     }
-    return dup( pipe->fd );
+    return dup( pipe->select.fd );
 }
 
 static int pipe_get_info( struct object *obj, struct get_file_info_reply *reply )
@@ -199,7 +199,8 @@
     assert( obj->ops == &pipe_ops );
 
     if (pipe->other) pipe->other->other = NULL;
-    close( pipe->fd );
+    unregister_select_user( &pipe->select );
+    close( pipe->select.fd );
     free( pipe );
 }
 
diff --git a/server/thread.c b/server/thread.c
index eff2b08..d4fea46 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -40,6 +40,7 @@
     int                     count;      /* count of objects */
     int                     flags;
     struct timeval          timeout;
+    struct timeout_user    *user;
     struct wait_queue_entry queues[1];
 };
 
@@ -80,21 +81,23 @@
 static void init_thread( struct thread *thread, int fd )
 {
     init_object( &thread->obj, &thread_ops, NULL );
-    thread->client_fd = fd;
-    thread->unix_pid  = 0;  /* not known yet */
-    thread->mutex     = NULL;
-    thread->debugger  = NULL;
-    thread->wait      = NULL;
-    thread->apc       = NULL;
-    thread->apc_count = 0;
-    thread->error     = 0;
-    thread->state     = STARTING;
-    thread->exit_code = 0x103;  /* STILL_ACTIVE */
-    thread->next      = NULL;
-    thread->prev      = NULL;
-    thread->priority  = THREAD_PRIORITY_NORMAL;
-    thread->affinity  = 1;
-    thread->suspend   = 0;
+    thread->client      = NULL;
+    thread->unix_pid    = 0;  /* not known yet */
+    thread->teb         = NULL;
+    thread->mutex       = NULL;
+    thread->debug_ctx   = NULL;
+    thread->debug_first = NULL;
+    thread->wait        = NULL;
+    thread->apc         = NULL;
+    thread->apc_count   = 0;
+    thread->error       = 0;
+    thread->state       = STARTING;
+    thread->exit_code   = 0x103;  /* STILL_ACTIVE */
+    thread->next        = NULL;
+    thread->prev        = NULL;
+    thread->priority    = THREAD_PRIORITY_NORMAL;
+    thread->affinity    = 1;
+    thread->suspend     = 0;
 }
 
 /* create the initial thread and start the main server loop */
@@ -104,7 +107,7 @@
     init_thread( &initial_thread, fd );
     initial_thread.process = create_initial_process(); 
     add_process_thread( initial_thread.process, &initial_thread );
-    add_client( fd, &initial_thread );
+    initial_thread.client = add_client( fd, &initial_thread );
     grab_object( &initial_thread ); /* so that we never free it */
     select_loop();
 }
@@ -134,7 +137,7 @@
 
     if ((*handle = alloc_handle( current->process, thread,
                                  THREAD_ALL_ACCESS, inherit )) == -1) goto error;
-    if (add_client( fd, thread ) == -1)
+    if (!(thread->client = add_client( fd, thread )))
     {
         SET_ERROR( ERROR_TOO_MANY_OPEN_FILES );
         goto error;
@@ -169,8 +172,8 @@
     struct thread *thread = (struct thread *)obj;
     assert( obj->ops == &thread_ops );
 
-    fprintf( stderr, "Thread pid=%d fd=%d\n",
-             thread->unix_pid, thread->client_fd );
+    fprintf( stderr, "Thread pid=%d teb=%p client=%p\n",
+             thread->unix_pid, thread->teb, thread->client );
 }
 
 static int thread_signaled( struct object *obj, struct thread *thread )
@@ -214,7 +217,7 @@
     int old_count = thread->suspend;
     if (thread->suspend < MAXIMUM_SUSPEND_COUNT)
     {
-        if (!thread->suspend++)
+        if (!(thread->process->suspend + thread->suspend++))
         {
             if (thread->unix_pid) kill( thread->unix_pid, SIGSTOP );
         }
@@ -228,7 +231,7 @@
     int old_count = thread->suspend;
     if (thread->suspend > 0)
     {
-        if (!--thread->suspend)
+        if (!(--thread->suspend + thread->process->suspend))
         {
             if (thread->unix_pid) kill( thread->unix_pid, SIGCONT );
         }
@@ -270,7 +273,7 @@
         vec[i].iov_len  = va_arg( args, int );
     }
     va_end( args );
-    return send_reply_v( thread->client_fd, thread->error, pass_fd, vec, n );
+    return send_reply_v( thread->client, thread->error, pass_fd, vec, n );
 }
 
 /* add a thread to an object wait queue; return 1 if OK, 0 on error */
@@ -306,7 +309,7 @@
     assert( wait );
     for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
         entry->obj->ops->remove_queue( entry->obj, entry );
-    if (wait->flags & SELECT_TIMEOUT) set_select_timeout( thread->client_fd, NULL );
+    if (wait->user) remove_timeout_user( wait->user );
     free( wait );
     thread->wait = NULL;
 }
@@ -329,20 +332,8 @@
     thread->wait  = wait;
     wait->count   = count;
     wait->flags   = flags;
-    if (flags & SELECT_TIMEOUT)
-    {
-        gettimeofday( &wait->timeout, 0 );
-        if (timeout)
-        {
-            wait->timeout.tv_usec += (timeout % 1000) * 1000;
-            if (wait->timeout.tv_usec >= 1000000)
-            {
-                wait->timeout.tv_usec -= 1000000;
-                wait->timeout.tv_sec++;
-            }
-            wait->timeout.tv_sec += timeout / 1000;
-        }
-    }
+    wait->user    = NULL;
+    if (flags & SELECT_TIMEOUT) make_timeout( &wait->timeout, timeout );
 
     for (i = 0, entry = wait->queues; i < count; i++, entry++)
     {
@@ -375,8 +366,12 @@
     assert( wait );
     if (wait->flags & SELECT_ALL)
     {
+        int not_ok = 0;
+        /* Note: we must check them all anyway, as some objects may
+         * want to do something when signaled, even if others are not */
         for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
-            if (!entry->obj->ops->signaled( entry->obj, thread )) goto other_checks;
+            not_ok |= !entry->obj->ops->signaled( entry->obj, thread );
+        if (not_ok) goto other_checks;
         /* Wait satisfied: tell it to all objects */
         *signaled = 0;
         for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
@@ -458,11 +453,15 @@
         send_select_reply( thread, -1 );
         return;
     }
-    if (!wake_thread( thread ))
+    if (wake_thread( thread )) return;
+    /* now we need to wait */
+    if (flags & SELECT_TIMEOUT)
     {
-        /* we need to wait */
-        if (flags & SELECT_TIMEOUT)
-            set_select_timeout( thread->client_fd, &thread->wait->timeout );
+        if (!(thread->wait->user = add_timeout_user( &thread->wait->timeout,
+                                                     call_timeout_handler, thread )))
+        {
+            send_select_reply( thread, -1 );
+        }
     }
 }
 
@@ -470,6 +469,7 @@
 void thread_timeout(void)
 {
     assert( current->wait );
+    current->wait->user = NULL;
     end_wait( current );
     send_select_reply( current, STATUS_TIMEOUT );
 }
@@ -513,7 +513,7 @@
 {
     if (thread->state == TERMINATED) return;  /* already killed */
     if (thread->unix_pid) kill( thread->unix_pid, SIGTERM );
-    remove_client( thread->client_fd, exit_code ); /* this will call thread_killed */
+    remove_client( thread->client, exit_code ); /* this will call thread_killed */
 }
 
 /* a thread has been killed */
@@ -558,7 +558,9 @@
     }
     current->state    = RUNNING;
     current->unix_pid = req->unix_pid;
-    if (current->suspend > 0) kill( current->unix_pid, SIGSTOP );
+    current->teb      = req->teb;
+    if (current->suspend + current->process->suspend > 0)
+        kill( current->unix_pid, SIGSTOP );
     reply.pid = current->process;
     reply.tid = current;
     send_reply( current, -1, 1, &reply, sizeof(reply) );
diff --git a/server/thread.h b/server/thread.h
index fed1d18..cffe255 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -19,7 +19,7 @@
 struct thread_wait;
 struct thread_apc;
 struct mutex;
-struct debugger;
+struct debug_ctx;
 
 enum run_state { STARTING, RUNNING, TERMINATED };
 
@@ -31,16 +31,18 @@
     struct thread      *proc_next; /* per-process thread list */
     struct thread      *proc_prev;
     struct process     *process;
-    struct mutex       *mutex;     /* list of currently owned mutexes */
-    struct debugger    *debugger;  /* debugger info if this thread is a debugger */
+    struct mutex       *mutex;       /* list of currently owned mutexes */
+    struct debug_ctx   *debug_ctx;   /* debugger context if this thread is a debugger */
+    struct process     *debug_first; /* head of debugged processes list */
     struct thread_wait *wait;      /* current wait condition if sleeping */
     struct thread_apc  *apc;       /* list of async procedure calls */
     int                 apc_count; /* number of outstanding APCs */
     int                 error;     /* current error code */
     enum run_state      state;     /* running state */
     int                 exit_code; /* thread exit code */
-    int                 client_fd; /* client fd for socket communications */
+    struct client      *client;    /* client for socket communications */
     int                 unix_pid;  /* Unix pid of client */
+    void               *teb;       /* TEB address (in client address space) */
     int                 priority;  /* priority level */
     int                 affinity;  /* affinity mask */
     int                 suspend;   /* suspend count */