]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge poll branch into trunk - cupsd now uses poll(), epoll(), or kqueue()
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Tue, 21 Nov 2006 15:36:04 +0000 (15:36 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Tue, 21 Nov 2006 15:36:04 +0000 (15:36 +0000)
depending on the platform.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@6123 7a7537e8-13f0-0310-91df-b6672ffda945

21 files changed:
CHANGES.txt
config-scripts/cups-poll.m4 [new file with mode: 0644]
config.h.in
configure.in
cups/array.c
cups/array.h
cups/http-private.h
cups/http.c
scheduler/Makefile
scheduler/client.c
scheduler/client.h
scheduler/cupsd.h
scheduler/dirsvc.c
scheduler/ipp.c
scheduler/job.c
scheduler/listen.c
scheduler/main.c
scheduler/select.c [new file with mode: 0644]
scheduler/server.c
scheduler/subscriptions.c
scheduler/sysman.c

index 1bbb36a35644e5deb243e59ca886a7dd3be70996..818a1edc910bd5af14f7e7b76682964124b3fecd 100644 (file)
@@ -1,8 +1,13 @@
-CHANGES.txt - 2006-11-14
+CHANGES.txt - 2006-11-21
 ------------------------
 
 CHANGES IN CUPS V1.3
 
+       - The scheduler now uses poll(), epoll(), or /dev/kqueue
+         instead of select() when possible (STR #1261)
+       - Added new cupsArrayGetIndex() and cupsArrayGetInsert()
+         functions to get the current index and insertion
+         positions of an array.
        - Added a new --with-max-copies configure option (STR
          #2090)
        - Added new cupsRemoveDest() and cupsSetDefaultDest()
diff --git a/config-scripts/cups-poll.m4 b/config-scripts/cups-poll.m4
new file mode 100644 (file)
index 0000000..d0b6e97
--- /dev/null
@@ -0,0 +1,31 @@
+dnl
+dnl "$Id$"
+dnl
+dnl   Select/poll stuff for the Common UNIX Printing System (CUPS).
+dnl
+dnl   Copyright 2006 by Easy Software Products, all rights reserved.
+dnl
+dnl   These coded instructions, statements, and computer programs are the
+dnl   property of Easy Software Products and are protected by Federal
+dnl   copyright law.  Distribution and use rights are outlined in the file
+dnl   "LICENSE.txt" which should have been included with this file.  If this
+dnl   file is missing or damaged please contact Easy Software Products
+dnl   at:
+dnl
+dnl       Attn: CUPS Licensing Information
+dnl       Easy Software Products
+dnl       44141 Airport View Drive, Suite 204
+dnl       Hollywood, Maryland 20636 USA
+dnl
+dnl       Voice: (301) 373-9600
+dnl       EMail: cups-info@cups.org
+dnl         WWW: http://www.cups.org
+dnl
+
+AC_CHECK_FUNC(poll, AC_DEFINE(HAVE_POLL))
+AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL))
+AC_CHECK_FUNC(kqueue, AC_DEFINE(HAVE_KQUEUE))
+
+dnl
+dnl End of "$Id$".
+dnl
index 0525181c889aff2f23b3298ce793b8d0de7c1325..93388abd9fd99f52be426b29f0430e209be21157 100644 (file)
 #define CUPS_DEFAULT_GSSSERVICENAME    ""
 
 
+/*
+ * Select/poll interfaces...
+ */
+
+#undef HAVE_POLL
+#undef HAVE_EPOLL
+#undef HAVE_KQUEUE
+
+
 #endif /* !_CUPS_CONFIG_H_ */
 
 /*
index 2b1fa0d3bb62fdfb288f4be2d31e4496b98850d4..2ce2a118a9313b4c6708f05409d5cfa71a398bcf 100644 (file)
@@ -35,6 +35,7 @@ sinclude(config-scripts/cups-compiler.m4)
 
 sinclude(config-scripts/cups-image.m4)
 sinclude(config-scripts/cups-network.m4)
+sinclude(config-scripts/cups-poll.m4)
 sinclude(config-scripts/cups-slp.m4)
 sinclude(config-scripts/cups-gssapi.m4)
 sinclude(config-scripts/cups-ldap.m4)
index 674a4b4d487d5e20ea6a49545bc3275190e9dfdb..259d1089db5f1b2b98c42da940e00d49c890cec8 100644 (file)
  *
  * Contents:
  *
- *   cupsArrayAdd()      - Add an element to the array.
- *   cupsArrayClear()    - Clear the array.
- *   cupsArrayCount()    - Get the number of elements in the array.
- *   cupsArrayCurrent()  - Return the current element in the array.
- *   cupsArrayDelete()   - Free all memory used by the array.
- *   cupsArrayDup()      - Duplicate the array.
- *   cupsArrayFind()     - Find an element in the array.
- *   cupsArrayFirst()    - Get the first element in the array.
- *   cupsArrayIndex()    - Get the N-th element in the array.
- *   cupsArrayInsert()   - Insert an element in the array.
- *   cupsArrayLast()     - Get the last element in the array.
- *   cupsArrayNew()      - Create a new array.
- *   cupsArrayNext()     - Get the next element in the array.
- *   cupsArrayPrev()     - Get the previous element in the array.
- *   cupsArrayRemove()   - Remove an element from the array.
- *   cupsArrayRestore()  - Reset the current element to the last cupsArraySave.
- *   cupsArraySave()     - Mark the current element for a later
- *                         cupsArrayRestore.
- *   cupsArrayUserData() - Return the user data for an array.
- *   cups_array_add()    - Insert or append an element to the array...
- *   cups_array_find()   - Find an element in the array...
+ *   cupsArrayAdd()       - Add an element to the array.
+ *   cupsArrayClear()     - Clear the array.
+ *   cupsArrayCount()     - Get the number of elements in the array.
+ *   cupsArrayCurrent()   - Return the current element in the array.
+ *   cupsArrayDelete()    - Free all memory used by the array.
+ *   cupsArrayDup()       - Duplicate the array.
+ *   cupsArrayFind()      - Find an element in the array.
+ *   cupsArrayFirst()     - Get the first element in the array.
+ *   cupsArrayGetIndex()  - Get the index of the current element.
+ *   cupsArrayGetInsert() - Get the index of the last inserted element.
+ *   cupsArrayIndex()     - Get the N-th element in the array.
+ *   cupsArrayInsert()    - Insert an element in the array.
+ *   cupsArrayLast()      - Get the last element in the array.
+ *   cupsArrayNew()       - Create a new array.
+ *   cupsArrayNext()      - Get the next element in the array.
+ *   cupsArrayPrev()      - Get the previous element in the array.
+ *   cupsArrayRemove()    - Remove an element from the array.
+ *   cupsArrayRestore()   - Reset the current element to the last cupsArraySave.
+ *   cupsArraySave()      - Mark the current element for a later
+ *                          cupsArrayRestore.
+ *   cupsArrayUserData()  - Return the user data for an array.
+ *   cups_array_add()     - Insert or append an element to the array...
+ *   cups_array_find()    - Find an element in the array...
  */
 
 /*
@@ -385,6 +387,38 @@ cupsArrayFirst(cups_array_t *a)            /* I - Array */
 }
 
 
+/*
+ * 'cupsArrayGetIndex()' - Get the index of the current element.
+ *
+ * @since CUPS 1.3@
+ */
+
+int                                    /* O - Index of the current element */
+cupsArrayGetIndex(cups_array_t *a)     /* I - Array */
+{
+  if (!a)
+    return (-1);
+  else
+    return (a->current);
+}
+
+
+/*
+ * 'cupsArrayGetInsert()' - Get the index of the last inserted element.
+ *
+ * @since CUPS 1.3@
+ */
+
+int                                    /* O - Index of the last inserted element */
+cupsArrayGetInsert(cups_array_t *a)    /* I - Array */
+{
+  if (!a)
+    return (-1);
+  else
+    return (a->insert);
+}
+
+
 /*
  * 'cupsArrayIndex()' - Get the N-th element in the array.
  */
