Use a separate FIFO pair for server requests that don't need to pass a
file descriptor.
Associate file descriptors with handles on the server side so that we
don't need to pass the fd every time the client wants to use it.

diff --git a/server/console.c b/server/console.c
index 6f72ade..dcdc287 100644
--- a/server/console.c
+++ b/server/console.c
@@ -419,7 +419,7 @@
         if ((out = alloc_handle( current->process, current->process->console_out,
                                  req->access, req->inherit )) != -1)
             goto done;  /* everything is fine */
-        close_handle( current->process, in );
+        close_handle( current->process, in, NULL );
         in = -1;
     }
     free_console( current->process );
diff --git a/server/debugger.c b/server/debugger.c
index c88f82e..7f84410 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -118,7 +118,7 @@
     /* documented: THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME */
     if ((handle = alloc_handle( debugger, thread, THREAD_ALL_ACCESS, FALSE )) == -1)
     {
-        close_handle( debugger, event->data.info.create_process.process );
+        close_handle( debugger, event->data.info.create_process.process, NULL );
         return 0;
     }
     event->data.info.create_process.thread = handle;
@@ -128,8 +128,8 @@
         /* the doc says write access too, but this doesn't seem a good idea */
         ((handle = alloc_handle( debugger, process->exe.file, GENERIC_READ, FALSE )) == -1))
     {
-        close_handle( debugger, event->data.info.create_process.process );
-        close_handle( debugger, event->data.info.create_process.thread );
+        close_handle( debugger, event->data.info.create_process.process, NULL );
+        close_handle( debugger, event->data.info.create_process.thread, NULL );
         return 0;
     }
     event->data.info.create_process.file       = handle;
@@ -316,17 +316,17 @@
         switch(event->data.code)
         {
         case CREATE_THREAD_DEBUG_EVENT:
-            close_handle( debugger, event->data.info.create_thread.handle );
+            close_handle( debugger, event->data.info.create_thread.handle, NULL );
             break;
         case CREATE_PROCESS_DEBUG_EVENT:
             if (event->data.info.create_process.file != -1)
-                close_handle( debugger, event->data.info.create_process.file );
-            close_handle( debugger, event->data.info.create_process.thread );
-            close_handle( debugger, event->data.info.create_process.process );
+                close_handle( debugger, event->data.info.create_process.file, NULL );
+            close_handle( debugger, event->data.info.create_process.thread, NULL );
+            close_handle( debugger, event->data.info.create_process.process, NULL );
             break;
         case LOAD_DLL_DEBUG_EVENT:
             if (event->data.info.load_dll.handle != -1)
-                close_handle( debugger, event->data.info.load_dll.handle );
+                close_handle( debugger, event->data.info.load_dll.handle, NULL );
             break;
         }
     }
diff --git a/server/file.c b/server/file.c
index 5c0f59a..e0ce8a7 100644
--- a/server/file.c
+++ b/server/file.c
@@ -325,11 +325,6 @@
     return (struct file *)get_handle_obj( process, handle, access, &file_ops );
 }
 
-int file_get_mmap_fd( struct file *file )
-{
-    return dup( file->obj.fd );
-}
-
 static int set_file_pointer( int handle, int *low, int *high, int whence )
 {
     struct file *file;
@@ -479,7 +474,8 @@
     req->fd = -1;
     if ((obj = get_handle_obj( current->process, req->handle, req->access, NULL )))
     {
-        set_reply_fd( current, obj->ops->get_fd( obj ) );
+        if ((req->fd = get_handle_fd( current->process, req->handle, req->access )) == -1)
+            send_client_fd( current, obj->ops->get_fd( obj ), req->handle );
         release_object( obj );
     }
 }
diff --git a/server/handle.c b/server/handle.c
index 1d1317f..6a3e1f6 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -19,8 +19,9 @@
 
 struct handle_entry
 {
-    struct object *ptr;
-    unsigned int   access;
+    struct object *ptr;       /* object */
+    unsigned int   access;    /* access rights */
+    int            fd;        /* file descriptor (in client process) */
 };
 
 struct handle_table
