Moved poll handling to the generic part of the server objects.
Fixed busy waiting on POLLERR events.
Merged struct client into struct thread.

diff --git a/server/request.c b/server/request.c
index 56b394d..62b15e9 100644
--- a/server/request.c
+++ b/server/request.c
@@ -4,13 +4,20 @@
  * Copyright (C) 1998 Alexandre Julliard
  */
 
+#include "config.h"
+
 #include <assert.h>
-#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
-#include <signal.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/time.h>
 #include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
 #include <sys/uio.h>
 #include <unistd.h>
 
@@ -22,9 +29,30 @@
 #include "server.h"
 #define WANT_REQUEST_HANDLERS
 #include "request.h"
+
+/* Some versions of glibc don't define this */
+#ifndef SCM_RIGHTS
+#define SCM_RIGHTS 1
+#endif
+
  
 struct thread *current = NULL;  /* thread handling the current request */
 
+
+/* socket communication static structures */
+static struct iovec myiovec;
+static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
+#ifndef HAVE_MSGHDR_ACCRIGHTS
+struct cmsg_fd
+{
+    int len;   /* sizeof structure */
+    int level; /* SOL_SOCKET */
+    int type;  /* SCM_RIGHTS */
+    int fd;    /* fd to pass */
+};
+static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
+#endif  /* HAVE_MSGHDR_ACCRIGHTS */
+
 /* complain about a protocol error and terminate the client connection */
 void fatal_protocol_error( struct thread *thread, const char *err, ... )
 {
@@ -34,11 +62,11 @@
     fprintf( stderr, "Protocol error:%p: ", thread );
     vfprintf( stderr, err, args );
     va_end( args );
-    remove_client( thread->client, PROTOCOL_ERROR );
+    kill_thread( thread, PROTOCOL_ERROR );
 }
 
 /* call a request handler */
-void call_req_handler( struct thread *thread, enum request req, int fd )
+static void call_req_handler( struct thread *thread, enum request req, int fd )
 {
     current = thread;
     clear_error();
@@ -65,31 +93,109 @@
     current = NULL;
 }
 
-/* a thread has been killed */
-void call_kill_handler( struct thread *thread, int exit_code )
-{
-    /* must be reentrant WRT call_req_handler */
-    struct thread *old_current = current;
-    current = thread;
-    if (current)
-    {
-        if (debug_level) trace_kill( exit_code );
-        thread_killed( current, exit_code );
-    }
-    current = (old_current != thread) ? old_current : NULL;
-}
-
 /* set the fd to pass to the thread */
 void set_reply_fd( struct thread *thread, int pass_fd )
 {
-    client_pass_fd( thread->client, pass_fd );
+    assert( thread->pass_fd == -1 );
+    thread->pass_fd = pass_fd;
 }
 
 /* send a reply to a thread */
 void send_reply( struct thread *thread )
 {
     if (thread->state == SLEEPING) thread->state = RUNNING;
-    client_reply( thread->client, thread->error );
+    if (debug_level) trace_reply( thread );
+    if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
+}
+
+/* read a message from a client that has something to say */
+void read_request( struct thread *thread )
+{
+    int ret;
+    enum request req;
+
+#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 = -1;
+#endif  /* HAVE_MSGHDR_ACCRIGHTS */
+
+    assert( thread->pass_fd == -1 );
+
+    myiovec.iov_base = (void *)&req;
+    myiovec.iov_len  = sizeof(req);
+
+    ret = recvmsg( thread->obj.fd, &msghdr, 0 );
+#ifndef HAVE_MSGHDR_ACCRIGHTS
+    thread->pass_fd = cmsg.fd;
+#endif
+
+    if (ret == sizeof(req))
+    {
+        int pass_fd = thread->pass_fd;
+        thread->pass_fd = -1;
+        call_req_handler( thread, req, pass_fd );
+        if (pass_fd != -1) close( pass_fd );
+        return;
+    }
+    if (ret == -1)
+    {
+        perror("recvmsg");
+        kill_thread( thread, BROKEN_PIPE );
+        return;
+    }
+    if (!ret)  /* closed pipe */
+    {
+        kill_thread( thread, BROKEN_PIPE );
+        return;
+    }
+    fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
+}
+
+/* send a message to a client that is ready to receive something */
+int write_request( struct thread *thread )
+{
+    int ret;
+
+    if (thread->pass_fd == -1)
+    {
+        ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
+        if (ret == sizeof(thread->error)) goto ok;
+    }
+    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 */
+
+        myiovec.iov_base = (void *)&thread->error;
+        myiovec.iov_len  = sizeof(thread->error);
+
+        ret = sendmsg( thread->obj.fd, &msghdr, 0 );
+        close( thread->pass_fd );
+        thread->pass_fd = -1;
+        if (ret == sizeof(thread->error)) goto ok;
+    }
+    if (ret == -1)
+    {
+        if (errno == EWOULDBLOCK) return 0;  /* not a fatal error */
+        if (errno != EPIPE) perror("sendmsg");
+    }
+    else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
+    kill_thread( thread, BROKEN_PIPE );
+    return -1;
+
+ ok:
+    set_select_events( &thread->obj, POLLIN );
+    return 1;
 }
 
 /* set the debug level */