@@ -582,8 +616,10 @@ cupsArrayRemove(cups_array_t *a,   /* I - Array */
   if (current <= a->current)
     a->current --;
 
-  if (current <= a->insert)
+  if (current < a->insert)
     a->insert --;
+  else if (current == a->insert)
+    a->insert = -1;
 
   for (i = 0; i < a->num_saved; i ++)
     if (current <= a->saved[i])
index 9919656fe00d65aa66b88bbe66e694f0da0aee91..5a81ee85412029be8c9fae0ef1e4187fb2c17c3a 100644 (file)
@@ -64,6 +64,8 @@ extern void           cupsArrayDelete(cups_array_t *a);
 extern cups_array_t    *cupsArrayDup(cups_array_t *a);
 extern void            *cupsArrayFind(cups_array_t *a, void *e);
 extern void            *cupsArrayFirst(cups_array_t *a);
+extern int             cupsArrayGetIndex(cups_array_t *a);
+extern int             cupsArrayGetInsert(cups_array_t *a);
 extern void            *cupsArrayIndex(cups_array_t *a, int n);
 extern int             cupsArrayInsert(cups_array_t *a, void *e);
 extern void            *cupsArrayLast(cups_array_t *a);
index 193aab45e0b8e189e9da1bdd97cb68562d50b3b5..6d4f01f22645efc6f9bb8d584d4c146d734fa86c 100644 (file)
@@ -168,7 +168,7 @@ struct _http_s                              /**** HTTP connection structure. ****/
   void                 *tls;           /* TLS state information */
   http_encryption_t    encryption;     /* Encryption requirements */
   /**** New in CUPS 1.1.19 ****/
-  fd_set               *input_set;     /* select() set for httpWait() @since CUPS 1.1.19@ */
+  fd_set               *input_set;     /* select() set for httpWait() @deprecated@ */
   http_status_t                expect;         /* Expect: header @since CUPS 1.1.19@ */
   char                 *cookie;        /* Cookie value(s) @since CUPS 1.1.19@ */
   /**** New in CUPS 1.1.20 ****/
index 9d35e7c9f92296f3bc22bef167bf3a013ddd16d8..35574f105995307f911691cb4223caabf378509a 100644 (file)
 #  include <sys/time.h>
 #  include <sys/resource.h>
 #endif /* !WIN32 */
+#ifdef HAVE_POLL
+#  include <sys/poll.h>
+#endif /* HAVE_POLL */
 
 
 /*
@@ -309,9 +312,6 @@ httpClose(http_t *http)                     /* I - HTTP connection */
 
   httpAddrFreeList(http->addrlist);
 
-  if (http->input_set)
-    free(http->input_set);
-
   if (http->cookie)
     free(http->cookie);
 
@@ -2878,12 +2878,13 @@ http_wait(http_t *http,                 /* I - HTTP connection */
           int    msec,                 /* I - Milliseconds to wait */
          int    usessl)                /* I - Use SSL context? */
 {
-#ifndef WIN32
-  struct rlimit                limit;          /* Runtime limit */
-  int                  set_size;       /* Size of select set */
-#endif /* !WIN32 */
+#ifdef HAVE_POLL
+  struct pollfd                pfd;            /* Polled file descriptor */
+#else
+  fd_set               input_set;      /* select() input set */
   struct timeval       timeout;        /* Timeout */
-  int                  nfds;           /* Result from select() */
+#endif /* HAVE_POLL */
+  int                  nfds;           /* Result from select()/poll() */
 
 
   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
@@ -2914,41 +2915,20 @@ http_wait(http_t *http,                 /* I - HTTP connection */
 #endif /* HAVE_SSL */
 
  /*
-  * Then try doing a select() to poll the socket...
+  * Then try doing a select() or poll() to poll the socket...
   */
 
-  if (!http->input_set)
-  {
-#ifdef WIN32
-   /*
-    * Windows has a fixed-size select() structure, different (surprise,
-    * surprise!) from all UNIX implementations.  Just allocate this
-    * fixed structure...
-    */
-
-    http->input_set = calloc(1, sizeof(fd_set));
-#else
-   /*
-    * Allocate the select() input set based upon the max number of file
-    * descriptors available for this process...
-    */
-
-    getrlimit(RLIMIT_NOFILE, &limit);
+#ifdef HAVE_POLL
+  pfd.fd     = http->fd;
+  pfd.events = POLLIN;
 
-    set_size = (limit.rlim_cur + 31) / 8 + 4;
-    if (set_size < sizeof(fd_set))
-      set_size = sizeof(fd_set);
-
-    http->input_set = calloc(1, set_size);
-#endif /* WIN32 */
-
-    if (!http->input_set)
-      return (0);
-  }
+  while ((nfds = poll(&pfd, 1, msec)) < 0 && errno == EINTR);
 
+#else
   do
   {
-    FD_SET(http->fd, http->input_set);
+    FD_ZERO(&input_set);
+    FD_SET(http->fd, &input_set);
 
     DEBUG_printf(("http_wait: msec=%d, http->fd=%d\n", msec, http->fd));
 
@@ -2957,20 +2937,19 @@ http_wait(http_t *http,                 /* I - HTTP connection */
       timeout.tv_sec  = msec / 1000;
       timeout.tv_usec = (msec % 1000) * 1000;
 
-      nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
+      nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
     }
     else
-      nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
+      nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
 
     DEBUG_printf(("http_wait: select() returned %d...\n", nfds));
   }
-#ifdef WIN32
+#  ifdef WIN32
   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
-#else
+#  else
   while (nfds < 0 && errno == EINTR);
-#endif /* WIN32 */
-
-  FD_CLR(http->fd, http->input_set);
+#  endif /* WIN32 */
+#endif /* HAVE_POLL */
 
   DEBUG_printf(("http_wait: returning with nfds=%d...\n", nfds));
 
index 63e921dbf7370851b2c44dd82ac846ed7b7175ef..10aa0ba70fe1b6aa5e7d0587b4213eafe9018015 100644 (file)
@@ -43,6 +43,7 @@ CUPSDOBJS =   \
                printers.o \
                process.o \
                quotas.o \
+               select.o \
                server.o \
                statbuf.o \
                subscriptions.o \
index b359accae335f2b98f590ea7bf3f4d5d2f0a68b6..e3fd064557a50e967a08db943a342b80d2e069a8 100644 (file)
@@ -36,6 +36,7 @@
  *   cupsdSendHeader()       - Send an HTTP request.
  *   cupsdUpdateCGI()        - Read status messages from CGI scripts and programs.
  *   cupsdWriteClient()      - Write data to a client as needed.
+ *   cupsdWritePipe()        - Flag that data is available on the CGI pipe.
  *   check_if_modified()     - Decode an "If-Modified-Since" line.
  *   encrypt_client()        - Enable encryption for the client...
  *   get_cdsa_server_certs() - Convert a keychain name into the CFArrayRef
@@ -404,10 +405,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   * Add the socket to the select() input mask.
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdAcceptClient: Adding fd %d to InputSet...",
-                  con->http.fd);
-  FD_SET(con->http.fd, InputSet);
+  cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
 
  /*
   * Temporarily suspend accept()'s until we lose a client...
@@ -574,13 +572,7 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
 
   if (con->file >= 0)
   {
-    if (FD_ISSET(con->file, InputSet))
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: %d Removing fd %d from InputSet...",
-                     con->http.fd, con->file);
-      FD_CLR(con->file, InputSet);
-    }
+    cupsdRemoveSelect(con->file);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "cupsdCloseClient: %d Closing data file %d.",
@@ -602,11 +594,8 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
       * Only do a partial close so that the encrypted client gets everything.
       */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: Removing fd %d from OutputSet...",
-                     con->http.fd);
       shutdown(con->http.fd, 0);
-      FD_CLR(con->http.fd, OutputSet);
+      cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
     }
     else
     {
@@ -614,12 +603,8 @@ cupsdCloseClient(cupsd_client_t *con)      /* I - Client to close */
       * Shut the socket down fully...
       */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdCloseClient: Removing fd %d from InputSet and OutputSet...",
-                     con->http.fd);
+      cupsdRemoveSelect(con->http.fd);
       close(con->http.fd);
-      FD_CLR(con->http.fd, InputSet);
-      FD_CLR(con->http.fd, OutputSet);
       con->http.fd = -1;
     }
   }
@@ -697,7 +682,7 @@ cupsdFlushHeader(cupsd_client_t *con)       /* I - Client to flush to */
  * 'cupsdReadClient()' - Read data from a client.
  */
 
-int                                    /* O - 1 on success, 0 on error */
+void
 cupsdReadClient(cupsd_client_t *con)   /* I - Client to read from */
 {
   char                 line[32768],    /* Line from client... */
@@ -726,7 +711,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
   if (con->http.error)
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: http error seen...");
-    return (cupsdCloseClient(con));
+    cupsdCloseClient(con);
+    return;
   }
 
 #ifdef HAVE_SSL
@@ -750,9 +736,9 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                       buf[0] & 255);
 
       if (!encrypt_client(con))
-        return (cupsdCloseClient(con));
+        cupsdCloseClient(con);
 
-      return (1);
+      return;
     }
   }
 #endif /* HAVE_SSL */
@@ -768,7 +754,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        {
          cupsdLogMessage(CUPSD_LOG_DEBUG2,
                          "cupsdReadClient: httpGets returned EOF...");
-          return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
 
        /*
@@ -831,7 +818,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                              "Bad request line \"%s\" from %s!", line,
                              con->http.hostname);
              cupsdSendError(con, HTTP_BAD_REQUEST);
-             return (cupsdCloseClient(con));
+             cupsdCloseClient(con);
+             return;
          case 2 :
              con->http.version = HTTP_0_9;
              break;
@@ -842,7 +830,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
                                "Bad request line \"%s\" from %s!", line,
                                con->http.hostname);
                cupsdSendError(con, HTTP_BAD_REQUEST);
-               return (cupsdCloseClient(con));
+               cupsdCloseClient(con);
+               return;
              }
 
              if (major < 2)
@@ -856,7 +845,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
              else
              {
                cupsdSendError(con, HTTP_NOT_SUPPORTED);
-               return (cupsdCloseClient(con));
+               cupsdCloseClient(con);
+               return;
              }
              break;
        }
@@ -901,7 +891,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
            cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!",
                            con->uri);
            cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED);
-           return (cupsdCloseClient(con));
+           cupsdCloseClient(con);
+           return;
          }
 
          /*
@@ -934,7 +925,8 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
        {
          cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation);
          cupsdSendError(con, HTTP_BAD_REQUEST);
-         return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
 
         con->start     = time(NULL);
@@ -957,12 +949,16 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         * Parse incoming parameters until the status changes...
        */
 
-        status = httpUpdate(HTTP(con));
+        while ((status = httpUpdate(HTTP(con))) == HTTP_CONTINUE)
+         if (con->http.used == 0 ||
+             !memchr(con->http.buffer, '\n', con->http.used))
+           break;
 
        if (status != HTTP_OK && status != HTTP_CONTINUE)
        {
          cupsdSendError(con, HTTP_BAD_REQUEST);
-         return (cupsdCloseClient(con));
+         cupsdCloseClient(con);
+         return;
        }
        break;
 
@@ -1029,7 +1025,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       */
 
       if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else if (con->operation == HTTP_OPTIONS)
     {
@@ -1040,7 +1039,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       if (con->best && con->best->type != AUTH_NONE)
       {
        if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
       }
 
       if (!strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") &&
@@ -1052,7 +1054,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
        */
 
        if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
        httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
@@ -1060,25 +1065,40 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
        httpPrintf(HTTP(con), "\r\n");
 
        if (cupsdFlushHeader(con) < 0)
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 
         if (!encrypt_client(con))
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 #else
        if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 #endif /* HAVE_SSL */
       }
 
       if (!cupsdSendHeader(con, HTTP_OK, NULL))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
 
       httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
       httpPrintf(HTTP(con), "Content-Length: 0\r\n");
       httpPrintf(HTTP(con), "\r\n");
 
       if (cupsdFlushHeader(con) < 0)
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else if (!is_path_absolute(con->uri))
     {
@@ -1087,7 +1107,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
       */
 
       if (!cupsdSendError(con, HTTP_FORBIDDEN))
-       return (cupsdCloseClient(con));
+      {
+       cupsdCloseClient(con);
+       return;
+      }
     }
     else
     {
@@ -1100,7 +1123,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
        */
 
        if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
        httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
@@ -1108,13 +1134,22 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
        httpPrintf(HTTP(con), "\r\n");
 
        if (cupsdFlushHeader(con) < 0)
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 
         if (!encrypt_client(con))
-         return (cupsdCloseClient(con));
+        {
+         cupsdCloseClient(con);
+         return;
+       }
 #else
        if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED))
-         return (cupsdCloseClient(con));
+       {
+         cupsdCloseClient(con);
+         return;
+       }
 #endif /* HAVE_SSL */
       }
 
@@ -1124,7 +1159,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                        "cupsdReadClient: Unauthorized request for %s...\n",
                        con->uri);
        cupsdSendError(con, status);
-       return (cupsdCloseClient(con));
+       cupsdCloseClient(con);
+       return;
       }
 
       if (con->http.expect &&
@@ -1137,7 +1173,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          */
 
          if (!cupsdSendHeader(con, HTTP_CONTINUE, NULL))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
        }
        else
        {
@@ -1146,13 +1185,19 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
          */
 
          if (!cupsdSendHeader(con, HTTP_EXPECTATION_FAILED, NULL))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
 
          httpPrintf(HTTP(con), "Content-Length: 0\r\n");
          httpPrintf(HTTP(con), "\r\n");
 
          if (cupsdFlushHeader(con) < 0)
-           return (cupsdCloseClient(con));
+          {
+           cupsdCloseClient(con);
+           return;
+         }
        }
       }
 