@@ -173,6 +174,7 @@
     table->free = i + 1;
     entry->ptr    = grab_object( obj );
     entry->access = access;
+    entry->fd     = -1;
     return index_to_handle(i);
 }
 
@@ -269,6 +271,7 @@
         for (i = 0; i <= table->last; i++, ptr++)
         {
             if (!ptr->ptr) continue;
+            ptr->fd = -1;
             if (ptr->access & RESERVED_INHERIT) grab_object( ptr->ptr );
             else ptr->ptr = NULL; /* don't inherit this entry */
         }
@@ -280,7 +283,7 @@
 
 /* close a handle and decrement the refcount of the associated object */
 /* return 1 if OK, 0 on error */
-int close_handle( struct process *process, int handle )
+int close_handle( struct process *process, int handle, int *fd )
 {
     struct handle_table *table;
     struct handle_entry *entry;
@@ -294,6 +297,9 @@
     }
     obj = entry->ptr;
     entry->ptr = NULL;
+    if (fd) *fd = entry->fd;
+    else if (entry->fd != -1) return 1;  /* silently ignore close attempt if we cannot close the fd */
+    entry->fd = -1;
     table = HANDLE_IS_GLOBAL(handle) ? global_table : (struct handle_table *)process->handles;
     if (entry < table->entries + table->free) table->free = entry - table->entries;
     if (entry == table->entries + table->last) shrink_handle_table( table );
@@ -351,12 +357,28 @@
     return grab_object( obj );
 }
 
-/* get/set the handle reserved flags */
-/* return the new flags (or -1 on error) */
-static int set_handle_info( struct process *process, int handle, int mask, int flags )
+/* retrieve the cached fd for a given handle */
+int get_handle_fd( struct process *process, int handle, unsigned int access )
 {
     struct handle_entry *entry;
 
+    if (HANDLE_IS_GLOBAL(handle)) return -1;  /* no fd cache for global handles */
+    if (!(entry = get_handle( process, handle ))) return -1;
+    if ((entry->access & access) != access)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return -1;
+    }
+    return entry->fd;
+}
+
+/* get/set the handle reserved flags */
+/* return the old flags (or -1 on error) */
+static int set_handle_info( struct process *process, int handle, int mask, int flags, int *fd )
+{
+    struct handle_entry *entry;
+    unsigned int old_access;
+
     if (get_magic_handle( handle ))
     {
         /* we can retrieve but not set info for magic handles */
@@ -364,10 +386,14 @@
         return 0;
     }
     if (!(entry = get_handle( process, handle ))) return -1;
+    old_access = entry->access;
     mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
     flags = (flags << RESERVED_SHIFT) & mask;
     entry->access = (entry->access & ~mask) | flags;
-    return (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
+    /* if no current fd set it, otherwise return current fd */
+    if (entry->fd == -1) entry->fd = *fd;
+    *fd = entry->fd;
+    return (old_access & RESERVED_ALL) >> RESERVED_SHIFT;
 }
 
 /* duplicate a handle */
@@ -420,19 +446,17 @@
 /* close a handle */
 DECL_HANDLER(close_handle)
 {
-    close_handle( current->process, req->handle );
-}
-
-/* get information about a handle */
-DECL_HANDLER(get_handle_info)
-{
-    req->flags = set_handle_info( current->process, req->handle, 0, 0 );
+    close_handle( current->process, req->handle, &req->fd );
 }
 
 /* set a handle information */
 DECL_HANDLER(set_handle_info)
 {
-    set_handle_info( current->process, req->handle, req->mask, req->flags );
+    int fd = req->fd;
+
+    if (HANDLE_IS_GLOBAL(req->handle)) fd = -1;  /* no fd cache for global handles */
+    req->old_flags = set_handle_info( current->process, req->handle, req->mask, req->flags, &fd );
+    req->cur_fd = fd;
 }
 
 /* duplicate a handle */
@@ -441,6 +465,7 @@
     struct process *src, *dst;
 
     req->handle = -1;
+    req->fd = -1;
     if ((src = get_process_from_handle( req->src_process, PROCESS_DUP_HANDLE )))
     {
         if (req->options & DUP_HANDLE_MAKE_GLOBAL)
@@ -456,7 +481,10 @@
         }
         /* close the handle no matter what happened */
         if (req->options & DUP_HANDLE_CLOSE_SOURCE)
-            close_handle( src, req->src_handle );
+        {
+            if (src == current->process) close_handle( src, req->src_handle, &req->fd );
+            else close_handle( src, req->src_handle, NULL );
+        }
         release_object( src );
     }
 }
