Added add_queue/remove_queue to server object operations.
Moved select() loop functions to select.c.

diff --git a/server/select.c b/server/select.c
new file mode 100644
index 0000000..5d3092e
--- /dev/null
+++ b/server/select.c
@@ -0,0 +1,192 @@
+/*
+ * Server main select() loop
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "server/object.h"
+
+/* select user fd */
+struct user
+{
+    struct timeval           when;    /* timeout expiry (absolute time) */
+    struct user             *next;    /* next in sorted timeout list */
+    struct user             *prev;    /* prev in sorted timeout list */
+    const struct select_ops *ops;   /* user operations list */
+    int                      fd;      /* user fd */
+    void                    *private; /* user private data */
+};
+
+static struct user *users[FD_SETSIZE];      /* users array */
+static fd_set read_set, write_set;          /* current select sets */
+static int nb_users;                        /* current number of users */
+static int max_fd;                          /* max fd in use */
+static struct user *timeout_head;           /* sorted timeouts list head */
+static struct user *timeout_tail;           /* sorted timeouts list tail */
+
+
+/* add a user */
+int add_select_user( int fd, int events, const struct select_ops *ops, void *private )
+{
+    int flags;
+    struct user *user = malloc( sizeof(*user) );
+    if (!user) return -1;
+    assert( !users[fd] );
+
+    user->ops          = ops;
+    user->when.tv_sec  = 0;
+    user->when.tv_usec = 0;
+    user->fd           = fd;
+    user->private      = private;
+
+    flags = fcntl( fd, F_GETFL, 0 );
+    fcntl( fd, F_SETFL, flags | O_NONBLOCK );
+
+    users[fd] = user;
+    set_select_events( fd, events );
+    if (fd > max_fd) max_fd = fd;
+    nb_users++;
+    return fd;
+}
+
+/* remove a user */
+void remove_select_user( int fd )
+{
+    struct user *user = users[fd];
+    assert( user );
+
+    set_select_timeout( fd, 0 );
+    set_select_events( fd, 0 );
+    users[fd] = NULL;
+    if (max_fd == fd) while (max_fd && !users[max_fd]) max_fd--;
+    nb_users--;
+    free( user );
+}
+
+/* set a user timeout */
+void set_select_timeout( int fd, struct timeval *when )
+{
+    struct user *user = users[fd];
+    struct user *pos;
+    assert( user );
+
+    if (user->when.tv_sec || user->when.tv_usec)
+    {
+        /* there is already a timeout */
+        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;
+        user->when.tv_sec = user->when.tv_usec = 0;
+    }
+    if (!when) return;  /* no timeout */
+    user->when = *when;
+
+    /* Now insert it in the linked list */
+
+    for (pos = timeout_head; pos; pos = pos->next)
+    {
+        if (pos->when.tv_sec > user->when.tv_sec) break;
+        if ((pos->when.tv_sec == user->when.tv_sec) &&
+            (pos->when.tv_usec > user->when.tv_usec)) 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;
+    }
+}
+
+/* set the events that select waits for on this fd */
+void set_select_events( int fd, int events )
+{
+    if (events & READ_EVENT) FD_SET( fd, &read_set );
+    else FD_CLR( fd, &read_set );
+    if (events & WRITE_EVENT) FD_SET( fd, &write_set );
+    else FD_CLR( fd, &write_set );
+}
+
+/* get a user private data, checking the type */
+void *get_select_private_data( const struct select_ops *ops, int fd )
+{
+    struct user *user = users[fd];
+    assert( user );
+    assert( user->ops == ops );
+    return user->private;
+}
+
+/* server main loop */
+void select_loop(void)
+{
+    int i, ret;
+
+    setsid();
+    signal( SIGPIPE, SIG_IGN );
+
+    while (nb_users)
+    {
+        fd_set read = read_set, write = write_set;
+#if 0
+        printf( "select: " );
+        for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
+                                                    (FD_ISSET( i, &write_set ) ? 'w' : '-') );
+        printf( "\n" );
+#endif
+        if (timeout_head)
+        {
+            struct timeval tv, now;
+            gettimeofday( &now, NULL );
+            if ((timeout_head->when.tv_sec < now.tv_sec) ||
+                ((timeout_head->when.tv_sec == now.tv_sec) &&
+                 (timeout_head->when.tv_usec < now.tv_usec)))
+            {
+                timeout_head->ops->timeout( timeout_head->fd, timeout_head->private );
+                continue;
+            }
+            tv.tv_sec = timeout_head->when.tv_sec - now.tv_sec;
+            if ((tv.tv_usec = timeout_head->when.tv_usec - now.tv_usec) < 0)
+            {
+                tv.tv_usec += 1000000;
+                tv.tv_sec--;
+            }
+            ret = select( max_fd + 1, &read, &write, NULL, &tv );
+        }
+        else  /* no timeout */
+        {
+            ret = select( max_fd + 1, &read, &write, NULL, NULL );
+        }
+
+        if (!ret) continue;
+        if (ret == -1) perror("select");
+
+        for (i = 0; i <= max_fd; i++)
+        {
+            int event = 0;
+            if (FD_ISSET( i, &write )) event |= WRITE_EVENT;
+            if (FD_ISSET( i, &read ))  event |= READ_EVENT;
+            if (event) users[i]->ops->event( i, event, users[i]->private );
+        }
+    }
+}