@@ -1174,7 +1219,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              else
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1243,7 +1291,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
               if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
               }
              else
                cupsdLogRequest(con, HTTP_OK);
@@ -1264,7 +1315,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1278,7 +1332,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                                       sizeof(buf))) == NULL)
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1295,7 +1352,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                if (!cupsdSendCommand(con, con->command, con->options, 0))
                {
                  if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                   return (cupsdCloseClient(con));
+                 {
+                   cupsdCloseClient(con);
+                   return;
+                 }
                }
                else
                  cupsdLogRequest(con, HTTP_OK);
@@ -1308,7 +1368,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              if (!check_if_modified(con, &filestats))
               {
                if (!cupsdSendError(con, HTTP_NOT_MODIFIED))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
              else
               {
@@ -1318,7 +1381,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                  snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
                if (!write_file(con, HTTP_OK, filename, line, &filestats))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
            }
             break;
@@ -1342,7 +1408,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
             }
@@ -1353,7 +1422,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1445,7 +1517,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                                       sizeof(buf))) == NULL)
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1459,7 +1534,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
                */
 
                if (!cupsdSendError(con, HTTP_UNAUTHORIZED))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
              }
            }
            break;
@@ -1479,7 +1557,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1502,7 +1583,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
             }
@@ -1513,7 +1597,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
               if (!cupsdSendError(con, HTTP_BAD_REQUEST))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1533,7 +1620,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
            if (con->file < 0)
            {
              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
            }
 
            fchmod(con->file, 0640);
@@ -1544,7 +1634,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        case HTTP_DELETE :
        case HTTP_TRACE :
             cupsdSendError(con, HTTP_NOT_IMPLEMENTED);
-           return (cupsdCloseClient(con));
+           cupsdCloseClient(con);
+           return;
 
        case HTTP_HEAD :
             if (!strncmp(con->uri, "/printers/", 10) &&
@@ -1562,7 +1653,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              else
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
 
                break;
              }
@@ -1581,13 +1675,22 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
              */
 
               if (!cupsdSendHeader(con, HTTP_OK, "text/html"))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "\r\n") < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (cupsdFlushHeader(con) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_OK);
            }
@@ -1604,7 +1707,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              */
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              break;
            }
@@ -1612,14 +1718,20 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                                          sizeof(buf))) == NULL)
            {
              if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html"))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_NOT_FOUND);
            }
            else if (!check_if_modified(con, &filestats))
             {
               if (!cupsdSendError(con, HTTP_NOT_MODIFIED))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_NOT_MODIFIED);
            }
@@ -1636,24 +1748,39 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
               if (!cupsdSendHeader(con, HTTP_OK, line))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n",
                             httpGetDateString(filestats.st_mtime)) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
              if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
                             (unsigned long)filestats.st_size) < 0)
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
 
               cupsdLogRequest(con, HTTP_OK);
            }
 
             if (httpPrintf(HTTP(con), "\r\n") < 0)
-             return (cupsdCloseClient(con));
+           {
+             cupsdCloseClient(con);
+             return;
+           }
 
            if (cupsdFlushHeader(con) < 0)
-             return (cupsdCloseClient(con));
+            {
+             cupsdCloseClient(con);
+             return;
+           }
 
             con->http.state = HTTP_WAITING;
             break;
@@ -1679,35 +1806,45 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                            "CHUNKED" : "LENGTH",
                        CUPS_LLCAST con->http.data_remaining, con->file);
 
-        if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
-         return (cupsdCloseClient(con));
-       else if (bytes > 0)
+        do
        {
-         con->bytes += bytes;
+          if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+         {
+           cupsdCloseClient(con);
+           return;
+         }
+         else if (bytes > 0)
+         {
+           con->bytes += bytes;
 
-          cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                         "cupsdReadClient: %d writing %d bytes to %d",
-                         con->http.fd, bytes, con->file);
+            cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                           "cupsdReadClient: %d writing %d bytes to %d",
+                           con->http.fd, bytes, con->file);
 
-          if (write(con->file, line, bytes) < bytes)
-         {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdReadClient: Unable to write %d bytes to %s: %s",
-                           bytes, con->filename, strerror(errno));
+            if (write(con->file, line, bytes) < bytes)
+           {
+              cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "cupsdReadClient: Unable to write %d bytes to %s: %s",
+                             bytes, con->filename, strerror(errno));
 
-           cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdReadClient: Closing data file %d...",
-                           con->file);
+             cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                             "cupsdReadClient: Closing data file %d...",
+                             con->file);
 
-           close(con->file);
-           con->file = -1;
-           unlink(con->filename);
-           cupsdClearString(&con->filename);
+             close(con->file);
+             con->file = -1;
+             unlink(con->filename);
+             cupsdClearString(&con->filename);
 
-            if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
+              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+           }
          }
-       }
+        }
+       while (con->http.state == HTTP_PUT_RECV && con->http.used > 0);
 
         if (con->http.state == HTTP_WAITING)
        {
@@ -1740,7 +1877,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
            cupsdClearString(&con->filename);
 
             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
+           {
+             cupsdCloseClient(con);
+             return;
+           }
          }
 
          /*
@@ -1754,7 +1894,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          */
 
           if (!cupsdSendError(con, status))
-           return (cupsdCloseClient(con));
+         {
+           cupsdCloseClient(con);
+           return;
+         }
        }
         break;
 
@@ -1767,94 +1910,112 @@ cupsdReadClient(cupsd_client_t *con)   /* I - Client to read from */
                            "CHUNKED" : "LENGTH",
                        CUPS_LLCAST con->http.data_remaining, con->file);
 
-        if (con->request)
+        do
        {
-        /*
-         * Grab any request data from the connection...
-         */
-
-         if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
+          if (con->request)
          {
-            cupsdLogMessage(CUPSD_LOG_ERROR,
-                           "cupsdReadClient: %d IPP Read Error!",
-                           con->http.fd);
+          /*
+           * Grab any request data from the connection...
+           */
 
-           cupsdSendError(con, HTTP_BAD_REQUEST);
-           return (cupsdCloseClient(con));
-         }
-         else if (ipp_state != IPP_DATA)
-         {
-            if (con->http.state == HTTP_POST_SEND)
+           if ((ipp_state = ippRead(&(con->http), con->request)) == IPP_ERROR)
            {
+              cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "cupsdReadClient: %d IPP Read Error!",
+                             con->http.fd);
+
              cupsdSendError(con, HTTP_BAD_REQUEST);
-             return (cupsdCloseClient(con));
+             cupsdCloseClient(con);
+             return;
            }
+           else if (ipp_state != IPP_DATA)
+           {
+              if (con->http.state == HTTP_POST_SEND)
+             {
+               cupsdSendError(con, HTTP_BAD_REQUEST);
+               cupsdCloseClient(con);
+               return;
+             }
 
-           break;
-          }
-         else
-           con->bytes += ippLength(con->request);
-       }
+             break;
+            }
+           else
+             con->bytes += ippLength(con->request);
+         }
 
-        if (con->file < 0 && con->http.state != HTTP_POST_SEND)
-       {
-         /*
-         * Create a file as needed for the request data...
-         */
+          if (con->file < 0 && con->http.state != HTTP_POST_SEND)
+         {
+           /*
+           * Create a file as needed for the request data...
+           */
 
-          cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
-         con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+            cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++);
+           con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
 
-          cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
-                         con->filename, con->file);
+            cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd,
+                           con->filename, con->file);
 
-         if (con->file < 0)
-         {
-           if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-             return (cupsdCloseClient(con));
-         }
+           if (con->file < 0)
+           {
+             if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+             {
+               cupsdCloseClient(con);
+               return;
+             }
+           }
 
-         fchmod(con->file, 0640);
-         fchown(con->file, RunUser, Group);
-          fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
-       }
+           fchmod(con->file, 0640);
+           fchown(con->file, RunUser, Group);
+            fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+         }
 
-       if (con->http.state != HTTP_POST_SEND)
-       {
-          if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
-           return (cupsdCloseClient(con));
-         else if (bytes > 0)
+         if (con->http.state != HTTP_POST_SEND)
          {
-           con->bytes += bytes;
+            if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+           {
+             cupsdCloseClient(con);
+             return;
+           }
+           else if (bytes > 0)
+           {
+             con->bytes += bytes;
 
-            cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                           "cupsdReadClient: %d writing %d bytes to %d",
-                           con->http.fd, bytes, con->file);
+              cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                             "cupsdReadClient: %d writing %d bytes to %d",
+                             con->http.fd, bytes, con->file);
 
-            if (write(con->file, line, bytes) < bytes)
-           {
-              cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdReadClient: Unable to write %d bytes to %s: %s",
-                             bytes, con->filename, strerror(errno));
+              if (write(con->file, line, bytes) < bytes)
+             {
+               cupsdLogMessage(CUPSD_LOG_ERROR,
+                               "cupsdReadClient: Unable to write %d bytes to %s: %s",
+                               bytes, con->filename, strerror(errno));
 
-             cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                             "cupsdReadClient: Closing file %d...",
-                             con->file);
+               cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                               "cupsdReadClient: Closing file %d...",
+                               con->file);
 
-             close(con->file);
-             con->file = -1;
-             unlink(con->filename);
-             cupsdClearString(&con->filename);
+               close(con->file);
+               con->file = -1;
+               unlink(con->filename);
+               cupsdClearString(&con->filename);
 
-              if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
+             }
+           }
+           else if (con->http.state == HTTP_POST_RECV)
+              return;
+           else if (con->http.state != HTTP_POST_SEND)
+           {
+             cupsdCloseClient(con);
+             return;
            }
          }
-         else if (con->http.state == HTTP_POST_RECV)
-            return (1); /* ??? */
-         else if (con->http.state != HTTP_POST_SEND)
-           return (cupsdCloseClient(con));
-       }
+        }
+       while (con->http.state == HTTP_POST_RECV && con->http.used > 0);
 
        if (con->http.state == HTTP_POST_SEND)
        {
@@ -1895,7 +2056,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
               }
 
               if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE))
-               return (cupsdCloseClient(con));
+             {
+               cupsdCloseClient(con);
+               return;
+             }
            }
 
            if (con->command)
@@ -1903,7 +2067,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
              if (!cupsdSendCommand(con, con->command, con->options, 0))
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND))
-                 return (cupsdCloseClient(con));
+               {
+                 cupsdCloseClient(con);
+                 return;
+               }
               }
              else
                cupsdLogRequest(con, HTTP_OK);
@@ -1911,7 +2078,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
          }
 
           if (con->request)
-           return (cupsdProcessIPPRequest(con));
+         {
+           cupsdProcessIPPRequest(con);
+           return;
+         }
        }
         break;
 
@@ -1920,9 +2090,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
   }
 
   if (!con->http.keep_alive && con->http.state == HTTP_WAITING)
-    return (cupsdCloseClient(con));
-  else
-    return (1);
+    cupsdCloseClient(con);
 }
 
 