diff --git a/server/handle.h b/server/handle.h
index 7bba30b..d648dd7 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -23,9 +23,10 @@
 /* that the thing pointed to starts with a struct object... */
 extern int alloc_handle( struct process *process, void *obj,
                          unsigned int access, int inherit );
-extern int close_handle( struct process *process, int handle );
+extern int close_handle( struct process *process, int handle, int *fd );
 extern struct object *get_handle_obj( struct process *process, int handle,
                                       unsigned int access, const struct object_ops *ops );
+extern int get_handle_fd( struct process *process, int handle, unsigned int access );
 extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
                              unsigned int access, int inherit, int options );
 extern int open_object( const WCHAR *name, size_t len, const struct object_ops *ops,
diff --git a/server/mapping.c b/server/mapping.c
index a68e8fb..38d1d89 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -30,6 +30,7 @@
     int            shared_size;     /* shared mapping total size */
 };
 
+static int mapping_get_fd( struct object *obj );
 static void mapping_dump( struct object *obj, int verbose );
 static void mapping_destroy( struct object *obj );
 
@@ -43,7 +44,7 @@
     NULL,                        /* satisfied */
     NULL,                        /* get_poll_events */
     NULL,                        /* poll_event */
-    no_get_fd,                   /* get_fd */
+    mapping_get_fd,              /* get_fd */
     no_flush,                    /* flush */
     no_get_file_info,            /* get_file_info */
     mapping_destroy              /* destroy */
@@ -86,6 +87,13 @@
 #define ROUND_SIZE(addr,size) \
    (((int)(size) + ((int)(addr) & page_mask) + page_mask) & ~page_mask)
 
+/* get the fd to use for mmaping a file */
+inline static int get_mmap_fd( struct file *file )
+{
+    struct object *obj;
+    if (!(obj = (struct object *)file)) return -1;
+    return obj->ops->get_fd( obj );
+}
 
 /* allocate and fill the temp file for a shared PE image mapping */
 static int build_shared_mapping( struct mapping *mapping, int fd,
@@ -115,7 +123,7 @@
 
     if (!(mapping->shared_file = create_temp_file( GENERIC_READ|GENERIC_WRITE ))) goto error;
     if (!grow_file( mapping->shared_file, 0, total_size )) goto error;
-    if ((shared_fd = file_get_mmap_fd( mapping->shared_file )) == -1) goto error;
+    if ((shared_fd = get_mmap_fd( mapping->shared_file )) == -1) goto error;
 
     if (!(buffer = malloc( max_size ))) goto error;
 
@@ -159,7 +167,7 @@
 
     /* load the headers */
 
-    if ((fd = file_get_mmap_fd( mapping->file )) == -1) return 0;
+    if ((fd = get_mmap_fd( mapping->file )) == -1) return 0;
     filepos = lseek( fd, 0, SEEK_SET );
     if (read( fd, &dos, sizeof(dos) ) != sizeof(dos)) goto error;
     if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto error;
@@ -270,6 +278,13 @@
     fputc( '\n', stderr );
 }
 
+static int mapping_get_fd( struct object *obj )
+{
+    struct mapping *mapping = (struct mapping *)obj;
+    assert( obj->ops == &mapping_ops );
+    return get_mmap_fd( mapping->file );
+}
+
 static void mapping_destroy( struct object *obj )
 {
     struct mapping *mapping = (struct mapping *)obj;
@@ -323,11 +338,10 @@
         req->base        = mapping->base;
         req->shared_file = -1;
         req->shared_size = mapping->shared_size;
+        req->anonymous   = !mapping->file;
         if (mapping->shared_file)
             req->shared_file = alloc_handle( current->process, mapping->shared_file,
                                              GENERIC_READ|GENERIC_WRITE, 0 );
-        if (mapping->file) set_reply_fd( current, file_get_mmap_fd( mapping->file ) );
         release_object( mapping );
     }
 }
-
diff --git a/server/object.h b/server/object.h
index 7a7d1a3..deec306 100644
--- a/server/object.h
+++ b/server/object.h
@@ -148,7 +148,6 @@
 
 extern struct file *get_file_obj( struct process *process, int handle,
                                   unsigned int access );
-extern int file_get_mmap_fd( struct file *file );
 extern int grow_file( struct file *file, int size_high, int size_low );
 extern int create_anonymous_file(void);
 extern struct file *create_temp_file( int access );
diff --git a/server/pipe.c b/server/pipe.c
index 5c830c0..7838c12 100644
--- a/server/pipe.c
+++ b/server/pipe.c
@@ -165,7 +165,7 @@
                                    STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|GENERIC_WRITE,
                                    req->inherit );
             if (hwrite == -1)
-                close_handle( current->process, hread );
+                close_handle( current->process, hread, NULL );
         }
         release_object( obj[0] );
         release_object( obj[1] );
diff --git a/server/request.c b/server/request.c
index c3928e5..fff02dd4 100644
--- a/server/request.c
+++ b/server/request.c
@@ -71,6 +71,32 @@
 };
 
 
+struct request_socket
+{
+    struct object       obj;         /* object header */
+    struct thread      *thread;      /* owning thread */
+};
+
+static void request_socket_dump( struct object *obj, int verbose );
+static void request_socket_poll_event( struct object *obj, int event );
+
+static const struct object_ops request_socket_ops =
+{
+    sizeof(struct request_socket), /* size */
+    request_socket_dump,           /* dump */
+    no_add_queue,                  /* add_queue */
+    NULL,                          /* remove_queue */
+    NULL,                          /* signaled */
+    NULL,                          /* satisfied */
+    NULL,                          /* get_poll_events */
+    request_socket_poll_event,     /* poll_event */
+    no_get_fd,                     /* get_fd */
+    no_flush,                      /* flush */
+    no_get_file_info,              /* get_file_info */
+    no_destroy                     /* destroy */
+};
+
+
 struct thread *current = NULL;  /* thread handling the current request */
 unsigned int global_error = 0;  /* global error code for when no thread is current */
 
@@ -149,13 +175,6 @@
     fatal_protocol_error( current, "bad request %d\n", req );
 }
 