@@ -1974,14 +2142,7 @@ cupsdSendCommand(
 
   fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdSendCommand: Adding fd %d to InputSet...", con->file);
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdSendCommand: Adding fd %d to OutputSet...",
-                  con->http.fd);
-
-  FD_SET(con->file, InputSet);
-  FD_SET(con->http.fd, OutputSet);
+  cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con);
 
   con->sent_header = 0;
   con->file_ready  = 0;
@@ -2300,7 +2461,7 @@ cupsdUpdateCGI(void)
  * 'cupsdWriteClient()' - Write data to a client as needed.
  */
 
-int                                    /* O - 1 if success, 0 if fail */
+void
 cupsdWriteClient(cupsd_client_t *con)  /* I - Client connection */
 {
   int          bytes;                  /* Number of bytes written */
@@ -2319,7 +2480,28 @@ cupsdWriteClient(cupsd_client_t *con)    /* I - Client connection */
 
   if (con->http.state != HTTP_GET_SEND &&
       con->http.state != HTTP_POST_SEND)
-    return (1);
+    return;
+
+  if (con->pipe_pid)
+  {
+   /*
+    * Make sure we select on the CGI output...
+    */
+
+    cupsdAddSelect(con->file, (cupsd_selfunc_t)cupsdWritePipe, NULL, con);
+
+    if (!con->file_ready)
+    {
+     /*
+      * Try again later when there is CGI output available...
+      */
+
+      cupsdRemoveSelect(con->http.fd);
+      return;
+    }
+
+    con->file_ready = 0;
+  }
 
   if (con->response)
   {
@@ -2365,7 +2547,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
              con->sent_header = 2;
 
              if (httpPrintf(HTTP(con), "Content-Length: 0\r\n") < 0)
-               return (0);
+               return;
            }
            else if (!strncasecmp(buf, "Status:", 7))
            {
@@ -2380,7 +2562,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
              if (con->http.version == HTTP_1_1)
              {
                if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n") < 0)
-                 return (0);
+                 return;
              }
             }
          }
@@ -2410,7 +2592,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
             if (cupsdFlushHeader(con) < 0)
            {
              cupsdCloseClient(con);
-             return (0);
+             return;
            }
 
            if (con->http.version == HTTP_1_1)
@@ -2435,7 +2617,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
         httpPrintf(HTTP(con), "%s", buf);
 
         con->http.activity = time(NULL);
-        return (1);
+        return;
       }
       else if (bytes == 0)
         con->http.activity = time(NULL);
@@ -2450,7 +2632,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
                        con->http.fd, bytes);
 
        cupsdCloseClient(con);
-       return (0);
+       return;
       }
 
       con->bytes += bytes;
@@ -2474,27 +2656,17 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
       if (httpWrite2(HTTP(con), "", 0) < 0)
       {
         cupsdCloseClient(con);
-       return (0);
+       return;
       }
     }
 
     con->http.state = HTTP_WAITING;
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdWriteClient: Removing fd %d from OutputSet...",
-                    con->http.fd);
-
-    FD_CLR(con->http.fd, OutputSet);
+    cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
 
     if (con->file >= 0)
     {
-      if (FD_ISSET(con->file, InputSet))
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                       "cupsdWriteClient: Removing fd %d from InputSet...",
-                        con->file);
-       FD_CLR(con->file, InputSet);
-      }
+      cupsdRemoveSelect(con->file);
 
       if (con->pipe_pid)
        cupsdEndProcess(con->pipe_pid, 0);
@@ -2535,25 +2707,28 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
     if (!con->http.keep_alive)
     {
       cupsdCloseClient(con);
-      return (0);
-    }
-  }
-  else
-  {
-    con->file_ready = 0;
-
-    if (con->pipe_pid && !FD_ISSET(con->file, InputSet))
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdWriteClient: Adding fd %d to InputSet...",
-                     con->file);
-      FD_SET(con->file, InputSet);
+      return;
     }
   }
 
   con->http.activity = time(NULL);
+}
 
-  return (1);
+
+/*
+ * 'cupsdWritePipe()' - Flag that data is available on the CGI pipe.
+ */
+
+void
+cupsdWritePipe(cupsd_client_t *con)    /* I - Client connection */
+{
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdWritePipe: CGI output on fd %d...",
+                  con->file);
+
+  con->file_ready = 1;
+
+  cupsdRemoveSelect(con->file);
+  cupsdAddSelect(con->http.fd, NULL, (cupsd_selfunc_t)cupsdWriteClient, con);
 }
 
 
@@ -4228,10 +4403,8 @@ write_file(cupsd_client_t *con,          /* I - Client connection */
   else
     con->http._data_remaining = INT_MAX;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "write_file: Adding fd %d to OutputSet...", con->http.fd);
-
-  FD_SET(con->http.fd, OutputSet);
+  cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+                 (cupsd_selfunc_t)cupsdWriteClient, con);
 
   return (1);
 }
index 5fd53edb42b789e4ede49c170b6fad3271621f69..bf74e9611889accbb841f28ace6cf172d46a45e5 100644 (file)
@@ -114,7 +114,7 @@ extern void cupsdDeleteAllListeners(void);
 extern int     cupsdFlushHeader(cupsd_client_t *con);
 extern void    cupsdPauseListening(void);
 extern int     cupsdProcessIPPRequest(cupsd_client_t *con);
-extern int     cupsdReadClient(cupsd_client_t *con);
+extern void    cupsdReadClient(cupsd_client_t *con);
 extern void    cupsdResumeListening(void);
 extern int     cupsdSendCommand(cupsd_client_t *con, char *command,
                                 char *options, int root);
@@ -125,7 +125,8 @@ extern void cupsdShutdownClient(cupsd_client_t *con);
 extern void    cupsdStartListening(void);
 extern void    cupsdStopListening(void);
 extern void    cupsdUpdateCGI(void);
-extern int     cupsdWriteClient(cupsd_client_t *con);
+extern void    cupsdWriteClient(cupsd_client_t *con);
+extern void    cupsdWritePipe(cupsd_client_t *con);
 
 
 /*
index ebaa350aa87517668e4ac227e667651c72763d91..a7ec3868cd127aba62b2f44e45711eab5c4a7897 100644 (file)
@@ -150,14 +150,18 @@ extern const char *cups_hstrerror(int);
 #define RELOAD_CUPSD   2               /* Reload only cupsd.conf */
 
 
+/*
+ * Select callback function type...
+ */
+
+typedef void (*cupsd_selfunc_t)(void *data);
+
+
 /*
  * Globals...
  */
 
-VAR int                        MaxFDs,         /* Maximum number of files */
-                       SetSize;        /* The size of the input/output sets */
-VAR fd_set             *InputSet,      /* Input files for select() */
-                       *OutputSet;     /* Output files for select() */
+VAR int                        MaxFDs;         /* Maximum number of files */
 
 VAR time_t             ReloadTime      VALUE(0);
                                        /* Time of reload request... */
@@ -202,6 +206,14 @@ extern int cupsdStartProcess(const char *command, char *argv[],
                                  char *envp[], int infd, int outfd,
                                  int errfd, int backfd, int root, int *pid);
 
+extern int     cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
+                              cupsd_selfunc_t write_cb, void *data);
+extern int     cupsdDoSelect(long timeout);
+extern int     cupsdIsSelecting(int fd);
+extern void    cupsdRemoveSelect(int fd);
+extern void    cupsdStartSelect(void);
+extern void    cupsdStopSelect(void);
+
 
 /*
  * End of "$Id$".
index 7a943c04e9c75b19bb83d132ca7fb589f1ca58ae..dac46ef3c12d43dc3db02edeb7b26e8705af338b 100644 (file)
@@ -945,11 +945,8 @@ cupsdStartBrowsing(void)
       * We only listen if we want remote printers...
       */
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdStartBrowsing: Adding fd %d to InputSet...",
-                      BrowseSocket);
-
-      FD_SET(BrowseSocket, InputSet);
+      cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)cupsdUpdateCUPSBrowse,
+                     NULL, NULL);
     }
   }
   else
@@ -1150,10 +1147,7 @@ cupsdStartPolling(void)
   * Finally, add the pipe to the input selection set...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
-
-  FD_SET(PollPipe, InputSet);
+  cupsdAddSelect(PollPipe, (cupsd_selfunc_t)cupsdUpdatePolling, NULL, NULL);
 }
 
 
@@ -1180,11 +1174,7 @@ cupsdStopBrowsing(void)
     close(BrowseSocket);
 #endif /* WIN32 */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                   "cupsdStopBrowsing: Removing fd %d from InputSet...",
-                   BrowseSocket);
-
-    FD_CLR(BrowseSocket, InputSet);
+    cupsdRemoveSelect(BrowseSocket);
     BrowseSocket = -1;
   }
 
@@ -1228,9 +1218,7 @@ cupsdStopPolling(void)
     cupsdStatBufDelete(PollStatusBuffer);
     close(PollPipe);
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
-    FD_CLR(PollPipe, InputSet);
+    cupsdRemoveSelect(PollPipe);
 
     PollPipe         = -1;
     PollStatusBuffer = NULL;