-/* set the fd to pass to the thread */
-void set_reply_fd( struct thread *thread, int pass_fd )
-{
-    assert( thread->pass_fd == -1 );
-    thread->pass_fd = pass_fd;
-}
-
 /* send a reply to a thread */
 void send_reply( struct thread *thread )
 {
@@ -213,29 +232,9 @@
 
     header->error = thread->error;
 
-    if (thread->pass_fd == -1)
-    {
-        /* write a single byte; the value is ignored anyway */
-        ret = write( thread->obj.fd, header, 1 );
-    }
-    else  /* we have an fd to send */
-    {
-#ifdef HAVE_MSGHDR_ACCRIGHTS
-        msghdr.msg_accrightslen = sizeof(int);
-        msghdr.msg_accrights = (void *)&thread->pass_fd;
-#else  /* HAVE_MSGHDR_ACCRIGHTS */
-        msghdr.msg_control    = &cmsg;
-        msghdr.msg_controllen = sizeof(cmsg);
-        cmsg.fd = thread->pass_fd;
-#endif  /* HAVE_MSGHDR_ACCRIGHTS */
+    assert (thread->pass_fd == -1);
 
-        myiovec.iov_base = (void *)header;
-        myiovec.iov_len  = 1;
-
-        ret = sendmsg( thread->obj.fd, &msghdr, 0 );
-        close( thread->pass_fd );
-        thread->pass_fd = -1;
-    }
+    ret = write( thread->reply_fd, header, 1 );
     if (ret > 0)
     {
         set_select_events( &thread->obj, POLLIN );
@@ -255,6 +254,40 @@
     return -1;
 }
 
+/* send an fd to a client */
+int send_client_fd( struct thread *thread, int fd, int handle )
+{
+    int ret;
+
+#ifdef HAVE_MSGHDR_ACCRIGHTS
+    msghdr.msg_accrightslen = sizeof(fd);
+    msghdr.msg_accrights = (void *)&fd;
+#else  /* HAVE_MSGHDR_ACCRIGHTS */
+    msghdr.msg_control    = &cmsg;
+    msghdr.msg_controllen = sizeof(cmsg);
+    cmsg.fd = fd;
+#endif  /* HAVE_MSGHDR_ACCRIGHTS */
+
+    myiovec.iov_base = (void *)&handle;
+    myiovec.iov_len  = sizeof(handle);
+
+    ret = sendmsg( thread->obj.fd, &msghdr, 0 );
+    close( fd );
+
+    if (ret > 0) return 0;
+    if (errno == EPIPE)
+    {
+        kill_thread( thread, 0 );  /* normal death */
+    }
+    else
+    {
+        perror("sendmsg");
+        thread->exit_code = 1;
+        kill_thread( thread, 1 );
+    }
+    return -1;
+}
+
 static void master_socket_dump( struct object *obj, int verbose )
 {
     struct master_socket *sock = (struct master_socket *)obj;
@@ -297,6 +330,61 @@
     socket_cleanup();
 }
 
+static void request_socket_dump( struct object *obj, int verbose )
+{
+    struct request_socket *sock = (struct request_socket *)obj;
+    assert( obj->ops == &request_socket_ops );
+    fprintf( stderr, "Request socket fd=%d thread=%p\n", sock->obj.fd, sock->thread );
+}
+
+/* handle a request socket event */
+static void request_socket_poll_event( struct object *obj, int event )
+{
+    struct request_socket *sock = (struct request_socket *)obj;
+    assert( obj->ops == &request_socket_ops );
+
+    if (event & (POLLERR | POLLHUP)) kill_thread( sock->thread, 0 );
+    else if (event & POLLIN)
+    {
+        struct thread *thread = sock->thread;
+        int ret;
+        char dummy[1];
+
+        ret = read( sock->obj.fd, &dummy, 1 );
+        if (ret > 0)
+        {
+            call_req_handler( thread );
+            return;
+        }
+        if (!ret)  /* closed pipe */
+        {
+            kill_thread( thread, 0 );
+            return;
+        }
+        perror("read");
+        thread->exit_code = 1;
+        kill_thread( thread, 1 );
+    }
+}
+
+/* create a request socket and send the fd to the client thread */
+struct object *create_request_socket( struct thread *thread )
+{
+    struct request_socket *sock;
+    int fd[2];
+
+    if (pipe( fd )) return NULL;
+    if (!(sock = alloc_object( &request_socket_ops, fd[0] )))
+    {
+        close( fd[1] );
+        return NULL;
+    }
+    sock->thread = thread;
+    send_client_fd( thread, fd[1], -1 );
+    set_select_events( &sock->obj, POLLIN );
+    return &sock->obj;
+}
+
 /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
 const char *get_config_dir(void)
 {
diff --git a/server/request.h b/server/request.h
index ef856f3..c58d5fb 100644
--- a/server/request.h
+++ b/server/request.h
@@ -33,11 +33,12 @@
 extern const char *get_config_dir(void);
 extern void read_request( struct thread *thread );
 extern int write_request( struct thread *thread );
-extern void set_reply_fd( struct thread *thread, int pass_fd );
+extern int send_client_fd( struct thread *thread, int fd, int handle );
 extern void send_reply( struct thread *thread );
 extern void open_master_socket(void);
 extern void close_master_socket(void);
 extern void lock_master_socket( int locked );
+extern struct object *create_request_socket( struct thread *thread );
 
 extern void trace_request( enum request req );
 extern void trace_reply( struct thread *thread );
@@ -90,7 +91,6 @@
 DECL_HANDLER(queue_apc);
 DECL_HANDLER(get_apc);
 DECL_HANDLER(close_handle);
-DECL_HANDLER(get_handle_info);
 DECL_HANDLER(set_handle_info);
 DECL_HANDLER(dup_handle);
 DECL_HANDLER(open_process);
@@ -205,7 +205,6 @@
     (req_handler)req_queue_apc,
     (req_handler)req_get_apc,
     (req_handler)req_close_handle,
-    (req_handler)req_get_handle_info,
     (req_handler)req_set_handle_info,
     (req_handler)req_dup_handle,
     (req_handler)req_open_process,
diff --git a/server/thread.c b/server/thread.c
index 7cfacdc..12e9377 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -89,26 +89,33 @@
 static int alloc_client_buffer( struct thread *thread )
 {
     struct get_thread_buffer_request *req;
-    int fd;
+    int fd, fd_pipe[2];
 
-    if ((fd = create_anonymous_file()) == -1) return -1;
+    if (pipe( fd_pipe ) == -1) return -1;
+    if ((fd = create_anonymous_file()) == -1) goto error;
     if (ftruncate( fd, MAX_REQUEST_LENGTH ) == -1) goto error;
     if ((thread->buffer = mmap( 0, MAX_REQUEST_LENGTH, PROT_READ | PROT_WRITE,
                                 MAP_SHARED, fd, 0 )) == (void*)-1) goto error;
     thread->buffer_info = (struct server_buffer_info *)((char *)thread->buffer + MAX_REQUEST_LENGTH) - 1;
+    if (!(thread->request_fd = create_request_socket( thread ))) goto error;
+    thread->reply_fd = fd_pipe[1];
     /* build the first request into the buffer and send it */
     req = thread->buffer;
     req->pid  = get_process_id( thread->process );
     req->tid  = get_thread_id( thread );
     req->boot = (thread == booting_thread);
     req->version = SERVER_PROTOCOL_VERSION;
-    set_reply_fd( thread, fd );
+
+    send_client_fd( thread, fd_pipe[0], -1 );
+    send_client_fd( thread, fd, -1 );
     send_reply( thread );
     return 1;
 
  error:
     file_set_error();
     if (fd != -1) close( fd );
+    close( fd_pipe[0] );
+    close( fd_pipe[1] );
     return 0;
 }
 
@@ -135,6 +142,8 @@
     thread->apc_tail    = NULL;
     thread->error       = 0;
     thread->pass_fd     = -1;
+    thread->request_fd  = NULL;
+    thread->reply_fd    = -1;
     thread->state       = RUNNING;
     thread->attached    = 0;
     thread->exit_code   = 0;
@@ -197,7 +206,9 @@
     if (thread->info) release_object( thread->info );
     if (thread->queue) release_object( thread->queue );
     if (thread->buffer != (void *)-1) munmap( thread->buffer, MAX_REQUEST_LENGTH );
+    if (thread->reply_fd != -1) close( thread->reply_fd );
     if (thread->pass_fd != -1) close( thread->pass_fd );
+    if (thread->request_fd) release_object( thread->request_fd );
 }
 
 /* dump a thread on stdout for debugging purposes */
@@ -618,7 +629,11 @@
     wake_up( &thread->obj, 0 );
     detach_thread( thread, violent_death ? SIGTERM : 0 );
     remove_select_user( &thread->obj );
+    release_object( thread->request_fd );
+    close( thread->reply_fd );
     munmap( thread->buffer, MAX_REQUEST_LENGTH );
+    thread->request_fd = NULL;
+    thread->reply_fd = -1;
     thread->buffer = (void *)-1;
     release_object( thread );
 }
@@ -675,7 +690,7 @@
             if ((req->handle = alloc_handle( current->process, thread,
                                              THREAD_ALL_ACCESS, req->inherit )) != -1)
             {
-                set_reply_fd( current, sock[1] );
+                send_client_fd( current, sock[1], req->handle );
                 /* thread object will be released when the thread gets killed */
                 add_process_thread( current->process, thread );
                 return;
diff --git a/server/thread.h b/server/thread.h
index c0db481..8e36569 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -48,7 +48,9 @@
     struct thread_apc  *apc_head;    /* queue of async procedure calls */
     struct thread_apc  *apc_tail;    /* queue of async procedure calls */
     unsigned int        error;       /* current error code */
-    int                 pass_fd;   /* fd to pass to the client */
+    struct object      *request_fd;  /* fd for receiving client requests */
+    int                 pass_fd;     /* fd to pass to the client */
+    int                 reply_fd;    /* fd to use to wake a client waiting on a reply */
     enum run_state      state;     /* running state */
     int                 attached;  /* is thread attached with ptrace? */
     int                 exit_code; /* thread exit code */
diff --git a/server/trace.c b/server/trace.c
index bad07e8..534f4d43 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -471,21 +471,23 @@
     fprintf( stderr, " handle=%d", req->handle );
 }
 