index b84b2fc178a116f8825c72abd06b4523c2ea3e32..e654a754846feeb45867c4c83d6f4c0b3b44df73 100644 (file)
@@ -661,11 +661,8 @@ cupsdProcessIPPRequest(
        con->http.data_remaining = length;
       }
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdProcessIPPRequest: Adding fd %d to OutputSet...",
-                     con->http.fd);
-
-      FD_SET(con->http.fd, OutputSet);
+      cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
+                     (cupsd_selfunc_t)cupsdWriteClient, con);
 
      /*
       * Tell the caller the response header was sent successfully...
@@ -3759,7 +3756,7 @@ copy_model(cupsd_client_t *con,           /* I - Client connection */
            const char     *from,       /* I - Source file */
            const char     *to)         /* I - Destination file */
 {
-  fd_set       *input;                 /* select() input set */
+  fd_set       input;                  /* select() input set */
   struct timeval timeout;              /* select() timeout */
   int          maxfd;                  /* Maximum file descriptor for select() */
   char         tempfile[1024];         /* Temporary PPD file */
@@ -3812,24 +3809,12 @@ copy_model(cupsd_client_t *con,         /* I - Client connection */
 
   cupsdOpenPipe(temppipe);
 
-  if ((input = calloc(1, SetSize)) == NULL)
-  {
-    close(tempfd);
-    unlink(tempfile);
-
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "copy_model: Unable to allocate %d bytes for select()...",
-                    SetSize);
-    return (-1);
-  }
-
   cupsdLogMessage(CUPSD_LOG_DEBUG,
                   "copy_model: Running \"cups-driverd cat %s\"...", from);
 
   if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
                          -1, 0, &temppid))
   {
-    free(input);
     close(tempfd);
     unlink(tempfile);
     return (-1);
@@ -3856,13 +3841,14 @@ copy_model(cupsd_client_t *con,         /* I - Client connection */
 
     bytes = 0;
 
-    FD_SET(temppipe[0], input);
-    FD_SET(CGIPipes[0], input);
+    FD_ZERO(&input);
+    FD_SET(temppipe[0], &input);
+    FD_SET(CGIPipes[0], &input);
 
     timeout.tv_sec  = 30;
     timeout.tv_usec = 0;
 
-    if ((i = select(maxfd, input, NULL, NULL, &timeout)) < 0)
+    if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
     {
       if (errno == EINTR)
         continue;
@@ -3878,7 +3864,7 @@ copy_model(cupsd_client_t *con,           /* I - Client connection */
       break;
     }
 
-    if (FD_ISSET(temppipe[0], input))
+    if (FD_ISSET(temppipe[0], &input))
     {
      /*
       * Read the PPD file from the pipe, and write it to the PPD file.
@@ -3895,15 +3881,13 @@ copy_model(cupsd_client_t *con,         /* I - Client connection */
        break;
     }
 
-    if (FD_ISSET(CGIPipes[0], input))
+    if (FD_ISSET(CGIPipes[0], &input))
       cupsdUpdateCGI();
   }
 
   close(temppipe[0]);
   close(tempfd);
 
-  free(input);
-
   if (!total)
   {
    /*
index 3d1f977e27506c2442b732a4e44f929f40f630a4..4fc7bdfc9c02f1d2e61a118411af609013a528d9 100644 (file)
@@ -480,11 +480,7 @@ cupsdFinishJob(cupsd_job_t *job)   /* I - Job */
     * Close the pipe and clear the input bit.
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdFinishJob: Removing fd %d from InputSet...",
-                    job->status_buffer->fd);
-
-    FD_CLR(job->status_buffer->fd, InputSet);
+    cupsdRemoveSelect(job->status_buffer->fd);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                    "cupsdFinishJob: Closing status pipes [ %d %d ]...",
@@ -1619,11 +1615,7 @@ cupsdStopJob(cupsd_job_t *job,           /* I - Job */
     * Close the pipe and clear the input bit.
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStopJob: Removing fd %d from InputSet...",
-                   job->status_buffer->fd);
-
-    FD_CLR(job->status_buffer->fd, InputSet);
+    cupsdRemoveSelect(job->status_buffer->fd);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "cupsdStopJob: Closing status pipes [ %d %d ]...",
@@ -3396,11 +3388,8 @@ start_job(cupsd_job_t     *job,          /* I - Job ID */
 
   free(argv);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "start_job: Adding fd %d to InputSet...",
-                  job->status_buffer->fd);
-
-  FD_SET(job->status_buffer->fd, InputSet);
+  cupsdAddSelect(job->status_buffer->fd, (cupsd_selfunc_t)cupsdUpdateJob, NULL,
+                 job);
 
   cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.",
                 job->id);
index 9c8302da96c3ec9059be60b0624d579ea2143af0..c9244d573e54d39c1a174399927202c6278fd0c8 100644 (file)
@@ -90,14 +90,7 @@ cupsdPauseListening(void)
   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
        lis;
        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdPauseListening: Removing fd %d from InputSet...",
-                      lis->fd);
-
-      FD_CLR(lis->fd, InputSet);
-    }
+    cupsdRemoveSelect(lis->fd);
 }
 
 
@@ -123,13 +116,7 @@ cupsdResumeListening(void)
   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
        lis;
        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdResumeListening: Adding fd %d to InputSet...",
-                      lis->fd);
-      FD_SET(lis->fd, InputSet);
-    }
+    cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
 }
 
 
index 9dd55474ed2f44743a178f9601c2803e0ddfe2e6..031855490f973031c121a60fbe42b3ca2a52a18a 100644 (file)
@@ -126,8 +126,6 @@ main(int  argc,                             /* I - Number of command-line args */
   char                 *opt;           /* Option character */
   int                  fg;             /* Run in the foreground */
   int                  fds;            /* Number of ready descriptors */
-  fd_set               *input,         /* Input set for select() */
-                       *output;        /* Output set for select() */
   cupsd_client_t       *con;           /* Current client */
   cupsd_job_t          *job;           /* Current job */
   cupsd_listener_t     *lis;           /* Current listener */
@@ -143,7 +141,7 @@ main(int  argc,                             /* I - Number of command-line args */
   size_t               string_count,   /* String count */
                        alloc_bytes,    /* Allocated string bytes */
                        total_bytes;    /* Total string bytes */
-  struct timeval       timeout;        /* select() timeout */
+  long                 timeout;        /* Timeout for cupsdDoSelect() */
   struct rlimit                limit;          /* Runtime limit */
 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction     action;         /* Actions for POSIX signals */
@@ -372,33 +370,23 @@ main(int  argc,                           /* I - Number of command-line args */
 
   getrlimit(RLIMIT_NOFILE, &limit);
 
+#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
   if (limit.rlim_max > FD_SETSIZE)
     MaxFDs = FD_SETSIZE;
   else
+#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
+#ifdef RLIM_INFINITY
+  if (limit.rlim_max == RLIM_INFINITY)
+    MaxFDs = 16384;
+  else
+#endif /* RLIM_INFINITY */
     MaxFDs = limit.rlim_max;
 
   limit.rlim_cur = MaxFDs;
 
   setrlimit(RLIMIT_NOFILE, &limit);
 
- /*
-  * Allocate memory for the input and output sets...
-  */
-
-  SetSize = (MaxFDs + 31) / 8 + 4;
-  if (SetSize < sizeof(fd_set))
-    SetSize = sizeof(fd_set);
-
-  InputSet  = (fd_set *)calloc(1, SetSize);
-  OutputSet = (fd_set *)calloc(1, SetSize);
-  input     = (fd_set *)calloc(1, SetSize);
-  output    = (fd_set *)calloc(1, SetSize);
-
-  if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL)
-  {
-    syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!");
-    return (1);
-  }
+  cupsdStartSelect();
 
  /*
   * Read configuration...
@@ -658,18 +646,15 @@ main(int  argc,                           /* I - Number of command-line args */
     }
 
    /*
-    * Check for available input or ready output.  If select() returns
-    * 0 or -1, something bad happened and we should exit immediately.
+    * Check for available input or ready output.  If cupsdDoSelect()
+    * returns 0 or -1, something bad happened and we should exit
+    * immediately.
     *
     * Note that we at least have one listening socket open at all
     * times.
     */
 
-    memcpy(input, InputSet, SetSize);
-    memcpy(output, OutputSet, SetSize);
-
-    timeout.tv_sec  = select_timeout(fds);
-    timeout.tv_usec = 0;
+    timeout = select_timeout(fds);
 
 #if HAVE_LAUNCHD
    /*
@@ -678,29 +663,19 @@ main(int  argc,                           /* I - Number of command-line args */
     * inactivity...
     */
 
-    if (timeout.tv_sec == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
+    if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
        (!Browsing || !(BrowseLocalProtocols & BROWSE_DNSSD) ||
         cupsArrayCount(Printers) == 0))
     {
-      timeout.tv_sec    = LaunchdTimeout;
+      timeout           = LaunchdTimeout;
       launchd_idle_exit = 1;
     }
     else
       launchd_idle_exit = 0;
 #endif /* HAVE_LAUNCHD */
 
-    if (timeout.tv_sec < 86400)                /* Only use timeout for < 1 day */
-      fds = select(MaxFDs, input, output, NULL, &timeout);
-    else
-      fds = select(MaxFDs, input, output, NULL, NULL);
-
-    if (fds < 0)
+    if ((fds = cupsdDoSelect(timeout)) < 0)
     {
-      char     s[16384],               /* String buffer */
-               *sptr;                  /* Pointer into buffer */
-      int      slen;                   /* Length of string buffer */
-
-
      /*
       * Got an error from select!
       */
@@ -712,37 +687,9 @@ main(int  argc,                            /* I - Number of command-line args */
       * Log all sorts of debug info to help track down the problem.
       */
 
-      cupsdLogMessage(CUPSD_LOG_EMERG, "select() failed - %s!",
+      cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
                       strerror(errno));
 
-      strcpy(s, "InputSet =");
-      slen = 10;
-      sptr = s + 10;
-
-      for (i = 0; i < MaxFDs; i ++)
-        if (FD_ISSET(i, InputSet))
-       {
-          snprintf(sptr, sizeof(s) - slen, " %d", i);
-         slen += strlen(sptr);
-         sptr += strlen(sptr);
-       }
-
-      cupsdLogMessage(CUPSD_LOG_EMERG, "%s", s);
-
-      strcpy(s, "OutputSet =");
-      slen = 11;
-      sptr = s + 11;
-
-      for (i = 0; i < MaxFDs; i ++)
-        if (FD_ISSET(i, OutputSet))
-       {
-          snprintf(sptr, sizeof(s) - slen, " %d", i);
-         slen += strlen(sptr);
-         sptr += strlen(sptr);
-       }
-
-      cupsdLogMessage(CUPSD_LOG_EMERG, "%s", s);
-
       for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
           con;
           i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
@@ -793,67 +740,6 @@ main(int  argc,                            /* I - Number of command-line args */
     }
 #endif /* HAVE_LAUNCHD */
 
-   /*
-    * Check for status info from job filters...
-    */
-
-    for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
-        job;
-        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
-      if (job->status_buffer && FD_ISSET(job->status_buffer->fd, input))
-      {
-       /*
-        * Clear the input bit to avoid updating the next job
-       * using the same status pipe file descriptor...
-       */
-
-        FD_CLR(job->status_buffer->fd, input);
-
-       /*
-        * Read any status messages from the filters...
-       */
-
-        cupsdUpdateJob(job);
-      }
-
-   /*
-    * Update CGI messages as needed...
-    */
-
-    if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input))
-      cupsdUpdateCGI();
-
-   /*
-    * Handle system management events as needed...
-    */
-
-#ifdef __APPLE__
-   /*
-    * Mac OS X provides the SystemConfiguration framework for system
-    * configuration change events...
-    */
-
-    if (SysEventPipes[0] >= 0 && FD_ISSET(SysEventPipes[0], input))
-      cupsdUpdateSystemMonitor();
-#else
-   /*
-    * All other operating systems need to poll for changes...
-    */
-
-    if ((current_time - netif_time) >= 60)
-    {
-      NetIFUpdate = 1;
-      netif_time  = current_time;
-    }
-#endif /* __APPLE__ */
-
-   /*
-    * Update notifier messages as needed...
-    */
-
-    if (NotifierPipes[0] >= 0 && FD_ISSET(NotifierPipes[0], input))
-      cupsdUpdateNotifierStatus();
-
    /*
     * Expire subscriptions and unload completed jobs as needed...
     */
@@ -874,12 +760,6 @@ main(int  argc,                            /* I - Number of command-line args */
 
     if (Browsing && BrowseRemoteProtocols)
     {
-      if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input))
-        cupsdUpdateCUPSBrowse();
-
-      if (PollPipe >= 0 && FD_ISSET(PollPipe, input))
-        cupsdUpdatePolling();
-
 #ifdef HAVE_LIBSLP
       if ((BrowseRemoteProtocols & BROWSE_SLP) &&
           BrowseSLPRefresh <= current_time)
@@ -899,19 +779,6 @@ main(int  argc,                            /* I - Number of command-line args */
       browse_time = current_time;
     }
 
-   /*
-    * Check for new connections on the "listen" sockets...
-    */
-
-    for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
-         lis;
-        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-      if (lis->fd >= 0 && FD_ISSET(lis->fd, input))
-      {
-        FD_CLR(lis->fd, input);
-        cupsdAcceptClient(lis);
-      }
-
    /*
     * Check for new data on the client sockets...
     */
@@ -921,61 +788,13 @@ main(int  argc,                           /* I - Number of command-line args */
         con = (cupsd_client_t *)cupsArrayNext(Clients))
     {
      /*
-      * Process the input buffer...
+      * Process pending data in the input buffer...
       */
 
-      if (FD_ISSET(con->http.fd, input) || con->http.used)
+      if (con->http.used)
       {
-        int fd = con->file;
-
-
-        FD_CLR(con->http.fd, input);
-
-        if (!cupsdReadClient(con))
-       {
-         if (fd >= 0)
-           FD_CLR(fd, input);
-
-         continue;
-       }
-      }
-
-     /*
-      * Write data as needed...
-      */
-
-      if (con->pipe_pid && FD_ISSET(con->file, input))
-      {
-       /*
-        * Keep track of pending input from the file/pipe separately
-       * so that we don't needlessly spin on select() when the web
-       * client is not ready to receive data...
-       */
-
-       FD_CLR(con->file, input);
-        con->file_ready = 1;
-
-#ifdef DEBUG
-        cupsdLogMessage(CUPSD_LOG_DEBUG2, "main: Data ready file %d!",
-                       con->file);
-#endif /* DEBUG */
-
-       if (!FD_ISSET(con->http.fd, output))
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                         "main: Removing fd %d from InputSet...", con->file);
-         FD_CLR(con->file, input);
-         FD_CLR(con->file, InputSet);
-       }
-      }
-
-      if (FD_ISSET(con->http.fd, output))
-      {
-        FD_CLR(con->http.fd, output);
-
-       if (!con->pipe_pid || con->file_ready)
-          if (!cupsdWriteClient(con))
-           continue;
+        cupsdReadClient(con);
+       continue;
       }
 
      /*
@@ -1135,14 +954,7 @@ main(int  argc,                           /* I - Number of command-line args */
       unlink("/var/spool/lp/SCHEDLOCK");
 #endif /* __sgi */
 
- /*
-  * Free memory used by FD sets and return...
-  */
-
-  free(InputSet);
-  free(OutputSet);
-  free(input);
-  free(output);
+  cupsdStopSelect();
 
   return (!stop_scheduler);
 }
diff --git a/scheduler/select.c b/scheduler/select.c
new file mode 100644 (file)
index 0000000..7cd28a3
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * "$Id$"
+ *
+ *   Select abstraction functions for the Common UNIX Printing System (CUPS).
+ *
+ *   Copyright 2006 by Easy Software Products.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Easy Software Products and are protected by Federal
+ *   copyright law.  Distribution and use rights are outlined in the file
+ *   "LICENSE.txt" which should have been included with this file.  If this
+ *   file is missing or damaged please contact Easy Software Products
+ *   at:
+ *
+ *       Attn: CUPS Licensing Information
+ *       Easy Software Products
+ *       44141 Airport View Drive, Suite 204
+ *       Hollywood, Maryland 20636 USA
+ *
+ *       Voice: (301) 373-9600
+ *       EMail: cups-info@cups.org
+ *         WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ *   cupsdAddSelect()    - Add a file descriptor to the list.
+ *   cupsdDoSelect()     - Do a select-like operation.
+ *   cupsdIsSelecting()  - Determine whether we are monitoring a file
+ *                         descriptor.
+ *   cupsdRemoveSelect() - Remove a file descriptor from the list.
+ *   cupsdStartSelect()  - Initialize the file polling engine.
+ *   cupsdStopSelect()   - Shutdown the file polling engine.
+ *   compare_fds()       - Compare file descriptors.
+ *   find_fd()           - Find an existing file descriptor record.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+
+#ifdef HAVE_EPOLL
+#  include <sys/epoll.h>
+#elif defined(HAVE_KQUEUE)
+#  include <sys/event.h>
+#  include <sys/time.h>
+#elif defined(HAVE_POLL)
+#  include <sys/poll.h>
+#elif defined(__hpux)
+#  include <sys/time.h>
+#else
+#  include <sys/select.h>
+#endif /* HAVE_EPOLL */
+
+
+/*
+ * Design Notes for Poll/Select API in CUPSD
+ * -----------------------------------------
+ * 
+ * SUPPORTED APIS
+ * 
+ *     OS              select  poll    epoll   kqueue  /dev/poll
+ *     --------------  ------  ------  ------  ------  ---------
+ *     AIX             YES     YES     NO      NO      NO
+ *     FreeBSD         YES     YES     NO      YES     NO
+ *     HP-UX           YES     YES     NO      NO      NO
+ *     IRIX            YES     YES     NO      NO      NO
+ *     Linux           YES     YES     YES     NO      NO
+ *     MacOS X         YES     YES     NO      YES     NO
+ *     NetBSD          YES     YES     NO      YES     NO
+ *     OpenBSD         YES     YES     NO      YES     NO
+ *     Solaris         YES     YES     NO      NO      YES
+ *     Tru64           YES     YES     NO      NO      NO
+ *     Windows         YES     NO      NO      NO      NO
+ * 
+ * 
+ * HIGH-LEVEL API
+ * 
+ *     typedef void (*cupsd_selfunc_t)(void *data);
+ * 
+ *     void cupsdStartSelect(void);
+ *     void cupsdStopSelect(void);
+ *     void cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
+ *                         cupsd_selfunc_t write_cb, void *data);
+ *     void cupsdRemoveSelect(int fd);
+ *     int cupsdDoSelect(int timeout);
+ * 
+ * 
+ * IMPLEMENTATION STRATEGY
+ * 
+ *     0. Common Stuff
+ *         a. CUPS array of file descriptor to callback functions
+ *            and data.
+ *         b. cupsdStartSelect() creates the array
+ *         c. cupsdStopSelect() destroys the array and all elements.
+ *         d. cupsdAddSelect() adds to the array and allocates a
+ *            new callback element.
+ *         e. cupsdRemoveSelect() removes from the array and frees
+ *            the callback element.
+ * 
+ *     1. select() O(n)
+ *         a. Input/Output fd_set variables, copied to working
+ *            copies and then used with select().
+ *         b. Loop through CUPS array, using FD_ISSET and calling
+ *            the read/write callbacks as needed.
+ *         c. cupsdRemoveSelect() clears fd_set bit from main and
+ *            working sets.
+ *         d. cupsdStopSelect() frees all of the memory used by the
+ *            CUPS array and fd_set's.
+ * 
+ *     2. poll() - O(n log n)
+ *         a. Regular array of pollfd, sorted the same as the CUPS
+ *            array.
+ *         b. Loop through pollfd array, call the corresponding
+ *            read/write callbacks as needed.
+ *         c. cupsdAddSelect() adds first to CUPS array and flags the
+ *            pollfd array as invalid.
+ *         d. cupsdDoSelect() rebuilds pollfd array as needed, calls
+ *            poll(), then loops through the pollfd array looking up
+ *            as needed.
+ *         e. cupsdRemoveSelect() flags the pollfd array as invalid.
+ *         f. cupsdStopSelect() frees all of the memory used by the
+ *            CUPS array and pollfd array.
+ * 
+ *     3. epoll() - O(n)
+ *         a. cupsdStartSelect() creates epoll file descriptor using
+ *            epoll_create() with the maximum fd count, and
+ *            allocates an events buffer for the maximum fd count.
+ *         b. cupsdAdd/RemoveSelect() uses epoll_ctl() to add
+ *            (EPOLL_CTL_ADD) or remove (EPOLL_CTL_DEL) a single
+ *            event using the level-triggered semantics. The event
+ *            user data field is a pointer to the new callback array
+ *            element.
+ *         c. cupsdDoSelect() uses epoll_wait() with the global event
+ *            buffer allocated in cupsdStartSelect() and then loops
+ *            through the events, using the user data field to find
+ *            the callback record.
+ *         d. cupsdStopSelect() closes the epoll file descriptor and
+ *            frees all of the memory used by the event buffer.
+ * 
+ *     4. kqueue() - O(n)
+ *         b. cupsdStartSelect() creates kqueue file descriptor
+ *            using kqyeue() function and allocates a global event
+ *            buffer.
+ *         c. cupsdAdd/RemoveSelect() uses EV_SET and kevent() to
+ *            register the changes. The event user data field is a
+ *            pointer to the new callback array element.
+ *         d. cupsdDoSelect() uses kevent() to poll for events and
+ *            loops through the events, using the user data field to
+ *            find the callback record.
+ *         e. cupsdStopSelect() closes the kqyeye() file descriptor
+ *            and frees all of the memory used by the event buffer.
+ * 
+ *     5. /dev/poll - O(n log n) - NOT YET IMPLEMENTED
+ *         a. cupsdStartSelect() opens /dev/poll and allocates an
+ *            array of pollfd structs; on failure to open /dev/poll,
+ *            revert to poll() system call.
+ *         b. cupsdAddSelect() writes a single pollfd struct to
+ *            /dev/poll with the new file descriptor and the
+ *            POLLIN/POLLOUT flags.
+ *         c. cupsdRemoveSelect() writes a single pollfd struct to
+ *            /dev/poll with the file descriptor and the POLLREMOVE
+ *            flag.
+ *         d. cupsdDoSelect() uses the DP_POLL ioctl to retrieve
+ *            events from /dev/poll and then loops through the
+ *            returned pollfd array, looking up the file descriptors
+ *            as needed.
+ *         e. cupsdStopSelect() closes /dev/poll and frees the
+ *            pollfd array.
+ */
+
+/*
+ * Local structures...
+ */
+
+typedef struct _cupsd_fd_s
+{
+  int                  fd;             /* File descriptor */
+  cupsd_selfunc_t      read_cb,        /* Read callback */
+                       write_cb;       /* Write callback */
+  void                 *data;          /* Data pointer for callbacks */
+} _cupsd_fd_t;
+
+
+/*
+ * Local globals...
+ */
+
+static cups_array_t    *cupsd_fds = NULL;
+
+#ifdef HAVE_EPOLL
+static int             cupsd_epoll_fd = -1;
+static struct epoll_event *cupsd_epoll_events = NULL;
+#elif defined(HAVE_KQUEUE)
+static int             cupsd_kqueue_fd = -1,
+                       cupsd_kqueue_changes = 0;
+static struct kevent   *cupsd_kqueue_events = NULL;
+#elif defined(HAVE_POLL)
+static int             cupsd_alloc_pollfds = 0,
+                       cupsd_update_pollfds = 0;
+static struct pollfd   *cupsd_pollfds = NULL;
+#else /* select() */
+static fd_set          cupsd_global_input,
+                       cupsd_global_output,
+                       cupsd_current_input,
+                       cupsd_current_output;
+#endif /* HAVE_EPOLL */
+
+
+/*
+ * Local functions...
+ */
+
+static int             compare_fds(_cupsd_fd_t *a, _cupsd_fd_t *b);
+static _cupsd_fd_t     *find_fd(int fd);
+
+
+/*
+ * 'cupsdAddSelect()' - Add a file descriptor to the list.
+ */
+
+int                                    /* O - 1 on success, 0 on error */
+cupsdAddSelect(int             fd,     /* I - File descriptor */
+               cupsd_selfunc_t read_cb,        /* I - Read callback */
+               cupsd_selfunc_t write_cb,/* I - Write callback */
+              void            *data)   /* I - Data to pass to callback */
+{
+  _cupsd_fd_t  *fdptr;                 /* File descriptor record */
+  int          added;                  /* 1 if added, 0 if modified */
+
+
+ /*
+  * Range check input...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdAddSelect: fd=%d, read_cb=%p, write_cb=%p, data=%p",
+                 fd, read_cb, write_cb, data);
+
+  if (fd < 0)
+    return (0);
+
+ /*
+  * See if this FD has already been added...
+  */
+
+  if ((fdptr = find_fd(fd)) == NULL)
+  {
+   /*
+    * No, add a new entry...
+    */
+
+    if ((fdptr = calloc(1, sizeof(_cupsd_fd_t))) == NULL)
+      return (0);
+
+    fdptr->fd = fd;
+
+    if (!cupsArrayAdd(cupsd_fds, fdptr))
+    {
+      cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to add fd %d to array!", fd);
+      free(fdptr);
+      return (0);
+    }
+
+    added = 1;
+  }
+  else
+    added = 0;
+
+#ifdef HAVE_EPOLL
+  {
+    struct epoll_event event;          /* Event data */
+
+
+    event.events = 0;
+
+    if (read_cb)
+      event.events |= EPOLLIN;
+
+    if (write_cb)
+      event.events |= EPOLLOUT;
+
+    event.data.ptr = fdptr;
+
+    epoll_ctl(cupsd_epoll_fd, added ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd,
+              &event);
+  }
+
+#elif defined(HAVE_KQUEUE)
+  {
+    struct kevent      event;          /* Event data */
+    struct timespec    timeout;        /* Timeout value */
+
+
+    timeout.tv_sec  = 0;
+    timeout.tv_nsec = 0;
+
+    if (fdptr->read_cb != read_cb)
+    {
+      if (read_cb)
+        EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, fdptr);
+      else
+        EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
+
+      if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+      {
+       cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                       "cupsdAddSelect: kevent() returned %s",
+                       strerror(errno));
+       return (0);
+      }
+    }
+
+    if (fdptr->write_cb != write_cb)
+    {
+      if (write_cb)
+        EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, fdptr);
+      else
+        EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
+
+      if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+      {
+       cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                       "cupsdAddSelect: kevent() returned %s",
+                       strerror(errno));
+       return (0);
+      }
+    }
+  }
+
+#elif defined(HAVE_POLL)
+  cupsd_update_pollfds = 1;
+
+#else /* select() */
+ /*
+  * Add or remove the file descriptor in the input and output sets
+  * for select()...
+  */
+
+  if (read_cb)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAddSelect: Adding fd %d to input set...", fd);
+    FD_SET(fd, &cupsd_global_input);
+  }
+  else
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAddSelect: Removing fd %d from input set...", fd);
+    FD_CLR(fd, &cupsd_global_input);
+    FD_CLR(fd, &cupsd_current_input);
+  }
+
+  if (write_cb)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAddSelect: Adding fd %d to output set...", fd);
+    FD_SET(fd, &cupsd_global_output);
+  }
+  else
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAddSelect: Removing fd %d from output set...", fd);
+    FD_CLR(fd, &cupsd_global_output);
+    FD_CLR(fd, &cupsd_current_output);
+  }
+#endif /* HAVE_EPOLL */
+
+ /*
+  * Save the (new) read and write callbacks...
+  */
+
+  fdptr->read_cb  = read_cb;
+  fdptr->write_cb = write_cb;
+  fdptr->data     = data;
+
+  return (1);
+}
+
+
+/*
+ * 'cupsdDoSelect()' - Do a select-like operation.
+ */
+
+int                                    /* O - Number of files or -1 on error */
+cupsdDoSelect(long timeout)            /* I - Timeout in seconds */
+{
+  int                  nfds;           /* Number of file descriptors */
+  _cupsd_fd_t          *fdptr;         /* Current file descriptor */
+#ifdef HAVE_EPOLL
+  int                  i;              /* Looping var */
+  struct epoll_event   *event;         /* Current event */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdDoSelect: polling %d fds for %ld seconds...",
+                 cupsArrayCount(cupsd_fds), timeout);
+
+  if (timeout >= 0 && timeout < 86400)
+    nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs,
+                      timeout * 1000);
+  else
+    nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, -1);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: epoll() returned %d...",
+                  nfds);
+
+  for (i = nfds, event = cupsd_epoll_events; i > 0; i --, event ++)
+  {
+    fdptr = (_cupsd_fd_t *)event->data.ptr;
+
+    if (fdptr->read_cb && (event->events & (EPOLLIN | EPOLLERR | EPOLLHUP)))
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...",
+                     fdptr->fd);
+      (*(fdptr->read_cb))(fdptr->data);
+    }
+
+    if (fdptr->write_cb && (event->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)))
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...",
+                     fdptr->fd);
+      (*(fdptr->write_cb))(fdptr->data);
+    }
+  }
+
+#elif defined(HAVE_KQUEUE)
+  int                  i;              /* Looping var */
+  struct kevent                *event;         /* Current event */
+  struct timespec      ktimeout;       /* kevent() timeout */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdDoSelect: polling %d fds for %ld seconds...",
+                 cupsArrayCount(cupsd_fds), timeout);
+
+  if (timeout >= 0 && timeout < 86400)
+  {
+    ktimeout.tv_sec  = timeout;
+    ktimeout.tv_nsec = 0;
+
+    nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs,
+                  &ktimeout);
+  }
+  else
+    nfds = kevent(cupsd_kqueue_fd, NULL, 0, cupsd_kqueue_events, MaxFDs, NULL);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdDoSelect: kevent(%d, ..., %d, ...) returned %d...",
+                  cupsd_kqueue_fd, MaxFDs, nfds);
+
+  cupsd_kqueue_changes = 0;
+
+  for (i = nfds, event = cupsd_kqueue_events; i > 0; i --, event ++)
+  {
+    fdptr = (_cupsd_fd_t *)event->udata;
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "event->filter=%d, event->ident=%d",
+                    event->filter, (int)event->ident);
+
+    if (fdptr->read_cb && event->filter == EVFILT_READ)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...",
+                     fdptr->fd);
+      (*(fdptr->read_cb))(fdptr->data);
+    }
+
+    if (fdptr->write_cb && event->filter == EVFILT_WRITE)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...",
+                     fdptr->fd);
+      (*(fdptr->write_cb))(fdptr->data);
+    }
+  }
+
+#elif defined(HAVE_POLL)
+  struct pollfd                *pfd;           /* Current pollfd structure */
+  int                  count;          /* Number of file descriptors */
+
+
+  count = cupsArrayCount(cupsd_fds);
+
+  if (cupsd_update_pollfds)
+  {
+   /*
+    * Update the cupsd_pollfds array to match the current FD array...
+    */
+
+    cupsd_update_pollfds = 0;
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Updating pollfd array...");
+
+   /*
+    * (Re)allocate memory as needed...
+    */
+
+    if (count > cupsd_alloc_pollfds)
+    {
+      int allocfds = count + 16;
+
+
+      if (cupsd_pollfds)
+       pfd = realloc(cupsd_pollfds, allocfds * sizeof(struct pollfd));
+      else
+       pfd = malloc(allocfds * sizeof(struct pollfd));
+
+      if (!pfd)
+      {
+       cupsdLogMessage(CUPSD_LOG_EMERG,
+                       "Unable to allocate %d bytes for polling!",
+                       (int)(allocfds * sizeof(struct pollfd)));
+
+       return (-1);
+      }
+
+      cupsd_pollfds       = pfd;
+      cupsd_alloc_pollfds = allocfds;
+    }
+
+   /*
+    * Rebuild the array...
+    */
+
+    for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds), pfd = cupsd_pollfds;
+         fdptr;
+        fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds), pfd ++)
+    {
+      pfd->fd      = fdptr->fd;
+      pfd->events  = 0;
+
+      if (fdptr->read_cb)
+       pfd->events |= POLLIN;
+
+      if (fdptr->write_cb)
+       pfd->events |= POLLOUT;
+    }
+  }
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdDoSelect: polling %d fds for %ld seconds...",
+                 count, timeout);
+
+  if (timeout >= 0 && timeout < 86400)
+    nfds = poll(cupsd_pollfds, count, timeout * 1000);
+  else
+    nfds = poll(cupsd_pollfds, count, -1);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: poll() returned %d...",
+                  nfds);
+
+  if (nfds > 0)
+  {
+   /*
+    * Do callbacks for each file descriptor...
+    */
+
+    for (pfd = cupsd_pollfds; count > 0; pfd ++, count --)
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                      "cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
+                     pfd - cupsd_pollfds, pfd->fd, pfd->revents);
+
+      if (!pfd->revents)
+        continue;
+
+      if ((fdptr = find_fd(pfd->fd)) == NULL)
+        continue;
+
+      if (fdptr->read_cb && (pfd->revents & (POLLIN | POLLERR | POLLHUP)))
+      {
+        cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...",
+                       fdptr->fd);
+        (*(fdptr->read_cb))(fdptr->data);
+      }
+
+      if (fdptr->write_cb && (pfd->revents & (POLLOUT | POLLERR | POLLHUP)))
+      {
+        cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...",
+                       fdptr->fd);
+        (*(fdptr->write_cb))(fdptr->data);
+      }
+    }
+  }
+
+#else /* select() */
+  struct timeval       stimeout;       /* Timeout for select() */
+  int                  maxfd;          /* Maximum file descriptor */
+
+
+ /*
+  * Figure out the highest file descriptor number...
+  */
+
+  if ((fdptr = (_cupsd_fd_t *)cupsArrayLast(cupsd_fds)) == NULL)
+    maxfd = 1;
+  else
+    maxfd = fdptr->fd + 1;
+
+ /*
+  * Do the select()...
+  */
+
+  cupsd_current_input  = cupsd_global_input;
+  cupsd_current_output = cupsd_global_output;
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdDoSelect: selecting %d fds for %ld seconds...",
+                 maxfd, timeout);
+
+  if (timeout >= 0 && timeout < 86400)
+  {
+    stimeout.tv_sec  = timeout;
+    stimeout.tv_usec = 0;
+
+    nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
+                  &stimeout);
+  }
+  else
+    nfds = select(maxfd, &cupsd_current_input, &cupsd_current_output, NULL,
+                  NULL);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: select() returned %d...",
+                  nfds);
+
+  if (nfds > 0)
+  {
+   /*
+    * Do callbacks for each file descriptor...
+    */
+
+    for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
+         fdptr;
+        fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
+    {
+      if (fdptr->read_cb && FD_ISSET(fdptr->fd, &cupsd_current_input))
+      {
+        cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Read on fd %d...",
+                       fdptr->fd);
+        (*(fdptr->read_cb))(fdptr->data);
+      }
+
+      if (fdptr->write_cb && FD_ISSET(fdptr->fd, &cupsd_current_output))
+      {
+        cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDoSelect: Write on fd %d...",
+                       fdptr->fd);
+        (*(fdptr->write_cb))(fdptr->data);
+      }
+    }
+  }
+
+#endif /* HAVE_EPOLL */
+
+ /*
+  * Return the number of file descriptors handled...
+  */
+
+  return (nfds);
+}
+
+
+/*
+ * 'cupsdIsSelecting()' - Determine whether we are monitoring a file
+ *                        descriptor.
+ */
+
+int                                    /* O - 1 if selecting, 0 otherwise */
+cupsdIsSelecting(int fd)               /* I - File descriptor */
+{
+  return (find_fd(fd) != NULL);
+}
+
+
+/*
+ * 'cupsdRemoveSelect()' - Remove a file descriptor from the list.
+ */
+
+void
+cupsdRemoveSelect(int fd)              /* I - File descriptor */
+{
+  _cupsd_fd_t          *fdptr;         /* File descriptor record */
+#ifdef HAVE_EPOLL
+  struct epoll_event   event;          /* Event data */
+#elif defined(HAVE_KQUEUE)
+  struct kevent                event;          /* Event data */
+  struct timespec      timeout;        /* Timeout value */
+#elif defined(HAVE_POLL)
+  /* No variables for poll() */
+#endif /* HAVE_EPOLL */
+
+
+ /*
+  * Range check input...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRemoveSelect: fd=%d", fd);
+
+  if (fd < 0)
+    return;
+
+ /*
+  * Find the file descriptor...
+  */
+
+  if ((fdptr = find_fd(fd)) == NULL)
+    return;
+
+#ifdef HAVE_EPOLL
+  epoll_ctl(cupsd_epoll_fd, EPOLL_CTL_DEL, fd, &event);
+
+#elif defined(HAVE_KQUEUE)
+  timeout.tv_sec  = 0;
+  timeout.tv_nsec = 0;
+
+  if (fdptr->read_cb)
+  {
+    EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, fdptr);
+
+    if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                     "cupsdRemoveSelect: kevent() returned %s",
+                     strerror(errno));
+      return;
+    }
+  }
+
+  if (fdptr->write_cb)
+  {
+    EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdptr);
+
+    if (kevent(cupsd_kqueue_fd, &event, 1, NULL, 0, &timeout))
+    {
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                     "cupsdRemoveSelect: kevent() returned %s",
+                     strerror(errno));
+      return;
+    }
+  }
+
+
+#elif defined(HAVE_POLL)
+ /*
+  * Update the pollfds array...
+  */
+
+  cupsd_update_pollfds = 1;
+
+#else /* select() */
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdRemoveSelect: Removing fd %d from input and output "
+                 "sets...", fd);
+  FD_CLR(fd, &cupsd_global_input);
+  FD_CLR(fd, &cupsd_global_output);
+  FD_CLR(fd, &cupsd_current_input);
+  FD_CLR(fd, &cupsd_current_output);
+#endif /* HAVE_EPOLL */
+
+ /*
+  * Remove the file descriptor for from the FD array...
+  */
+
+  cupsArrayRemove(cupsd_fds, fdptr);
+  free(fdptr);
+}
+
+
+/*
+ * 'cupsdStartSelect()' - Initialize the file polling engine.
+ */
+
+void
+cupsdStartSelect(void)
+{
+  cupsd_fds = cupsArrayNew((cups_array_func_t)compare_fds, NULL);
+
+#ifdef HAVE_EPOLL
+  cupsd_epoll_fd     = epoll_create(MaxFDs);
+  cupsd_epoll_events = calloc(MaxFDs, sizeof(struct epoll_event));
+
+#elif defined(HAVE_KQUEUE)
+  cupsd_kqueue_fd      = kqueue();
+  cupsd_kqueue_changes = 0;
+  cupsd_kqueue_events  = calloc(MaxFDs, sizeof(struct kevent));
+
+#elif defined(HAVE_POLL)
+  cupsd_update_pollfds = 0;
+
+#else /* select() */
+  FD_ZERO(&cupsd_global_input);
+  FD_ZERO(&cupsd_global_output);
+#endif /* HAVE_EPOLL */
+}
+
+
+/*
+ * 'cupsdStopSelect()' - Shutdown the file polling engine.
+ */
+
+void
+cupsdStopSelect(void)
+{
+  _cupsd_fd_t  *fdptr;                 /* Current file descriptor */
+
+
+  for (fdptr = (_cupsd_fd_t *)cupsArrayFirst(cupsd_fds);
+       fdptr;
+       fdptr = (_cupsd_fd_t *)cupsArrayNext(cupsd_fds))
+    free(fdptr);
+
+  cupsArrayDelete(cupsd_fds);
+  cupsd_fds = NULL;
+
+#ifdef HAVE_EPOLL
+  if (cupsd_epoll_events)
+  {
+    free(cupsd_epoll_events);
+    cupsd_epoll_events = NULL;
+  }
+
+  if (cupsd_epoll_fd >= 0)
+  {
+    close(cupsd_epoll_fd);
+    cupsd_epoll_fd = -1;
+  }
+
+#elif defined(HAVE_KQUEUE)
+  if (cupsd_kqueue_events)
+  {
+    free(cupsd_kqueue_events);
+    cupsd_kqueue_events = NULL;
+  }
+
+  if (cupsd_kqueue_fd >= 0)
+  {
+    close(cupsd_kqueue_fd);
+    cupsd_kqueue_fd = -1;
+  }
+
+  cupsd_kqueue_changes = 0;
+
+#elif defined(HAVE_POLL)
+  if (cupsd_pollfds)
+  {
+    free(cupsd_pollfds);
+    cupsd_pollfds       = NULL;
+    cupsd_alloc_pollfds = 0;
+  }
+
+  cupsd_update_pollfds = 0;
+
+#else /* select() */
+  FD_ZERO(&cupsd_global_input);
+  FD_ZERO(&cupsd_global_output);
+#endif /* HAVE_EPOLL */
+}
+
+
+/*
+ * 'compare_fds()' - Compare file descriptors.
+ */
+
+static int                             /* O - Result of comparison */
+compare_fds(_cupsd_fd_t *a,            /* I - First file descriptor */
+            _cupsd_fd_t *b)            /* I - Second file descriptor */
+{
+  return (a->fd - b->fd);
+}
+
+
+/*
+ * 'find_fd()' - Find an existing file descriptor record.
+ */
+
+static _cupsd_fd_t *                   /* O - FD record pointer or NULL */
+find_fd(int fd)                                /* I - File descriptor */
+{
+  _cupsd_fd_t  *fdptr,                 /* Matching record (if any) */
+               key;                    /* Search key */
+
+
+  cupsArraySave(cupsd_fds);
+
+  key.fd = fd;
+  fdptr  = (_cupsd_fd_t *)cupsArrayFind(cupsd_fds, &key);
+
+  cupsArrayRestore(cupsd_fds);
+
+  return (fdptr);
+}
+
+
+/*
+ * End of "$Id$".
+ */
index 057f7767aacb533139e35738d8c56d3406880cbf..f48a633ac2f3f623e4a0e2ce20d30f507c5b5f25 100644 (file)
@@ -107,10 +107,7 @@ cupsdStartServer(void)
   {
     CGIStatusBuffer = cupsdStatBufNew(CGIPipes[0], "[CGI]");
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStartServer: Adding fd %d to InputSet...",
-                   CGIPipes[0]);
-    FD_SET(CGIPipes[0], InputSet);
+    cupsdAddSelect(CGIPipes[0], (cupsd_selfunc_t)cupsdUpdateCGI, NULL, NULL);
   }
 
  /*
@@ -158,11 +155,7 @@ cupsdStopServer(void)
 
   if (CGIPipes[0] >= 0)
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStopServer: Removing fd %d from InputSet...",
-                    CGIPipes[0]);
-
-    FD_CLR(CGIPipes[0], InputSet);
+    cupsdRemoveSelect(CGIPipes[0]);
 
     cupsdStatBufDelete(CGIStatusBuffer);
     close(CGIPipes[1]);
index c972f92683682235ae12b919ada1c09f5d61baf3..6e5cac700afdb11301a1b0e876e649fd8af74884 100644 (file)
@@ -1226,10 +1226,7 @@ cupsdStopAllNotifiers(void)
 
   if (NotifierPipes[0] >= 0)
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStopAllNotifiers: Removing fd %d from InputSet...",
-                   NotifierPipes[0]);
-    FD_CLR(NotifierPipes[0], InputSet);
+    cupsdRemoveSelect(NotifierPipes[0]);
 
     cupsdStatBufDelete(NotifierStatusBuffer);
 
@@ -1571,11 +1568,8 @@ cupsd_start_notifier(
 
     NotifierStatusBuffer = cupsdStatBufNew(NotifierPipes[0], "[Notifier]");
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "start_notifier: Adding fd %d to InputSet...",
-                   NotifierPipes[0]);
-
-    FD_SET(NotifierPipes[0], InputSet);
+    cupsdAddSelect(NotifierPipes[0], (cupsd_selfunc_t)cupsdUpdateNotifierStatus,
+                   NULL, NULL);
   }
 
   if (cupsdOpenPipe(fds))
index 8f86b36d0451bbb094294ab95274a273a5c9d7e7..83a339dca5bc34ddc13a3205de6977c16245768c 100644 (file)
@@ -160,10 +160,8 @@ cupsdStartSystemMonitor(void)
     return;
   }
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdStartSystemMonitor: Adding fd %d to InputSet...",
-                  SysEventPipes[0]);
-  FD_SET(SysEventPipes[0], InputSet);
+  cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)cupsdUpdateSystemMonitor,
+                 NULL, NULL);
 
  /*
   * Set non-blocking mode on the descriptor we will be receiving notification
@@ -220,12 +218,7 @@ cupsdStopSystemMonitor(void)
 
   if (SysEventPipes[0] >= 0)
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdStopSystemMonitor: Removing fd %d from InputSet...",
-                   SysEventPipes[0]);
-
-    FD_CLR(SysEventPipes[0], InputSet);
-
+    cupsdRemoveSelect(SysEventPipes[0]);
     cupsdClosePipe(SysEventPipes);
   }
 }