-static void dump_get_handle_info_request( const struct get_handle_info_request *req )
+static void dump_close_handle_reply( const struct close_handle_request *req )
 {
-    fprintf( stderr, " handle=%d", req->handle );
-}
-
-static void dump_get_handle_info_reply( const struct get_handle_info_request *req )
-{
-    fprintf( stderr, " flags=%d", req->flags );
+    fprintf( stderr, " fd=%d", req->fd );
 }
 
 static void dump_set_handle_info_request( const struct set_handle_info_request *req )
 {
     fprintf( stderr, " handle=%d,", req->handle );
     fprintf( stderr, " flags=%d,", req->flags );
-    fprintf( stderr, " mask=%d", req->mask );
+    fprintf( stderr, " mask=%d,", req->mask );
+    fprintf( stderr, " fd=%d", req->fd );
+}
+
+static void dump_set_handle_info_reply( const struct set_handle_info_request *req )
+{
+    fprintf( stderr, " old_flags=%d,", req->old_flags );
+    fprintf( stderr, " cur_fd=%d", req->cur_fd );
 }
 
 static void dump_dup_handle_request( const struct dup_handle_request *req )
@@ -500,7 +502,8 @@
 
 static void dump_dup_handle_reply( const struct dup_handle_request *req )
 {
-    fprintf( stderr, " handle=%d", req->handle );
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " fd=%d", req->fd );
 }
 
 static void dump_open_process_request( const struct open_process_request *req )
@@ -957,7 +960,8 @@
     fprintf( stderr, " header_size=%d,", req->header_size );
     fprintf( stderr, " base=%p,", req->base );
     fprintf( stderr, " shared_file=%d,", req->shared_file );
-    fprintf( stderr, " shared_size=%d", req->shared_size );
+    fprintf( stderr, " shared_size=%d,", req->shared_size );
+    fprintf( stderr, " anonymous=%d", req->anonymous );
 }
 
 static void dump_create_device_request( const struct create_device_request *req )
@@ -1471,7 +1475,6 @@
     (dump_func)dump_queue_apc_request,
     (dump_func)dump_get_apc_request,
     (dump_func)dump_close_handle_request,
-    (dump_func)dump_get_handle_info_request,
     (dump_func)dump_set_handle_info_request,
     (dump_func)dump_dup_handle_request,
     (dump_func)dump_open_process_request,
@@ -1582,9 +1585,8 @@
     (dump_func)0,
     (dump_func)0,
     (dump_func)dump_get_apc_reply,
-    (dump_func)0,
-    (dump_func)dump_get_handle_info_reply,
-    (dump_func)0,
+    (dump_func)dump_close_handle_reply,
+    (dump_func)dump_set_handle_info_reply,
     (dump_func)dump_dup_handle_reply,
     (dump_func)dump_open_process_reply,
     (dump_func)dump_select_reply,
@@ -1695,7 +1697,6 @@
     "queue_apc",
     "get_apc",
     "close_handle",
-    "get_handle_info",
     "set_handle_info",
     "dup_handle",
     "open_process",