gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r27749 - in libmicrohttpd: . src/include src/microhttpd src


From: gnunet
Subject: [GNUnet-SVN] r27749 - in libmicrohttpd: . src/include src/microhttpd src/testcurl
Date: Thu, 4 Jul 2013 17:29:56 +0200

Author: grothoff
Date: 2013-07-04 17:29:56 +0200 (Thu, 04 Jul 2013)
New Revision: 27749

Modified:
   libmicrohttpd/ChangeLog
   libmicrohttpd/src/include/microhttpd.h
   libmicrohttpd/src/microhttpd/connection.c
   libmicrohttpd/src/microhttpd/connection.h
   libmicrohttpd/src/microhttpd/daemon.c
   libmicrohttpd/src/microhttpd/internal.h
   libmicrohttpd/src/microhttpd/memorypool.c
   libmicrohttpd/src/testcurl/Makefile.am
   libmicrohttpd/src/testcurl/perf_get.c
   libmicrohttpd/src/testcurl/perf_get_concurrent.c
   libmicrohttpd/src/testcurl/test_get.c
   libmicrohttpd/src/testcurl/test_quiesce.c
   libmicrohttpd/src/testcurl/test_start_stop.c
Log:
Adding support for using epoll for the MHD event loop

Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog     2013-07-04 15:27:59 UTC (rev 27748)
+++ libmicrohttpd/ChangeLog     2013-07-04 15:29:56 UTC (rev 27749)
@@ -6,6 +6,35 @@
        because the application queued a response immediately ---
        reserve that behavior for PUT/POST. -CG
 
+Tue Jun 25 15:08:30 CEST 2013
+       Added option 'MHD_USE_DUAL_STACK' to support a single
+       daemon for IPv4 and IPv6 without the application having
+       to do the binding. -CG
+
+Mon Jun 24 22:33:34 CEST 2013
+       Finished integration with epoll, including benchmarking and
+       documentation. -CG
+
+Sun Jun 23 15:28:13 CEST 2013
+       Added option 'MHD_USE_PIPE_FOR_SHUTDOWN' to cleanly support
+       'MHD_quiesce_daemon' with thread pools and per-connection
+       threads (we then need a pipe for shutdown, but if
+       'MHD_quiesce_daemon' is not used, we do not want to
+       require the use of a pipe; introducing the pipe after
+       the threads have been started can also fail, so the
+       application needs to tell us early on). -CG
+
+Sat Jun 22 20:24:17 CEST 2013
+       Removed locking calls for thread modes that do not need them.
+       Reorganized way to obtain connection's event loop state.
+       Added sorted XDLL for connections with default timeout to
+       avoid having to loop over all connections to determine current
+       timeout (custom per-connection timeouts are in another list
+       which is iterated each time). -CG
+
+Fri Jun 21 20:55:48 CEST 2013
+       Preparing build system and tests for epoll support. -CG
+
 Tue May 21 14:34:36 CEST 2013
        Improving configure tests for OpenSSL and spdylay to
        avoid build errors in libmicrospdy code if those libraries

Modified: libmicrohttpd/src/include/microhttpd.h
===================================================================
--- libmicrohttpd/src/include/microhttpd.h      2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/include/microhttpd.h      2013-07-04 15:29:56 UTC (rev 
27749)
@@ -356,8 +356,11 @@
   MHD_USE_SELECT_INTERNALLY = 8,
 
   /**
-   * Run using the IPv6 protocol (otherwise, MHD will
-   * just support IPv4).
+   * Run using the IPv6 protocol (otherwise, MHD will just support
+   * IPv4).  If you want MHD to support IPv4 and IPv6 using a single
+   * socket, pass MHD_USE_DUAL_STACK, otherwise, if you only pass
+   * this option, MHD will try to bind to IPv6-only (resulting in
+   * no IPv4 support).
    */
   MHD_USE_IPv6 = 16,
 
@@ -428,8 +431,13 @@
    * specify it), if 'MHD_USE_NO_LISTEN_SOCKET' is specified.  In
    * "external" select mode, this option is always simply ignored.
    */
-  MHD_USE_PIPE_FOR_SHUTDOWN = 1024
+  MHD_USE_PIPE_FOR_SHUTDOWN = 1024,
 
+  /**
+   * Use a single socket for IPv4 and IPv6.
+   */
+  MHD_USE_DUAL_STACK = MHD_USE_IPv6 | 2048
+
 };
 
 

Modified: libmicrohttpd/src/microhttpd/connection.c
===================================================================
--- libmicrohttpd/src/microhttpd/connection.c   2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/microhttpd/connection.c   2013-07-04 15:29:56 UTC (rev 
27749)
@@ -318,8 +318,9 @@
 
   daemon = connection->daemon;
   SHUTDOWN (connection->socket_fd, 
-           (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
+           (MHD_YES == connection->read_closed) ? SHUT_WR : SHUT_RDWR);
   connection->state = MHD_CONNECTION_CLOSED;
+  connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
   if ( (NULL != daemon->notify_completed) &&
        (MHD_YES == connection->client_aware) )
     daemon->notify_completed (daemon->notify_completed_cls, 
@@ -745,8 +746,8 @@
       kind = MHD_FOOTER_KIND;
       off = 0;
     }
-  must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) &&
-                    (connection->read_closed == MHD_YES) &&
+  must_add_close = ( (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) &&
+                    (MHD_YES == connection->read_closed) &&
                     (0 == strcasecmp (connection->version,
                                       MHD_HTTP_VERSION_1_1)) &&
                     (NULL == MHD_get_response_header (connection->response,
@@ -853,87 +854,16 @@
 
 
 /**
- * Add "fd" to the "fd_set".  If "fd" is
- * greater than "*max", set "*max" to fd.
+ * Update the 'event_loop_info' field of this connection based on the state
+ * that the connection is now in.  May also close the connection or
+ * perform other updates to the connection if needed to prepare for
+ * the next round of the event loop.
  *
- * @param fd file descriptor to add to the set
- * @param set set to modify
- * @param max_fd maximum value to potentially update
+ * @param connection connetion to get poll set for 
  */
 static void
-add_to_fd_set (int fd, 
-              fd_set *set, 
-              int *max_fd)
+MHD_connection_update_event_loop_info (struct MHD_Connection *connection)
 {
-  FD_SET (fd, set);
-  if ( (NULL != max_fd) &&
-       (fd > *max_fd) )
-    *max_fd = fd;
-}
-
-
-/**
- * Obtain the select sets for this connection.  The given
- * sets (and the maximum) are updated and must have 
- * already been initialized.
- *
- * @param connection connetion to get select sets for
- * @param read_fd_set read set to initialize
- * @param write_fd_set write set to initialize
- * @param except_fd_set except set to initialize (never changed)
- * @param max_fd where to store largest FD put into any set
- * @return MHD_YES on success
- */
-int
-MHD_connection_get_fdset (struct MHD_Connection *connection,
-                          fd_set *read_fd_set,
-                          fd_set *write_fd_set,
-                          fd_set *except_fd_set, 
-                         int *max_fd)
-{
-  int ret;
-  struct MHD_Pollfd p;
-
-  /* we use the 'poll fd' as a convenient way to re-use code 
-     when determining the select sets */
-  memset (&p, 0, sizeof(struct MHD_Pollfd));
-  ret = MHD_connection_get_pollfd (connection, &p);
-  if ( (MHD_YES == ret) && (p.fd >= 0) ) {
-    if (0 != (p.events & MHD_POLL_ACTION_IN)) 
-      add_to_fd_set(p.fd, read_fd_set, max_fd);    
-    if (0 != (p.events & MHD_POLL_ACTION_OUT)) 
-      add_to_fd_set(p.fd, write_fd_set, max_fd);    
-  }
-  return ret;
-}
-
-
-/**
- * Obtain the pollfd for this connection
- *
- * @param connection connetion to get poll set for 
- * @param p where to store the polling information
- * @return MHD_YES on success. If return MHD_YES and p->fd < 0, this 
- *                 connection is not waiting for any read or write events
- */
-int
-MHD_connection_get_pollfd (struct MHD_Connection *connection, 
-                          struct MHD_Pollfd *p)
-{
-  int fd;
-
-  if (NULL == connection->pool)
-    connection->pool = MHD_pool_create (connection->daemon->pool_size);
-  if (NULL == connection->pool)
-    {
-      CONNECTION_CLOSE_ERROR (connection,
-                             "Failed to create memory pool!\n");
-      return MHD_YES;
-    }
-  fd = connection->socket_fd;
-  p->fd = fd;
-  if (-1 == fd)
-    return MHD_YES;
   while (1)
     {
 #if DEBUG_STATES
@@ -945,9 +875,9 @@
 #if HTTPS_SUPPORT     
        case MHD_TLS_CONNECTION_INIT:
          if (0 == gnutls_record_get_direction (connection->tls_session))
-            p->events |= MHD_POLL_ACTION_IN;
+            connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
          else
-           p->events |= MHD_POLL_ACTION_OUT;
+            connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
          break;
 #endif
         case MHD_CONNECTION_INIT:
@@ -955,16 +885,9 @@
         case MHD_CONNECTION_HEADER_PART_RECEIVED:
           /* while reading headers, we always grow the
              read buffer if needed, no size-check required */
-          if ((connection->read_closed) &&
-              (0 == connection->read_buffer_offset))
+          if ( (connection->read_buffer_offset == 
connection->read_buffer_size) &&
+              (MHD_NO == try_grow_read_buffer (connection)) )
             {
-             CONNECTION_CLOSE_ERROR (connection, 
-                                     "Connection buffer to small for 
request\n");
-              continue;
-            }
-          if ((connection->read_buffer_offset == connection->read_buffer_size)
-              && (MHD_NO == try_grow_read_buffer (connection)))
-            {
               transmit_error_response (connection,
                                        (connection->url != NULL)
                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
@@ -972,18 +895,19 @@
                                        REQUEST_TOO_BIG);
               continue;
             }
-          if (MHD_NO == connection->read_closed)
-            p->events |= MHD_POLL_ACTION_IN;
+         if (MHD_NO == connection->read_closed)
+           connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+         else
+           connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
           break;
         case MHD_CONNECTION_HEADERS_RECEIVED:
-          /* we should never get here */
           EXTRA_CHECK (0);
           break;
         case MHD_CONNECTION_HEADERS_PROCESSED:
           EXTRA_CHECK (0);
           break;
         case MHD_CONNECTION_CONTINUE_SENDING:
-          p->events |= MHD_POLL_ACTION_OUT;
+          connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
           break;
         case MHD_CONNECTION_CONTINUE_SENT:
           if (connection->read_buffer_offset == connection->read_buffer_size)
@@ -1010,9 +934,11 @@
                   continue;
                 }
             }
-          if ((connection->read_buffer_offset < connection->read_buffer_size)
-              && (MHD_NO == connection->read_closed))
-            p->events |= MHD_POLL_ACTION_IN;
+          if ( (connection->read_buffer_offset < connection->read_buffer_size) 
&&
+              (MHD_NO == connection->read_closed) )
+           connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
+         else
+           connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
           break;
         case MHD_CONNECTION_BODY_RECEIVED:
         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
@@ -1024,50 +950,49 @@
                                      NULL);
               continue;
             }
-          p->events |= MHD_POLL_ACTION_IN;
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
           /* transition to FOOTERS_RECEIVED
              happens in read handler */
           break;
         case MHD_CONNECTION_FOOTERS_RECEIVED:
-          /* no socket action, wait for client
-             to provide response */
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
           break;
         case MHD_CONNECTION_HEADERS_SENDING:
           /* headers in buffer, keep writing */
-          p->events |= MHD_POLL_ACTION_OUT;
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
           break;
         case MHD_CONNECTION_HEADERS_SENT:
           EXTRA_CHECK (0);
           break;
         case MHD_CONNECTION_NORMAL_BODY_READY:
-          p->events |= MHD_POLL_ACTION_OUT;
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
           break;
         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
-          /* not ready, no socket action */
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
           break;
         case MHD_CONNECTION_CHUNKED_BODY_READY:
-          p->events |= MHD_POLL_ACTION_OUT;
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
           break;
         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
-          /* not ready, no socket action */
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_BLOCK;
           break;
         case MHD_CONNECTION_BODY_SENT:
           EXTRA_CHECK (0);
           break;
         case MHD_CONNECTION_FOOTERS_SENDING:
-          p->events |= MHD_POLL_ACTION_OUT;
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
           break;
         case MHD_CONNECTION_FOOTERS_SENT:
           EXTRA_CHECK (0);
           break;
         case MHD_CONNECTION_CLOSED:
-          return MHD_YES;       /* do nothing, not even reading */
+         connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
+          return;       /* do nothing, not even reading */
         default:
           EXTRA_CHECK (0);
         }
       break;
     }
-  return MHD_YES;
 }
 
 
@@ -1888,10 +1813,41 @@
 
 
 /**
+ * Update the 'last_activity' field of the connection to the current time
+ * and move the connection to the head of the 'normal_timeout' list if
+ * the timeout for the connection uses the default value.
+ *
+ * @param connection the connection that saw some activity
+ */
+static void
+update_last_activity (struct MHD_Connection *connection)
+{
+  struct MHD_Daemon *daemon = connection->daemon;
+
+  connection->last_activity = MHD_monotonic_time();
+  if (connection->connection_timeout != daemon->connection_timeout)
+    return; /* custom timeout, no need to move it in DLL */
+
+  /* move connection to head of timeout list (by remove + add operation) */
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
+    MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+  XDLL_remove (daemon->normal_timeout_head,
+              daemon->normal_timeout_tail,
+              connection);
+  XDLL_insert (daemon->normal_timeout_head,
+              daemon->normal_timeout_tail,
+              connection);
+  if  ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
+    MHD_PANIC ("Failed to release cleanup mutex\n");    
+}
+
+
+
+/**
  * This function handles a particular connection when it has been
- * determined that there is data to be read off a socket. All
- * implementations (multithreaded, external select, internal select)
- * call this function to handle reads.
+ * determined that there is data to be read off a socket. 
  *
  * @param connection connection to handle
  * @return always MHD_YES (we should continue to process the
@@ -1900,7 +1856,7 @@
 int
 MHD_connection_handle_read (struct MHD_Connection *connection)
 {
-  connection->last_activity = MHD_monotonic_time();
+  update_last_activity (connection);
   if (connection->state == MHD_CONNECTION_CLOSED)
     return MHD_YES;
   /* make sure "read" has a reasonable number of bytes
@@ -1953,9 +1909,7 @@
 
 /**
  * This function was created to handle writes to sockets when it has
- * been determined that the socket can be written to. All
- * implementations (multithreaded, external select, internal select)
- * call this function
+ * been determined that the socket can be written to.
  *
  * @param connection connection to handle
  * @return always MHD_YES (we should continue to process the
@@ -1966,7 +1920,8 @@
 {
   struct MHD_Response *response;
   int ret;
-  connection->last_activity = MHD_monotonic_time();
+
+  update_last_activity (connection);
   while (1)
     {
 #if DEBUG_STATES
@@ -2111,9 +2066,7 @@
 
 /**
  * This function was created to handle per-connection processing that
- * has to happen even if the socket cannot be read or written to.  All
- * implementations (multithreaded, external select, internal select)
- * call this function.
+ * has to happen even if the socket cannot be read or written to. 
  *
  * @param connection connection to handle
  * @return MHD_YES if we should continue to process the
@@ -2122,7 +2075,7 @@
 int
 MHD_connection_handle_idle (struct MHD_Connection *connection)
 {
-  struct MHD_Daemon *daemon;
+  struct MHD_Daemon *daemon = connection->daemon;
   unsigned int timeout;
   const char *end;
   int rend;
@@ -2131,18 +2084,18 @@
   while (1)
     {
 #if DEBUG_STATES
-      MHD_DLOG (connection->daemon, "%s: state: %s\n",
+      MHD_DLOG (daemon, "%s: state: %s\n",
                 __FUNCTION__, MHD_state_to_string (connection->state));
 #endif
       switch (connection->state)
         {
         case MHD_CONNECTION_INIT:
           line = get_next_header_line (connection);
-          if (line == NULL)
+          if (NULL == line)
             {
-              if (connection->state != MHD_CONNECTION_INIT)
+              if (MHD_CONNECTION_INIT != connection->state)
                 continue;
-              if (connection->read_closed)
+              if (MHD_YES == connection->read_closed)
                 {
                  CONNECTION_CLOSE_ERROR (connection, 
                                          NULL);
@@ -2159,9 +2112,9 @@
           line = get_next_header_line (connection);
           if (line == NULL)
             {
-              if (connection->state != MHD_CONNECTION_URL_RECEIVED)
+              if (MHD_CONNECTION_URL_RECEIVED != connection->state)
                 continue;
-              if (connection->read_closed)
+              if (MHD_YES == connection->read_closed)
                 {
                  CONNECTION_CLOSE_ERROR (connection, 
                                          NULL);
@@ -2189,7 +2142,7 @@
             {
               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
                 continue;
-              if (connection->read_closed)
+              if (MHD_YES == connection->read_closed)
                 {
                  CONNECTION_CLOSE_ERROR (connection, 
                                          NULL);
@@ -2232,7 +2185,7 @@
               /* force close, in case client still tries to upload... */
               connection->read_closed = MHD_YES;
             }
-          connection->state = (connection->remaining_upload_size == 0)
+          connection->state = (0 == connection->remaining_upload_size)
             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
           continue;
         case MHD_CONNECTION_CONTINUE_SENDING:
@@ -2269,7 +2222,7 @@
             {
               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
                 continue;
-              if (connection->read_closed)
+              if (MHD_YES == connection->read_closed)
                 {
                  CONNECTION_CLOSE_ERROR (connection, 
                                          NULL);
@@ -2297,7 +2250,7 @@
             {
               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
                 continue;
-              if (connection->read_closed)
+              if (MHD_YES == connection->read_closed)
                 {
                  CONNECTION_CLOSE_ERROR (connection, 
                                          NULL);
@@ -2421,11 +2374,10 @@
                   ( (end != NULL) && (0 == strcasecmp (end, "close")) ) );
           MHD_destroy_response (connection->response);
           connection->response = NULL;
-          if (connection->daemon->notify_completed != NULL)
-           connection->daemon->notify_completed (connection->daemon->
-                                                 notify_completed_cls,
-                                                 connection,
-                                                 &connection->client_context,
+          if (daemon->notify_completed != NULL)
+           daemon->notify_completed (daemon->notify_completed_cls,
+                                     connection,
+                                     &connection->client_context,
                                                  
MHD_REQUEST_TERMINATED_COMPLETED_OK);     
          connection->client_aware = MHD_NO;
           end =
@@ -2478,21 +2430,26 @@
              MHD_destroy_response (connection->response);
              connection->response = NULL;
            }
-         daemon = connection->daemon;
-         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to acquire cleanup mutex\n");
-           }
+         if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+              (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )  
        
+           MHD_PANIC ("Failed to acquire cleanup mutex\n");            
+         if (connection->connection_timeout == daemon->connection_timeout)
+           XDLL_remove (daemon->normal_timeout_head,
+                        daemon->normal_timeout_tail,
+                        connection);
+         else
+           XDLL_remove (daemon->manual_timeout_head,
+                        daemon->manual_timeout_tail,
+                        connection);
          DLL_remove (daemon->connections_head,
                      daemon->connections_tail,
                      connection);
          DLL_insert (daemon->cleanup_head,
                      daemon->cleanup_tail,
                      connection);
-         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to release cleanup mutex\n");
-           }
+         if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+              (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex)) ) 
        
+           MHD_PANIC ("Failed to release cleanup mutex\n");        
          return MHD_NO;
         default:
           EXTRA_CHECK (0);
@@ -2507,6 +2464,32 @@
       MHD_connection_close (connection, 
MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
       return MHD_YES;
     }
+  MHD_connection_update_event_loop_info (connection);
+  switch (connection->event_loop_info)
+    {
+    case MHD_EVENT_LOOP_INFO_READ:
+      if (0 != (connection->epoll_state & MHD_EPOLL_STATE_READ_READY))
+       EDLL_insert (daemon->eready_head,
+                    daemon->eready_tail,
+                    connection);
+      break;
+    case MHD_EVENT_LOOP_INFO_WRITE:
+      if (0 != (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))
+       EDLL_insert (daemon->eready_head,
+                    daemon->eready_tail,
+                    connection);
+      break;
+    case MHD_EVENT_LOOP_INFO_BLOCK:
+      /* we should look at this connection again in the next iteration
+        of the event loop, as we're waiting on the application */
+      EDLL_insert (daemon->eready_head,
+                  daemon->eready_tail,
+                  connection);      
+      break;
+    case MHD_EVENT_LOOP_INFO_CLEANUP:
+      /* This connection is finished, nothing left to do */
+      break;
+    }
   return MHD_YES;
 }
 
@@ -2582,13 +2565,37 @@
                           ...)
 {
   va_list ap;
+  struct MHD_Daemon *daemon;
 
+  daemon = connection->daemon;      
   switch (option)
     {
     case MHD_CONNECTION_OPTION_TIMEOUT:
+      if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+          (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
+       MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+      if (connection->connection_timeout == daemon->connection_timeout)
+       XDLL_remove (daemon->normal_timeout_head,
+                    daemon->normal_timeout_tail,
+                    connection);
+      else
+       XDLL_remove (daemon->manual_timeout_head,
+                    daemon->manual_timeout_tail,
+                    connection);
       va_start (ap, option);
       connection->connection_timeout = va_arg (ap, unsigned int);
       va_end (ap);
+      if (connection->connection_timeout == daemon->connection_timeout)
+       XDLL_insert (daemon->normal_timeout_head,
+                    daemon->normal_timeout_tail,
+                    connection);
+      else
+       XDLL_insert (daemon->manual_timeout_head,
+                    daemon->manual_timeout_tail,
+                    connection);
+      if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+          (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
+       MHD_PANIC ("Failed to release cleanup mutex\n");    
       return MHD_YES;
     default:
       return MHD_NO;

Modified: libmicrohttpd/src/microhttpd/connection.h
===================================================================
--- libmicrohttpd/src/microhttpd/connection.h   2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/microhttpd/connection.h   2013-07-04 15:29:56 UTC (rev 
27749)
@@ -31,38 +31,6 @@
 
 
 /**
- * Obtain the select sets for this connection.   The given
- * sets (and the maximum) are updated and must have 
- * already been initialized.
- *
- * @param connection connetion to get select sets for
- * @param read_fd_set read set to initialize
- * @param write_fd_set write set to initialize
- * @param except_fd_set except set to initialize (never changed)
- * @param max_fd where to store largest FD put into any set
- * @return MHD_YES on success
- */
-int
-MHD_connection_get_fdset (struct MHD_Connection *connection,
-                          fd_set * read_fd_set,
-                          fd_set * write_fd_set,
-                          fd_set * except_fd_set, int *max_fd);
-
-
-/**
- * Obtain the pollfd for this connection. The poll interface allows large
- * file descriptors. Select goes stupid when the fd overflows fdset (which
- * is fixed).
- *
- * @param connection connetion to get poll set for 
- * @param p where to store the polling information
- */
-int 
-MHD_connection_get_pollfd (struct MHD_Connection *connection,
-                          struct MHD_Pollfd *p);
-
-
-/**
  * Set callbacks for this connection to those for HTTP.
  *
  * @param connection connection to initialize

Modified: libmicrohttpd/src/microhttpd/daemon.c
===================================================================
--- libmicrohttpd/src/microhttpd/daemon.c       2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/microhttpd/daemon.c       2013-07-04 15:29:56 UTC (rev 
27749)
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+  (C) 2007-2013 Daniel Pittman and Christian Grothoff
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -39,7 +39,6 @@
 
 #if HTTPS_SUPPORT
 #include "connection_https.h"
-#include <gnutls/gnutls.h>
 #include <gcrypt.h>
 #endif
 
@@ -178,7 +177,7 @@
  * @param daemon handle to daemon where lock is
  */
 static void
-MHD_ip_count_lock(struct MHD_Daemon *daemon)
+MHD_ip_count_lock (struct MHD_Daemon *daemon)
 {
   if (0 != pthread_mutex_lock(&daemon->per_ip_connection_mutex))
     {
@@ -193,7 +192,7 @@
  * @param daemon handle to daemon where lock is
  */
 static void
-MHD_ip_count_unlock(struct MHD_Daemon *daemon)
+MHD_ip_count_unlock (struct MHD_Daemon *daemon)
 {
   if (0 != pthread_mutex_unlock(&daemon->per_ip_connection_mutex))
     {
@@ -212,7 +211,7 @@
  * @return -1, 0 or 1 depending on result of compare
  */
 static int
-MHD_ip_addr_compare(const void *a1, const void *a2)
+MHD_ip_addr_compare (const void *a1, const void *a2)
 {
   return memcmp (a1, a2, offsetof (struct MHD_IPCount, count));
 }
@@ -227,9 +226,9 @@
  * @return MHD_YES on success and MHD_NO otherwise (e.g., invalid address type)
  */
 static int
-MHD_ip_addr_to_key(const struct sockaddr *addr, 
-                  socklen_t addrlen,
-                   struct MHD_IPCount *key)
+MHD_ip_addr_to_key (const struct sockaddr *addr, 
+                   socklen_t addrlen,
+                   struct MHD_IPCount *key)
 {
   memset(key, 0, sizeof(*key));
 
@@ -268,9 +267,9 @@
  *   Also returns MHD_NO if fails to allocate memory.
  */
 static int
-MHD_ip_limit_add(struct MHD_Daemon *daemon,
-                 const struct sockaddr *addr,
-                socklen_t addrlen)
+MHD_ip_limit_add (struct MHD_Daemon *daemon,
+                 const struct sockaddr *addr,
+                 socklen_t addrlen)
 {
   struct MHD_IPCount *key;
   void **nodep;
@@ -332,9 +331,9 @@
  * @param addrlen number of bytes in addr
  */
 static void
-MHD_ip_limit_del(struct MHD_Daemon *daemon,
-                 const struct sockaddr *addr,
-                socklen_t addrlen)
+MHD_ip_limit_del (struct MHD_Daemon *daemon,
+                 const struct sockaddr *addr,
+                 socklen_t addrlen)
 {
   struct MHD_IPCount search_key;
   struct MHD_IPCount *found_key;
@@ -392,7 +391,11 @@
 {
   int res;
 
-  connection->tls_read_ready = MHD_NO;
+  if (MHD_YES == connection->tls_read_ready)
+    {
+      connection->daemon->num_tls_read_ready--;
+      connection->tls_read_ready = MHD_NO;
+    }
   res = gnutls_record_recv (connection->tls_session, other, i);
   if ( (GNUTLS_E_AGAIN == res) ||
        (GNUTLS_E_INTERRUPTED == res) )
@@ -404,12 +407,15 @@
     {
       /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
         disrupted); set errno to something caller will interpret
-        correctly as a hard error*/
+        correctly as a hard error */
       errno = EPIPE;
       return res;
     }
   if (res == i)
-    connection->tls_read_ready = MHD_YES;
+    {
+      connection->tls_read_ready = MHD_YES;
+      connection->daemon->num_tls_read_ready++;
+    }
   return res;
 }
 
@@ -515,6 +521,26 @@
 
 
 /**
+ * Add "fd" to the "fd_set".  If "fd" is
+ * greater than "*max", set "*max" to fd.
+ *
+ * @param fd file descriptor to add to the set
+ * @param set set to modify
+ * @param max_fd maximum value to potentially update
+ */
+static void
+add_to_fd_set (int fd, 
+              fd_set *set, 
+              int *max_fd)
+{
+  FD_SET (fd, set);
+  if ( (NULL != max_fd) &&
+       (fd > *max_fd) )
+    *max_fd = fd;
+}
+
+
+/**
  * Obtain the select sets for this daemon.
  *
  * @param daemon daemon to get sets from
@@ -546,6 +572,20 @@
        || (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
        || (0 != (daemon->options & MHD_USE_POLL)))
     return MHD_NO;
+#if EPOLL_SUPPORT
+  if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
+    {
+      /* we're in epoll mode, use the epoll FD as a stand-in for
+        the entire event set */
+
+      if (daemon->epoll_fd >= FD_SETSIZE)
+       return MHD_NO; /* poll fd too big, fail hard */
+      FD_SET (daemon->epoll_fd, read_fd_set);
+      if ((*max_fd) < daemon->epoll_fd) 
+       *max_fd = daemon->epoll_fd;
+      return MHD_YES;
+    }
+#endif
   fd = daemon->socket_fd;
   if (-1 != fd)
   {
@@ -555,11 +595,23 @@
       *max_fd = fd;
   }
   for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-    if (MHD_YES != MHD_connection_get_fdset (pos,
-                                            read_fd_set,
-                                            write_fd_set,
-                                            except_fd_set, max_fd))
-      return MHD_NO;    
+    {
+      switch (pos->event_loop_info)
+       {
+       case MHD_EVENT_LOOP_INFO_READ:
+         add_to_fd_set (pos->socket_fd, read_fd_set, max_fd);
+         break;
+       case MHD_EVENT_LOOP_INFO_WRITE:
+         add_to_fd_set (pos->socket_fd, write_fd_set, max_fd);
+         break;
+       case MHD_EVENT_LOOP_INFO_BLOCK:
+         /* not in any FD set */
+         break;
+       case MHD_EVENT_LOOP_INFO_CLEANUP:
+         /* this should never happen */
+         break;
+       }
+    }
 #if DEBUG_CONNECT
   MHD_DLOG (daemon, "Maximum socket in select set: %d\n", *max_fd);
 #endif
@@ -581,14 +633,12 @@
   int num_ready;
   fd_set rs;
   fd_set ws;
-  fd_set es;
   int max;
   struct timeval tv;
   struct timeval *tvp;
   unsigned int timeout;
   time_t now;
 #ifdef HAVE_POLL_H
-  struct MHD_Pollfd mp;
   struct pollfd p[1];
 #endif
 
@@ -607,14 +657,6 @@
          tv.tv_usec = 0;
          tvp = &tv;
        }
-      if ( (MHD_CONNECTION_NORMAL_BODY_UNREADY == con->state) ||
-          (MHD_CONNECTION_CHUNKED_BODY_UNREADY == con->state) )
-       {
-         /* do not block (we're waiting for our callback to succeed) */
-         tv.tv_sec = 0;
-         tv.tv_usec = 0;
-         tvp = &tv;
-       }
 #if HTTPS_SUPPORT
       if (MHD_YES == con->tls_read_ready)
        {
@@ -629,10 +671,25 @@
          /* use select */
          FD_ZERO (&rs);
          FD_ZERO (&ws);
-         FD_ZERO (&es);
          max = 0;
-         MHD_connection_get_fdset (con, &rs, &ws, &es, &max);
-         num_ready = SELECT (max + 1, &rs, &ws, &es, tvp);
+         switch (con->event_loop_info)
+           {
+           case MHD_EVENT_LOOP_INFO_READ:
+             add_to_fd_set (con->socket_fd, &rs, &max);
+             break;
+           case MHD_EVENT_LOOP_INFO_WRITE:
+             add_to_fd_set (con->socket_fd, &ws, &max);
+             break;
+           case MHD_EVENT_LOOP_INFO_BLOCK:
+             tv.tv_sec = 0;
+             tv.tv_usec = 0;
+             tvp = &tv;
+             break;
+           case MHD_EVENT_LOOP_INFO_CLEANUP:
+             /* how did we get here!? */
+             goto exit;
+           }
+         num_ready = SELECT (max + 1, &rs, &ws, NULL, tvp);
          if (num_ready < 0) 
            {
              if (EINTR == errno)
@@ -648,7 +705,7 @@
          /* call appropriate connection handler if necessary */
          if ( (FD_ISSET (con->socket_fd, &rs))
 #if HTTPS_SUPPORT
-                  || (MHD_YES == con->tls_read_ready) 
+              || (MHD_YES == con->tls_read_ready) 
 #endif
               )
            con->read_handler (con);
@@ -661,16 +718,26 @@
       else
        {
          /* use poll */
-         memset(&mp, 0, sizeof (struct MHD_Pollfd));
-         MHD_connection_get_pollfd(con, &mp);
-         memset(&p, 0, sizeof (p));
-         p[0].fd = mp.fd;
-         if (mp.events & MHD_POLL_ACTION_IN) 
-           p[0].events |= POLLIN;        
-         if (mp.events & MHD_POLL_ACTION_OUT) 
-           p[0].events |= POLLOUT;
-         if (poll (p, 
-                   1, 
+         memset (&p, 0, sizeof (p));
+         p[0].fd = con->socket_fd;
+         switch (con->event_loop_info)
+           {
+           case MHD_EVENT_LOOP_INFO_READ:
+             p[0].events |= POLLIN;  
+             break;
+           case MHD_EVENT_LOOP_INFO_WRITE:
+             p[0].events |= POLLOUT;
+             break;
+           case MHD_EVENT_LOOP_INFO_BLOCK:
+             tv.tv_sec = 0;
+             tv.tv_usec = 0;
+             tvp = &tv;
+             break;
+           case MHD_EVENT_LOOP_INFO_CLEANUP:
+             /* how did we get here!? */
+             goto exit;
+           }
+         if (poll (p, 1, 
                    (NULL == tvp) ? -1 : tv.tv_sec * 1000) < 0)
            {
              if (EINTR == errno)
@@ -732,15 +799,23 @@
                    void *other, 
                    size_t i)
 {
+  ssize_t ret;
+
   if ( (-1 == connection->socket_fd) ||
        (MHD_CONNECTION_CLOSED == connection->state) )
     {
       errno = ENOTCONN;
       return -1;
     }
-  if (0 != (connection->daemon->options & MHD_USE_SSL))
-    return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
-  return RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
+  ret = RECV (connection->socket_fd, other, i, MSG_NOSIGNAL);
+#if EPOLL_SUPPORT
+  if (ret < i)
+    {
+      /* partial read --- no longer read-ready */
+      connection->epoll_state &= ~MHD_EPOLL_STATE_READ_READY;
+    }
+#endif
+  return ret;
 }
 
 
@@ -757,12 +832,13 @@
                     const void *other,
                    size_t i)
 {
+  ssize_t ret;
 #if LINUX
   int fd;
   off_t offset;
   off_t left;
-  ssize_t ret;
 #endif
+
   if ( (-1 == connection->socket_fd) ||
        (MHD_CONNECTION_CLOSED == connection->state) )
     {
@@ -786,7 +862,16 @@
                                 fd,
                                 &offset,
                                 (size_t) left)))
-       return ret;
+       {
+#if EPOLL_SUPPORT
+         if (ret < left)
+           {
+             /* partial write --- no longer write-ready */
+             connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+           }
+#endif
+         return ret;
+       }
       if ( (EINTR == errno) || (EAGAIN == errno) )
        return 0;
       if ( (EINVAL == errno) || (EBADF == errno) )
@@ -797,7 +882,15 @@
         http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html 
*/
     }
 #endif
-  return SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
+  ret = SEND (connection->socket_fd, other, i, MSG_NOSIGNAL);
+#if EPOLL_SUPPORT
+  if (ret < i)
+    {
+      /* partial write --- no longer write-ready */
+      connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+    }
+#endif
+  return ret;
 }
 
 
@@ -890,13 +983,31 @@
 {
   struct MHD_Connection *connection;
   int res_thread_create;
+  unsigned int i;
 #if OSX
   static int on = 1;
-#endif
+#endif  
 
+  if (NULL != daemon->worker_pool)
+    {
+      /* have a pool, try to find a pool with capacity; we use the
+        socket as the initial offset into the pool for load
+        balancing */
+      for (i=0;i<daemon->worker_pool_size;i++)
+       if (0 < daemon->worker_pool[(i + client_socket) % 
daemon->worker_pool_size].max_connections)
+         return MHD_add_connection (&daemon->worker_pool[(i + client_socket) % 
daemon->worker_pool_size],
+                                    client_socket,
+                                    addr, addrlen);
+      /* all pools are at their connection limit, must refuse */
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
+      return MHD_NO;      
+    }
+
 #ifndef WINDOWS
   if ( (client_socket >= FD_SETSIZE) &&
-       (0 == (daemon->options & MHD_USE_POLL)) )
+       (0 == (daemon->options & (MHD_USE_POLL | MHD_USE_EPOLL_LINUX_ONLY))) )
     {
 #if HAVE_MESSAGES
       MHD_DLOG (daemon,
@@ -905,7 +1016,8 @@
                FD_SETSIZE);
 #endif
       SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
       return MHD_NO;
     }
 #endif
@@ -925,7 +1037,8 @@
                 "Server reached connection limit (closing inbound 
connection)\n");
 #endif
       SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
       return MHD_NO;
     }
 
@@ -940,9 +1053,10 @@
 #endif
 #endif
       SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
       MHD_ip_limit_del (daemon, addr, addrlen);
-      return MHD_YES;
+      return MHD_NO;
     }
 
 #if OSX
@@ -963,13 +1077,29 @@
                STRERROR (errno));
 #endif
       SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
       MHD_ip_limit_del (daemon, addr, addrlen);
       return MHD_NO;
     }
   memset (connection, 0, sizeof (struct MHD_Connection));
+  connection->pool = MHD_pool_create (daemon->pool_size);
+  if (NULL == connection->pool)
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Error allocating memory: %s\n", 
+               STRERROR (errno));
+#endif
+      SHUTDOWN (client_socket, SHUT_RDWR);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
+      MHD_ip_limit_del (daemon, addr, addrlen);
+      free (connection);      
+      return MHD_NO;
+    }
+
   connection->connection_timeout = daemon->connection_timeout;
-  connection->pool = NULL;
   if (NULL == (connection->addr = malloc (addrlen)))
     {
 #if HAVE_MESSAGES
@@ -978,8 +1108,10 @@
                STRERROR (errno));
 #endif
       SHUTDOWN (client_socket, SHUT_RDWR);
-      CLOSE (client_socket);
+      if (0 != CLOSE (client_socket))
+       MHD_PANIC ("close failed\n");
       MHD_ip_limit_del (daemon, addr, addrlen);
+      MHD_pool_destroy (connection->pool);
       free (connection);
       return MHD_NO;
     }
@@ -988,7 +1120,7 @@
   connection->socket_fd = client_socket;
   connection->daemon = daemon;
   connection->last_activity = MHD_monotonic_time();
-
+  
   /* set default connection handlers  */
   MHD_set_http_callbacks_ (connection);
   connection->recv_cls = &recv_param_adapter;
@@ -1050,7 +1182,8 @@
                     daemon->cred_type);
 #endif
           SHUTDOWN (client_socket, SHUT_RDWR);
-          CLOSE (client_socket);
+          if (0 != CLOSE (client_socket))
+           MHD_PANIC ("close failed\n");
           MHD_ip_limit_del (daemon, addr, addrlen);
           free (connection->addr);
           free (connection);
@@ -1065,16 +1198,22 @@
                                          (gnutls_push_func) 
&send_param_adapter);
 
       if (daemon->https_mem_trust)
-         gnutls_certificate_server_set_request(connection->tls_session, 
GNUTLS_CERT_REQUEST);
+         gnutls_certificate_server_set_request (connection->tls_session, 
+                                                GNUTLS_CERT_REQUEST);
     }
 #endif
 
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
     MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+  XDLL_insert (daemon->normal_timeout_head,
+              daemon->normal_timeout_tail,
+              connection);
   DLL_insert (daemon->connections_head,
              daemon->connections_tail,
              connection);
-  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
+  if  ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
     MHD_PANIC ("Failed to release cleanup mutex\n");    
 
   /* attempt to create handler thread */
@@ -1088,27 +1227,58 @@
           MHD_DLOG (daemon, "Failed to create a thread: %s\n",
                     STRERROR (res_thread_create));
 #endif
-          SHUTDOWN (client_socket, SHUT_RDWR);
-          CLOSE (client_socket);
-          MHD_ip_limit_del (daemon, addr, addrlen);
-         if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to acquire cleanup mutex\n");
-           }
-         DLL_remove (daemon->connections_head,
-                     daemon->connections_tail,
-                     connection);
-         if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-           {
-             MHD_PANIC ("Failed to release cleanup mutex\n");
-           }
-          free (connection->addr);
-          free (connection);
-          return MHD_NO;
+         goto cleanup;
         }
     }
-  daemon->max_connections--;
+#if EPOLL_SUPPORT
+  if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
+    {
+      struct epoll_event event;
+
+      event.events = EPOLLIN | EPOLLOUT | EPOLLET;
+      event.data.ptr = connection;       
+      if (0 != epoll_ctl (daemon->epoll_fd,
+                         EPOLL_CTL_ADD,
+                         client_socket,
+                         &event))
+       {
+#if HAVE_MESSAGES
+         if (0 != (daemon->options & MHD_USE_DEBUG))
+           MHD_DLOG (daemon, 
+                     "Call to epoll_ctl failed: %s\n", 
+                     STRERROR (errno));
+#endif
+         goto cleanup;
+       }
+      daemon->listen_socket_in_epoll = MHD_YES;
+
+    }
+#endif
+  daemon->max_connections--;  
   return MHD_YES;  
+#if HTTPS_SUPPORT || EPOLL_SUPPORT
+ cleanup:
+  SHUTDOWN (client_socket, SHUT_RDWR);
+  if (0 != CLOSE (client_socket))
+    MHD_PANIC ("close failed\n");
+  MHD_ip_limit_del (daemon, addr, addrlen);
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )    
+    MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+  DLL_remove (daemon->connections_head,
+             daemon->connections_tail,
+             connection);
+  XDLL_remove (daemon->normal_timeout_head,
+              daemon->normal_timeout_tail,
+              connection);
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )
+    MHD_PANIC ("Failed to release cleanup mutex\n");
+  MHD_pool_destroy (connection->pool); 
+  free (connection->addr);
+  free (connection);
+  return MHD_NO;
+#endif
 }
 
 
@@ -1118,7 +1288,11 @@
  * accept policy callback.
  * 
  * @param daemon handle with the listen socket
- * @return MHD_YES on success
+ * @return MHD_YES on success (connections denied by policy or due
+ *         to 'out of memory' and similar errors) are still considered
+ *         successful as far as MHD_accept_connection is concerned);
+ *         a return code of MHD_NO only refers to the actual
+ *         'accept' system call.
  */
 static int
 MHD_accept_connection (struct MHD_Daemon *daemon)
@@ -1143,14 +1317,9 @@
   s = accept4 (fd, addr, &addrlen, SOCK_CLOEXEC);
   need_fcntl = MHD_NO;
 #else
-  s = -1;
+  s = ACCEPT (fd, addr, &addrlen);
   need_fcntl = MHD_YES;
 #endif
-  if (-1 == s)
-  {
-    s = ACCEPT (fd, addr, &addrlen);
-    need_fcntl = MHD_YES;
-  }
   if ((-1 == s) || (addrlen <= 0))
     {
 #if HAVE_MESSAGES
@@ -1163,11 +1332,13 @@
       if (-1 != s)
         {
           SHUTDOWN (s, SHUT_RDWR);
-          CLOSE (s);
+          if (0 != CLOSE (s))
+           MHD_PANIC ("close failed\n");
           /* just in case */
         }
       return MHD_NO;
     }
+#if !HAVE_ACCEPT4
   if (MHD_YES == need_fcntl)
   {
     /* make socket non-inheritable */
@@ -1198,13 +1369,15 @@
       }
 #endif
   }
+#endif
 #if HAVE_MESSAGES
 #if DEBUG_CONNECT
   MHD_DLOG (daemon, "Accepted connection on socket %d\n", s);
 #endif
 #endif
-  return MHD_add_connection (daemon, s,
+  (void) MHD_add_connection (daemon, s,
                             addr, addrlen);
+  return MHD_YES;
 }
 
 
@@ -1222,10 +1395,9 @@
   void *unused;
   int rc;
 
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire cleanup mutex\n");
-    }
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )
+    MHD_PANIC ("Failed to acquire cleanup mutex\n");    
   while (NULL != (pos = daemon->cleanup_head))
     {
       DLL_remove (daemon->cleanup_head,
@@ -1245,22 +1417,39 @@
        gnutls_deinit (pos->tls_session);
 #endif
       MHD_ip_limit_del (daemon, (struct sockaddr*)pos->addr, pos->addr_len);
+#if EPOLL_SUPPORT
+      if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+          (-1 != daemon->epoll_fd) )
+       {
+         /* epoll documentation suggests that closing a FD
+            automatically removes it from the epoll set; however,
+            this is not true as if we fail to do manually remove it,
+            we are still seeing an event for this fd in epoll,
+            causing grief (use-after-free...) --- at least on my
+            system. */
+         if (0 != epoll_ctl (daemon->epoll_fd,
+                             EPOLL_CTL_DEL,
+                             pos->socket_fd,
+                             NULL))
+           MHD_PANIC ("Failed to remove FD from epoll set\n");
+       }
+#endif
       if (NULL != pos->response)
        {
          MHD_destroy_response (pos->response);
          pos->response = NULL;
        }
-      if (-1 != pos->socket_fd)
-       CLOSE (pos->socket_fd);
+      if ( (-1 != pos->socket_fd) &&
+          (0 != CLOSE (pos->socket_fd)) )
+       MHD_PANIC ("close failed\n");
       if (NULL != pos->addr)
        free (pos->addr);
       free (pos);
       daemon->max_connections++;
     }
-  if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release cleanup mutex\n");
-    }
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && 
+       (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )    
+    MHD_PANIC ("Failed to release cleanup mutex\n");    
 }
 
 
@@ -1292,17 +1481,20 @@
 #endif  
       return MHD_NO;
     }
+
+#if HTTPS_SUPPORT
+  if (0 != daemon->num_tls_read_ready)
+    {
+      /* if there is any TLS connection with data ready for
+        reading, we must not block in the event loop */
+      *timeout = 0;
+      return MHD_YES;
+    }
+#endif
+
   have_timeout = MHD_NO;
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
+  for (pos = daemon->manual_timeout_head; NULL != pos; pos = pos->nextX)
     {
-#if HTTPS_SUPPORT
-      if (MHD_YES == pos->tls_read_ready)
-       {
-         earliest_deadline = 0;
-         have_timeout = MHD_YES;
-         break;
-       }
-#endif
       if (0 != pos->connection_timeout) 
        {
          if ( (! have_timeout) ||
@@ -1316,6 +1508,22 @@
          have_timeout = MHD_YES;
        }
     }
+  /* normal timeouts are sorted, so we only need to look at the 'head' */
+  pos = daemon->normal_timeout_head;
+  if ( (NULL != pos) &&
+       (0 != pos->connection_timeout) )
+    {
+      if ( (! have_timeout) ||
+          (earliest_deadline > pos->last_activity + pos->connection_timeout) )
+       earliest_deadline = pos->last_activity + pos->connection_timeout;
+#if HTTPS_SUPPORT
+      if (  (0 != (daemon->options & MHD_USE_SSL)) &&
+           (0 != gnutls_record_check_pending (pos->tls_session)) )
+       earliest_deadline = 0;
+#endif
+      have_timeout = MHD_YES;
+    }
+
   if (MHD_NO == have_timeout)
     return MHD_NO;
   now = MHD_monotonic_time();
@@ -1356,10 +1564,23 @@
   struct MHD_Connection *pos;
   struct MHD_Connection *next;
 
+#if EPOLL_SUPPORT
+  if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY))
+    {
+      /* we're in epoll mode, the epoll FD stands for
+        the entire event set! */
+      if (daemon->epoll_fd >= FD_SETSIZE)
+       return MHD_NO; /* poll fd too big, fail hard */
+      if (FD_ISSET (daemon->epoll_fd, read_fd_set))
+       return MHD_run (daemon);
+      return MHD_YES;
+    }
+#endif
+
   /* select connection thread handling type */
   if ( (-1 != (ds = daemon->socket_fd)) &&
        (FD_ISSET (ds, read_fd_set)) )
-    MHD_accept_connection (daemon);
+    (void) MHD_accept_connection (daemon);
   /* drain signaling pipe to avoid spinning select */
   if ( (-1 != daemon->wpipe[0]) &&
        (FD_ISSET (daemon->wpipe[0], read_fd_set)) )
@@ -1373,18 +1594,30 @@
         {
          next = pos->next;
           ds = pos->socket_fd;
-          if (ds != -1)
-            {
-              if ( (FD_ISSET (ds, read_fd_set))
+          if (-1 == ds)
+           continue;
+         switch (pos->event_loop_info)
+           {
+           case MHD_EVENT_LOOP_INFO_READ:
+             if ( (FD_ISSET (ds, read_fd_set))
 #if HTTPS_SUPPORT
                   || (MHD_YES == pos->tls_read_ready) 
 #endif
                   )
-                pos->read_handler (pos);
-              if (FD_ISSET (ds, write_fd_set))
-                pos->write_handler (pos);
-             pos->idle_handler (pos);
-            }
+               pos->read_handler (pos);
+             break;
+           case MHD_EVENT_LOOP_INFO_WRITE:
+             if (FD_ISSET (ds, write_fd_set))
+               pos->write_handler (pos);
+             break;
+           case MHD_EVENT_LOOP_INFO_BLOCK:
+             /* only idle handler */
+             break;
+           case MHD_EVENT_LOOP_INFO_CLEANUP:
+             /* should never happen */
+             break;
+           }
+         pos->idle_handler (pos);      
         }
     }
   return MHD_YES;
@@ -1502,11 +1735,11 @@
   /* count number of connections and thus determine poll set size */
   num_connections = 0;
   for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
-    num_connections++;
-
+    if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) ||
+        (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) )
+      num_connections++;
   {
     struct pollfd p[2 + num_connections];
-    struct MHD_Pollfd mp;
     MHD_UNSIGNED_LONG_LONG ltimeout;
     unsigned int i;
     int timeout;
@@ -1544,13 +1777,22 @@
     i = 0;
     for (pos = daemon->connections_head; NULL != pos; pos = pos->next)
       {
-       memset(&mp, 0, sizeof (struct MHD_Pollfd));
-       MHD_connection_get_pollfd (pos, &mp);
-       p[poll_server+i].fd = mp.fd;
-       if (mp.events & MHD_POLL_ACTION_IN) 
-         p[poll_server+i].events |= POLLIN;        
-       if (mp.events & MHD_POLL_ACTION_OUT) 
-         p[poll_server+i].events |= POLLOUT;
+       p[poll_server+i].fd = pos->socket_fd;
+       switch (pos->event_loop_info)
+         {
+         case MHD_EVENT_LOOP_INFO_READ:
+           p[poll_server+i].events |= POLLIN;        
+           break;
+         case MHD_EVENT_LOOP_INFO_WRITE:
+           p[poll_server+i].events |= POLLOUT;
+           break;
+         case MHD_EVENT_LOOP_INFO_BLOCK:
+           /* not in poll */
+           break;
+         case MHD_EVENT_LOOP_INFO_CLEANUP:
+           /* should never happen */
+           break;
+         }
        i++;
       }
     if (0 == poll_server + num_connections)
@@ -1574,24 +1816,44 @@
     while (NULL != (pos = next))
       {
        next = pos->next;
-       /* first, sanity checks */
-       if (i >= num_connections)
-         break; /* connection list changed somehow, retry later ... */
-       MHD_connection_get_pollfd (pos, &mp);
-       if (p[poll_server+i].fd != mp.fd)
-         break; /* fd mismatch, something else happened, retry later ... */
-
-       /* normal handling */
-       if (0 != (p[poll_server+i].revents & POLLIN)) 
-         pos->read_handler (pos);
-       if (0 != (p[poll_server+i].revents & POLLOUT)) 
-         pos->write_handler (pos);     
-       pos->idle_handler (pos);
-       i++;
+       switch (pos->event_loop_info)
+         {
+         case MHD_EVENT_LOOP_INFO_READ:
+           /* first, sanity checks */
+           if (i >= num_connections)
+             break; /* connection list changed somehow, retry later ... */     
+           if (p[poll_server+i].fd != pos->socket_fd)
+             break; /* fd mismatch, something else happened, retry later ... */
+           /* normal handling */
+           if (0 != (p[poll_server+i].revents & POLLIN)) 
+             pos->read_handler (pos);
+           pos->idle_handler (pos);
+           i++;
+           break;
+         case MHD_EVENT_LOOP_INFO_WRITE:
+           /* first, sanity checks */
+           if (i >= num_connections)
+             break; /* connection list changed somehow, retry later ... */     
+           if (p[poll_server+i].fd != pos->socket_fd)
+             break; /* fd mismatch, something else happened, retry later ... */
+           /* normal handling */
+           if (0 != (p[poll_server+i].revents & POLLOUT)) 
+             pos->write_handler (pos);
+           pos->idle_handler (pos);
+           i++;
+           break;
+         case MHD_EVENT_LOOP_INFO_BLOCK:
+           pos->idle_handler (pos);
+           break;
+         case MHD_EVENT_LOOP_INFO_CLEANUP:
+           /* should never happen */
+           break;
+         }
       }
+    /* handle 'listen' FD */
     if ( (-1 != poll_listen) &&
         (0 != (p[poll_listen].revents & POLLIN)) )
-      MHD_accept_connection (daemon);
+      (void) MHD_accept_connection (daemon);
   }
   return MHD_YES;
 }
@@ -1651,7 +1913,7 @@
     return MHD_NO;  
   if ( (-1 != poll_listen) &&
        (0 != (p[poll_listen].revents & POLLIN)) )
-    MHD_accept_connection (daemon);  
+    (void) MHD_accept_connection (daemon);  
   return MHD_YES;
 }
 #endif
@@ -1681,7 +1943,205 @@
 }
 
 
+#if EPOLL_SUPPORT
+
 /**
+ * How many events to we process at most per epoll call?  Trade-off
+ * between required stack-size and number of system calls we have to
+ * make; 128 should be way enough to avoid more than one system call
+ * for most scenarios, and still be moderate in stack size
+ * consumption.  Embedded systems might want to choose a smaller value
+ * --- but why use 'epoll' on such a system in the first place?
+ */
+#define MAX_EVENTS 128
+
+
+/**
+ * Do 'epoll'-based processing (this function is allowed to
+ * block).
+ *
+ * @param daemon daemon to run poll loop for
+ * @param may_block YES if blocking, NO if non-blocking
+ * @return MHD_NO on serious errors, MHD_YES on success
+ */
+static int
+MHD_epoll (struct MHD_Daemon *daemon,
+          int may_block)
+{
+  struct MHD_Connection *pos;
+  struct MHD_Connection *next;
+  struct epoll_event events[MAX_EVENTS];
+  struct epoll_event event;
+  int timeout_ms;
+  MHD_UNSIGNED_LONG_LONG timeout_ll;
+  int num_events;
+  unsigned int i;
+
+  if (-1 == daemon->epoll_fd)
+    return MHD_NO; /* we're down! */
+  if (MHD_YES == daemon->shutdown)
+    return MHD_NO;
+  if ( (-1 != daemon->socket_fd) &&
+       (0 != daemon->max_connections) &&
+       (MHD_NO == daemon->listen_socket_in_epoll) )
+    {
+      event.events = EPOLLIN;
+      event.data.ptr = daemon;   
+      if (0 != epoll_ctl (daemon->epoll_fd,
+                         EPOLL_CTL_ADD,
+                         daemon->socket_fd,
+                         &event))
+       {
+#if HAVE_MESSAGES
+         if (0 != (daemon->options & MHD_USE_DEBUG))
+           MHD_DLOG (daemon, 
+                     "Call to epoll_ctl failed: %s\n", 
+                     STRERROR (errno));
+#endif
+         return MHD_NO;
+       }
+      daemon->listen_socket_in_epoll = MHD_YES;
+    }
+  if ( (MHD_YES == daemon->listen_socket_in_epoll) &&
+       (0 == daemon->max_connections) )
+    {
+      /* we're at the connection limit, disable listen socket
+        for event loop for now */
+      if (0 != epoll_ctl (daemon->epoll_fd,
+                         EPOLL_CTL_DEL,
+                         daemon->socket_fd,
+                         NULL))
+       MHD_PANIC ("Failed to remove listen FD from epoll set\n");
+      daemon->listen_socket_in_epoll = MHD_NO;
+    }
+  if (MHD_YES == may_block)
+    {
+      if (MHD_YES == MHD_get_timeout (daemon,
+                                     &timeout_ll))
+       {
+         if (timeout_ll >= (MHD_UNSIGNED_LONG_LONG) INT_MAX)
+           timeout_ms = INT_MAX;
+         else
+           timeout_ms = (int) timeout_ll;
+       }
+      else
+       timeout_ms = -1;
+    }
+  else
+    timeout_ms = 0;
+
+  /* drain 'epoll' event queue; need to iterate as we get at most
+     MAX_EVENTS in one system call here; in practice this should
+     pretty much mean only one round, but better an extra loop here
+     than unfair behavior... */
+  num_events = MAX_EVENTS;
+  while (MAX_EVENTS == num_events)
+    {
+      /* update event masks */
+      num_events = epoll_wait (daemon->epoll_fd,
+                              events, MAX_EVENTS, timeout_ms);
+      if (-1 == num_events)
+       {
+         if (EINTR == errno)
+           return MHD_YES;
+#if HAVE_MESSAGES
+         if (0 != (daemon->options & MHD_USE_DEBUG))
+           MHD_DLOG (daemon, 
+                     "Call to epoll_wait failed: %s\n", 
+                     STRERROR (errno));
+#endif
+         return MHD_NO;
+       }
+      for (i=0;i<num_events;i++)
+       {
+         if (NULL == events[i].data.ptr)
+           continue; /* shutdown signal! */
+         if (daemon != events[i].data.ptr)
+           {
+             /* this is an event relating to a 'normal' connection,
+                remember the event and if appropriate mark the
+                connection as 'eready'. */
+             pos = events[i].data.ptr;
+             if (0 != (events[i].events & EPOLLIN))
+               {
+                 pos->epoll_state |= MHD_EPOLL_STATE_READ_READY;
+                 if ( (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info) &&
+                      (0 == (pos->epoll_state & 
MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
+                   {
+                     EDLL_insert (daemon->eready_head, 
+                                  daemon->eready_tail,
+                                  pos);
+                     pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
+                   }
+               }
+             if (0 != (events[i].events & EPOLLOUT))
+               {
+                 pos->epoll_state |= MHD_EPOLL_STATE_WRITE_READY;
+                 if ( (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info) &&
+                      (0 == (pos->epoll_state & 
MHD_EPOLL_STATE_IN_EREADY_EDLL) ) )
+                   {
+                     EDLL_insert (daemon->eready_head, 
+                                  daemon->eready_tail,
+                                  pos);
+                     pos->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
+                   }
+               }
+           }
+         else /* must be listen socket */
+           {
+             /* run 'accept' until it fails or we are not allowed to take
+                on more connections */
+             while ( (MHD_YES == MHD_accept_connection (daemon)) &&
+                     (0 != daemon->max_connections) ) ;
+           }
+       }
+    }
+
+  /* process events for connections */
+  while (NULL != (pos = daemon->eready_tail))
+    {
+      EDLL_remove (daemon->eready_head,
+                  daemon->eready_tail,
+                  pos);
+      pos->epoll_state -= MHD_EPOLL_STATE_IN_EREADY_EDLL;
+      if (MHD_EVENT_LOOP_INFO_READ == pos->event_loop_info)
+       pos->read_handler (pos);
+      if (MHD_EVENT_LOOP_INFO_WRITE == pos->event_loop_info)
+       pos->write_handler (pos);
+      pos->idle_handler (pos);
+    }
+  /* Finally, handle timed-out connections; we need to do this here
+     as the epoll mechanism won't call the 'idle_handler' on everything,
+     as the other event loops do.  As timeouts do not get an explicit
+     event, we need to find those connections that might have timed out
+     here.
+
+     Connections with custom timeouts must all be looked at, as we
+     do not bother to sort that (presumably very short) list. */
+  next = daemon->manual_timeout_head;
+  while (NULL != (pos = next))
+    {
+      next = pos->nextX;
+      pos->idle_handler (pos);
+    }
+  /* Connections with the default timeout are sorted by prepending
+     them to the head of the list whenever we touch the connection;
+     thus it sufficies to iterate from the tail until the first
+     connection is NOT timed out */
+  next = daemon->normal_timeout_tail;
+  while (NULL != (pos = next))
+    {
+      next = pos->prevX;
+      pos->idle_handler (pos);
+      if (MHD_CONNECTION_CLOSED != pos->state)
+       break; /* sorted by timeout, no need to visit the rest! */
+    }
+  return MHD_YES;
+}
+#endif
+
+
+/**
  * Run webserver operations (without blocking unless
  * in client callbacks).  This method should be called
  * by clients in combination with MHD_get_fdset
@@ -1702,10 +2162,14 @@
        (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
        (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
     return MHD_NO;
-  if (0 == (daemon->options & MHD_USE_POLL)) 
+  if (0 != (daemon->options & MHD_USE_POLL)) 
+    MHD_poll (daemon, MHD_NO);    
+#if EPOLL_SUPPORT     
+  else if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) 
+    MHD_epoll (daemon, MHD_NO);
+#endif
+  else    
     MHD_select (daemon, MHD_NO);    
-  else    
-    MHD_poll (daemon, MHD_NO);    
   MHD_cleanup_connections (daemon);
   return MHD_YES;
 }
@@ -1725,10 +2189,14 @@
 
   while (MHD_YES != daemon->shutdown)
     {
-      if (0 == (daemon->options & MHD_USE_POLL)) 
+      if (0 != (daemon->options & MHD_USE_POLL)) 
+       MHD_poll (daemon, MHD_YES); 
+#if EPOLL_SUPPORT     
+      else if (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) 
+       MHD_epoll (daemon, MHD_YES);
+#endif
+      else 
        MHD_select (daemon, MHD_YES);
-      else 
-       MHD_poll (daemon, MHD_YES);      
       MHD_cleanup_connections (daemon);
     }
   return NULL;
@@ -1784,10 +2252,50 @@
   int ret;
 
   ret = daemon->socket_fd;
+  if (-1 == ret)
+    return -1;
+  if ( (-1 == daemon->wpipe[1]) &&
+       (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon, 
+               "Using MHD_quiesce_daemon in this mode requires 
MHD_USE_PIPE_FOR_SHUTDOWN\n");
+#endif
+      return -1;
+    }
+
   if (NULL != daemon->worker_pool)
-    for (i = 0; i < daemon->worker_pool_size; i++)        
-      daemon->worker_pool[i].socket_fd = -1;    
+    for (i = 0; i < daemon->worker_pool_size; i++)
+      {
+       daemon->worker_pool[i].socket_fd = -1;
+#if EPOLL_SUPPORT
+       if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+            (-1 != daemon->worker_pool[i].epoll_fd) &&
+            (MHD_YES == daemon->worker_pool[i].listen_socket_in_epoll) )
+         {
+           if (0 != epoll_ctl (daemon->worker_pool[i].epoll_fd,
+                               EPOLL_CTL_DEL,
+                               ret,
+                               NULL))
+             MHD_PANIC ("Failed to remove listen FD from epoll set\n");
+           daemon->worker_pool[i].listen_socket_in_epoll = MHD_NO;
+         }
+#endif
+      }
   daemon->socket_fd = -1;
+#if EPOLL_SUPPORT
+  if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+       (-1 != daemon->epoll_fd) &&
+       (MHD_YES == daemon->listen_socket_in_epoll) )
+    {
+      if (0 != epoll_ctl (daemon->epoll_fd,
+                         EPOLL_CTL_DEL,
+                         ret,
+                         NULL))
+       MHD_PANIC ("Failed to remove listen FD from epoll set\n");
+      daemon->listen_socket_in_epoll = MHD_NO;
+    }
+#endif
   return ret;
 }
 
@@ -2157,7 +2665,55 @@
 }
 
 
+#if EPOLL_SUPPORT
 /**
+ * Setup epoll FD for the daemon and initialize it to listen
+ * on the listen FD.
+ *
+ * @param daemon daemon to initialize for epoll
+ * @return MHD_YES on success, MHD_NO on failure
+ */
+static int
+setup_epoll_to_listen (struct MHD_Daemon *daemon)
+{
+  struct epoll_event event;
+
+  daemon->epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
+  if (-1 == daemon->epoll_fd)
+    {
+#if HAVE_MESSAGES
+      if (0 != (daemon->options & MHD_USE_DEBUG))
+       MHD_DLOG (daemon, 
+                 "Call to epoll_create1 failed: %s\n", 
+                 STRERROR (errno));
+#endif
+      return MHD_NO;
+    }
+  if (-1 == daemon->socket_fd)
+    return MHD_YES; /* non-listening daemon */
+  event.events = EPOLLIN;
+  event.data.ptr = daemon;       
+  if (0 != epoll_ctl (daemon->epoll_fd,
+                     EPOLL_CTL_ADD,
+                     daemon->socket_fd,
+                     &event))
+    {
+#if HAVE_MESSAGES
+      if (0 != (daemon->options & MHD_USE_DEBUG))
+       MHD_DLOG (daemon, 
+                 "Call to epoll_ctl failed: %s\n", 
+                 STRERROR (errno));
+#endif
+      return MHD_NO;
+    }
+  daemon->listen_socket_in_epoll = MHD_YES;
+  return MHD_YES;
+}
+#endif
+
+
+
+/**
  * Start a webserver on the given port.
  *
  * @param flags combination of MHD_FLAG values
@@ -2209,6 +2765,9 @@
   if (NULL == (daemon = malloc (sizeof (struct MHD_Daemon))))
     return NULL;
   memset (daemon, 0, sizeof (struct MHD_Daemon));
+#if EPOLL_SUPPORT
+  daemon->epoll_fd = -1;
+#endif
   /* try to open listen socket */
 #if HTTPS_SUPPORT
   if (0 != (flags & MHD_USE_SSL))
@@ -2236,10 +2795,12 @@
   daemon->custom_error_log_cls = stderr;
 #endif
 #ifdef HAVE_LISTEN_SHUTDOWN
-  use_pipe = (0 != (daemon->options & MHD_USE_NO_LISTEN_SOCKET));
+  use_pipe = (0 != (daemon->options & (MHD_USE_NO_LISTEN_SOCKET | 
MHD_USE_PIPE_FOR_SHUTDOWN)));
 #else
   use_pipe = 1; /* yes, must use pipe to signal shutdown */
 #endif
+  if (0 == (flags & (MHD_USE_SELECT_INTERNALLY | 
MHD_USE_THREAD_PER_CONNECTION)))
+    use_pipe = 0; /* useless if we are using 'external' select */
   if ( (use_pipe) &&
        (0 != PIPE (daemon->wpipe)) )
     {
@@ -2259,8 +2820,10 @@
       MHD_DLOG (daemon, 
                "file descriptor for control pipe exceeds maximum value\n");
 #endif
-      CLOSE (daemon->wpipe[0]);
-      CLOSE (daemon->wpipe[1]);
+      if (0 != CLOSE (daemon->wpipe[0]))
+       MHD_PANIC ("close failed\n");
+      if (0 != CLOSE (daemon->wpipe[1]))
+       MHD_PANIC ("close failed\n");
       free (daemon);
       return NULL;
     }
@@ -2291,7 +2854,7 @@
 #ifdef DAUTH_SUPPORT
   if (daemon->nonce_nc_size > 0) 
     {
-      if ( ( (size_t) (daemon->nonce_nc_size * sizeof(struct MHD_NonceNc))) / 
+      if ( ( (size_t) (daemon->nonce_nc_size * sizeof (struct MHD_NonceNc))) / 
           sizeof(struct MHD_NonceNc) != daemon->nonce_nc_size)
        {
 #if HAVE_MESSAGES
@@ -2305,7 +2868,7 @@
          free (daemon);
          return NULL;    
        }
-      daemon->nnc = malloc (daemon->nonce_nc_size * sizeof(struct 
MHD_NonceNc));
+      daemon->nnc = malloc (daemon->nonce_nc_size * sizeof (struct 
MHD_NonceNc));
       if (NULL == daemon->nnc)
        {
 #if HAVE_MESSAGES
@@ -2359,6 +2922,32 @@
       goto free_and_fail;
     }
 #endif
+#if EPOLL_SUPPORT
+  if ( (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY)) &&
+       (0 == daemon->worker_pool_size) &&
+       (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
+    {
+      if (0 != (flags & MHD_USE_THREAD_PER_CONNECTION))
+       {
+#if HAVE_MESSAGES
+         MHD_DLOG (daemon,
+                   "Combining MHD_USE_THREAD_PER_CONNECTION and 
MHD_USE_EPOLL_LINUX_ONLY is not supported.\n");
+#endif
+         goto free_and_fail;
+       }
+      if (MHD_YES != setup_epoll_to_listen (daemon))
+       goto free_and_fail;
+    }
+#else
+  if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY))
+    {
+#if HAVE_MESSAGES
+      MHD_DLOG (daemon,
+               "epoll is not supported on this platform by this build.\n");
+#endif
+      goto free_and_fail;
+    }
+#endif
   if ( (-1 == daemon->socket_fd) &&
        (0 == (daemon->options & MHD_USE_NO_LISTEN_SOCKET)) )
     {
@@ -2377,10 +2966,11 @@
 #endif
          goto free_and_fail;
        }
-      if ((SETSOCKOPT (socket_fd,
-                      SOL_SOCKET,
-                      SO_REUSEADDR,
-                      &on, sizeof (on)) < 0) && ((flags & MHD_USE_DEBUG) != 0))
+      if ( (0 > SETSOCKOPT (socket_fd,
+                           SOL_SOCKET,
+                           SO_REUSEADDR,
+                           &on, sizeof (on))) && 
+          (0 != (flags & MHD_USE_DEBUG)) )
        {
 #if HAVE_MESSAGES
          MHD_DLOG (daemon, 
@@ -2423,27 +3013,33 @@
        }
       daemon->socket_fd = socket_fd;
 
-      if (0 != (flags & MHD_USE_IPv6))
+      if ( (0 != (flags & MHD_USE_IPv6)) &&
+          (0 == (flags & MHD_USE_DUAL_STACK)) )
        {
 #ifdef IPPROTO_IPV6
 #ifdef IPV6_V6ONLY
          /* Note: "IPV6_V6ONLY" is declared by Windows Vista ff., see 
"IPPROTO_IPV6 Socket Options" 
             
(http://msdn.microsoft.com/en-us/library/ms738574%28v=VS.85%29.aspx); 
             and may also be missing on older POSIX systems; good luck if you 
have any of those,
-            your IPv6 socket may then also bind against IPv4... */
+            your IPv6 socket may then also bind against IPv4 anyway... */
 #ifndef WINDOWS
          const int on = 1;
-         setsockopt (socket_fd, 
-                     IPPROTO_IPV6, IPV6_V6ONLY, 
-                     &on, sizeof (on));
 #else
          const char on = 1;
-         setsockopt (socket_fd, 
-                     IPPROTO_IPV6, IPV6_V6ONLY, 
-                     &on, sizeof (on));
 #endif
+         if ( (0 > SETSOCKOPT (socket_fd, 
+                               IPPROTO_IPV6, IPV6_V6ONLY, 
+                               &on, sizeof (on))) &&
+              (0 != (flags & MHD_USE_DEBUG)) )
+           {
+#if HAVE_MESSAGES
+             MHD_DLOG (daemon, 
+                       "setsockopt failed: %s\n", 
+                       STRERROR (errno));
 #endif
+           }
 #endif
+#endif
        }
       if (-1 == BIND (socket_fd, servaddr, addrlen))
        {
@@ -2454,19 +3050,35 @@
                      (unsigned int) port, 
                      STRERROR (errno));
 #endif
-         CLOSE (socket_fd);
+         if (0 != CLOSE (socket_fd))
+           MHD_PANIC ("close failed\n");
          goto free_and_fail;
        }
-      
-      if (LISTEN (socket_fd, 20) < 0)
+#if EPOLL_SUPPORT
+      if (0 != (flags & MHD_USE_EPOLL_LINUX_ONLY))
        {
+         int sk_flags = fcntl (socket_fd, F_GETFL);
+         if (0 != fcntl (socket_fd, F_SETFL, sk_flags | O_NONBLOCK))
+           {
+             MHD_DLOG (daemon,
+                       "Failed to make listen socket non-blocking: %s\n", 
+                       STRERROR (errno));
+             if (0 != CLOSE (socket_fd))
+               MHD_PANIC ("close failed\n");         
+             goto free_and_fail;             
+           }
+       }
+#endif
+      if (LISTEN (socket_fd, 32) < 0)
+       {
 #if HAVE_MESSAGES
          if (0 != (flags & MHD_USE_DEBUG))
            MHD_DLOG (daemon,
                      "Failed to listen for connections: %s\n", 
                      STRERROR (errno));
 #endif
-         CLOSE (socket_fd);
+         if (0 != CLOSE (socket_fd))     
+           MHD_PANIC ("close failed\n");
          goto free_and_fail;
        }      
     }
@@ -2476,7 +3088,7 @@
     }
 #ifndef WINDOWS
   if ( (socket_fd >= FD_SETSIZE) &&
-       (0 == (flags & MHD_USE_POLL)) )
+       (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL_LINUX_ONLY)) ) )
     {
 #if HAVE_MESSAGES
       if ((flags & MHD_USE_DEBUG) != 0)
@@ -2485,7 +3097,8 @@
                  socket_fd,
                  FD_SETSIZE);
 #endif
-      CLOSE (socket_fd);
+      if (0 != CLOSE (socket_fd))
+       MHD_PANIC ("close failed\n");
       goto free_and_fail;
     }
 #endif
@@ -2496,8 +3109,9 @@
       MHD_DLOG (daemon,
                "MHD failed to initialize IP connection limit mutex\n");
 #endif
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
+      if ( (-1 != socket_fd) &&
+          (0 != CLOSE (socket_fd)) )
+       MHD_PANIC ("close failed\n");
       goto free_and_fail;
     }
   if (0 != pthread_mutex_init (&daemon->cleanup_connection_mutex, NULL))
@@ -2507,8 +3121,9 @@
                "MHD failed to initialize IP connection limit mutex\n");
 #endif
       pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
+      if ( (-1 != socket_fd) &&
+          (0 != CLOSE (socket_fd)) )
+       MHD_PANIC ("close failed\n");
       goto free_and_fail;
     }
 
@@ -2520,8 +3135,9 @@
       MHD_DLOG (daemon, 
                "Failed to initialize TLS support\n");
 #endif
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
+      if ( (-1 != socket_fd) &&
+          (0 != CLOSE (socket_fd)) )
+       MHD_PANIC ("close failed\n");
       pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
       pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
       goto free_and_fail;
@@ -2541,8 +3157,9 @@
 #endif
       pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
       pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
+      if ( (-1 != socket_fd) &&
+          (0 != CLOSE (socket_fd)) )
+       MHD_PANIC ("close failed\n");
       goto free_and_fail;
     }
   if ( (daemon->worker_pool_size > 0) &&
@@ -2596,8 +3213,8 @@
         {
           /* Create copy of the Daemon object for each worker */
           struct MHD_Daemon *d = &daemon->worker_pool[i];
+
           memcpy (d, daemon, sizeof (struct MHD_Daemon));
-
           /* Adjust pooling params for worker daemons; note that memcpy()
              has already copied MHD_USE_SELECT_INTERNALLY thread model into
              the worker threads. */
@@ -2611,7 +3228,11 @@
           d->max_connections = conns_per_thread;
           if (i < leftover_conns)
             ++d->max_connections;
-
+#if EPOLL_SUPPORT
+         if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+              (MHD_YES != setup_epoll_to_listen (d)) )
+           goto thread_failed;
+#endif
           /* Must init cleanup connection mutex for each worker */
           if (0 != pthread_mutex_init (&d->cleanup_connection_mutex, NULL))
             {
@@ -2623,7 +3244,8 @@
             }
 
           /* Spawn the worker thread */
-          if (0 != (res_thread_create = create_thread (&d->pid, daemon, 
&MHD_select_thread, d)))
+          if (0 != (res_thread_create = 
+                   create_thread (&d->pid, daemon, &MHD_select_thread, d)))
             {
 #if HAVE_MESSAGES
               MHD_DLOG (daemon,
@@ -2646,8 +3268,9 @@
      MHD_USE_SELECT_INTERNALLY mode. */
   if (0 == i)
     {
-      if (-1 != socket_fd)
-       CLOSE (socket_fd);
+      if ( (-1 != socket_fd) &&
+          (0 != CLOSE (socket_fd)) )
+       MHD_PANIC ("close failed\n");
       pthread_mutex_destroy (&daemon->cleanup_connection_mutex);
       pthread_mutex_destroy (&daemon->per_ip_connection_mutex);
       if (NULL != daemon->worker_pool)
@@ -2666,6 +3289,8 @@
  free_and_fail:
   /* clean up basic memory state in 'daemon' and return NULL to 
      indicate failure */
+  if (-1 != daemon->epoll_fd)
+    close (daemon->epoll_fd);
 #ifdef DAUTH_SUPPORT
   free (daemon->nnc);
   pthread_mutex_destroy (&daemon->nnc_lock);
@@ -2680,6 +3305,37 @@
 
 
 /**
+ * Close the given connection, remove it from all of its
+ * DLLs and move it into the cleanup queue.
+ *
+ * @param pos connection to move to cleanup
+ */
+static void
+close_connection (struct MHD_Connection *pos)
+{
+  struct MHD_Daemon *daemon = pos->daemon;
+
+  MHD_connection_close (pos,
+                       MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
+  if (pos->connection_timeout == pos->daemon->connection_timeout)
+    XDLL_remove (daemon->normal_timeout_head,
+                daemon->normal_timeout_tail,
+                pos);
+  else
+    XDLL_remove (daemon->manual_timeout_head,
+                daemon->manual_timeout_tail,
+                pos);
+  DLL_remove (daemon->connections_head,
+             daemon->connections_tail,
+             pos);
+  pos->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
+  DLL_insert (daemon->cleanup_head,
+             daemon->cleanup_tail,
+             pos);
+}
+
+
+/**
  * Close all connections for the daemon; must only be called after
  * all of the threads have been joined and there is no more concurrent
  * activity on the connection lists.
@@ -2695,45 +3351,59 @@
   
   /* first, make sure all threads are aware of shutdown; need to
      traverse DLLs in peace... */
-  if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to acquire cleanup mutex\n");
-    }
-  for (pos = daemon->connections_head; NULL != pos; pos = pos->next)    
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_lock (&daemon->cleanup_connection_mutex)) )    
+    MHD_PANIC ("Failed to acquire cleanup mutex\n");    
+  for (pos = daemon->connections_head; NULL != pos; pos = pos->nextX)    
     SHUTDOWN (pos->socket_fd, 
              (pos->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);    
-  if (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex))
-    {
-      MHD_PANIC ("Failed to release cleanup mutex\n");
-    }
+  if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
+       (0 != pthread_mutex_unlock (&daemon->cleanup_connection_mutex)) )    
+    MHD_PANIC ("Failed to release cleanup mutex\n");    
 
-  /* now, collect threads */
+  /* now, collect threads from thread pool */
   if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION))
     {
       while (NULL != (pos = daemon->connections_head))
        {
-         if (0 != (rc = pthread_join (pos->pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
+         if (0 != (rc = pthread_join (pos->pid, &unused)))         
+           MHD_PANIC ("Failed to join a thread\n");        
          pos->thread_joined = MHD_YES;
        }
     }
 
   /* now that we're alone, move everyone to cleanup */
   while (NULL != (pos = daemon->connections_head))
+    close_connection (pos);
+  MHD_cleanup_connections (daemon);
+}
+
+
+#if EPOLL_SUPPORT
+/**
+ * Shutdown 'epoll' event loop by adding 'wpipe' to its event set.
+ *
+ * @param daemon daemon of which the epoll instance must be signalled
+ */
+static void
+epoll_shutdown (struct MHD_Daemon *daemon)
+{
+  struct epoll_event event;
+  
+  if (-1 == daemon->wpipe[1]) 
     {
-      MHD_connection_close (pos,
-                           MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
-      DLL_remove (daemon->connections_head,
-                 daemon->connections_tail,
-                 pos);
-      DLL_insert (daemon->cleanup_head,
-                 daemon->cleanup_tail,
-                 pos);
+      /* wpipe was required in this mode, how could this happen? */
+      MHD_PANIC ("Internal error\n");
     }
-  MHD_cleanup_connections (daemon);
+  event.events = EPOLLOUT;
+  event.data.ptr = NULL;         
+  if (0 != epoll_ctl (daemon->epoll_fd,
+                     EPOLL_CTL_ADD,
+                     daemon->wpipe[1],
+                     &event))
+    MHD_PANIC ("Failed to add wpipe to epoll set to signal termination\n");    
 }
+#endif
 
 
 /**
@@ -2762,6 +3432,12 @@
        {
          daemon->worker_pool[i].shutdown = MHD_YES;
          daemon->worker_pool[i].socket_fd = -1;
+#if EPOLL_SUPPORT
+         if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+              (-1 != daemon->worker_pool[i].epoll_fd) &&
+              (-1 == fd) )
+           epoll_shutdown (&daemon->worker_pool[i]);
+#endif
        }
     }
   if (-1 != daemon->wpipe[1])
@@ -2777,6 +3453,13 @@
        (void) SHUTDOWN (fd, SHUT_RDWR);
     }
 #endif
+#if EPOLL_SUPPORT
+  if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+       (-1 != daemon->epoll_fd) &&
+       (-1 == fd) )
+    epoll_shutdown (daemon);    
+#endif
+
 #if DEBUG_CLOSE
 #if HAVE_MESSAGES
   MHD_DLOG (daemon, "MHD listen socket shutdown\n");
@@ -2790,12 +3473,13 @@
       /* MHD_USE_NO_LISTEN_SOCKET disables thread pools, hence we need to 
check */
       for (i = 0; i < daemon->worker_pool_size; ++i)
        {
-         if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))
-           {
-             MHD_PANIC ("Failed to join a thread\n");
-           }
-         close_all_connections (&daemon->worker_pool[i]);
+         if (0 != (rc = pthread_join (daemon->worker_pool[i].pid, &unused)))   
   
+             MHD_PANIC ("Failed to join a thread\n");      
+         close_all_connections (&daemon->worker_pool[i]);        
          pthread_mutex_destroy 
(&daemon->worker_pool[i].cleanup_connection_mutex);
+         if ( (-1 != daemon->worker_pool[i].epoll_fd) &&
+              (0 != CLOSE (daemon->worker_pool[i].epoll_fd)) )
+           MHD_PANIC ("close failed\n");
        }
       free (daemon->worker_pool);
     }
@@ -2813,8 +3497,9 @@
        }
     }
   close_all_connections (daemon);
-  if (-1 != fd)
-    (void) CLOSE (fd);
+  if ( (-1 != fd) &&
+       (0 != CLOSE (fd)) )
+    MHD_PANIC ("close failed\n");
 
   /* TLS clean up */
 #if HTTPS_SUPPORT
@@ -2825,6 +3510,12 @@
         gnutls_certificate_free_credentials (daemon->x509_cred);
     }
 #endif
+#if EPOLL_SUPPORT
+  if ( (0 != (daemon->options & MHD_USE_EPOLL_LINUX_ONLY)) &&
+       (-1 != daemon->epoll_fd) &&
+       (0 != CLOSE (daemon->epoll_fd)) )    
+    MHD_PANIC ("close failed\n");
+#endif
 
 #ifdef DAUTH_SUPPORT
   free (daemon->nnc);
@@ -2835,8 +3526,10 @@
 
   if (-1 != daemon->wpipe[1])
     {
-      (void) CLOSE (daemon->wpipe[0]);
-      (void) CLOSE (daemon->wpipe[1]);
+      if (0 != CLOSE (daemon->wpipe[0]))
+       MHD_PANIC ("close failed\n");
+      if (0 != CLOSE (daemon->wpipe[1]))
+       MHD_PANIC ("close failed\n");
     }
   free (daemon);
 }
@@ -2858,8 +3551,16 @@
 {
   switch (infoType)
     {
+    case MHD_DAEMON_INFO_KEY_SIZE:
+      return NULL; /* no longer supported */
+    case MHD_DAEMON_INFO_MAC_KEY_SIZE:
+      return NULL; /* no longer supported */
     case MHD_DAEMON_INFO_LISTEN_FD:
       return (const union MHD_DaemonInfo *) &daemon->socket_fd;
+#if EPOLL_SUPPORT
+    case MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY:
+      return (const union MHD_DaemonInfo *) &daemon->epoll_fd;
+#endif
     default:
       return NULL;
     };

Modified: libmicrohttpd/src/microhttpd/internal.h
===================================================================
--- libmicrohttpd/src/microhttpd/internal.h     2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/microhttpd/internal.h     2013-07-04 15:29:56 UTC (rev 
27749)
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  (C) 2007, 2008, 2009, 2010, 2011, 2012 Daniel Pittman and Christian Grothoff
+  (C) 2007-2013 Daniel Pittman and Christian Grothoff
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -32,7 +32,11 @@
 #if HTTPS_SUPPORT
 #include <gnutls/gnutls.h>
 #endif
+#if EPOLL_SUPPORT
+#include <sys/epoll.h>
+#endif
 
+
 /**
  * Should we perform additional sanity checks at runtime (on our internal
  * invariants)?  This may lead to aborts, but can be useful for debugging.
@@ -69,63 +73,67 @@
 #define MHD_PANIC(msg) mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL)
 #endif
 
+
 /**
- * Events we care about with respect to poll/select
- * for file descriptors.
+ * State of the socket with respect to epoll (bitmask).
  */
-enum MHD_PollActions
+enum MHD_EpollState
   {
+
     /**
-     * No event interests us.
+     * The socket is not involved with a defined state in epoll right
+     * now.
      */
-    MHD_POLL_ACTION_NOTHING = 0,
+    MHD_EPOLL_STATE_UNREADY = 0,
 
     /**
-     * We would like to read.
+     * epoll told us that data was ready for reading, and we did
+     * not consume all of it yet.
      */
-    MHD_POLL_ACTION_IN = 1,
+    MHD_EPOLL_STATE_READ_READY = 1,
 
     /**
-     * We would like to write.
-     */ 
-    MHD_POLL_ACTION_OUT = 2
+     * epoll told us that space was available for writing, and we did
+     * not consume all of it yet.
+     */
+    MHD_EPOLL_STATE_WRITE_READY = 2,
+
+    /**
+     * Is this connection currently in the 'eready' EDLL?
+     */
+    MHD_EPOLL_STATE_IN_EREADY_EDLL = 4
+
   };
 
 
 /**
- * State of the socket with respect to epoll.
+ * What is this connection waiting for?
  */
-enum MHD_EpollState
+enum MHD_ConnectionEventLoopInfo
   {
+    /**
+     * We are waiting to be able to read.
+     */
+    MHD_EVENT_LOOP_INFO_READ = 0,
 
     /**
-     *
+     * We are waiting to be able to write.
      */
-    MHD_EPOLL_STATE_NOTHING = 0
+    MHD_EVENT_LOOP_INFO_WRITE = 1,
 
+    /**
+     * We are waiting for the application to provide data.
+     */ 
+    MHD_EVENT_LOOP_INFO_BLOCK = 2,
 
-
+    /**
+     * We are finished and are awaiting cleanup.
+     */ 
+    MHD_EVENT_LOOP_INFO_CLEANUP = 3
   };
 
 
 /**
- * Socket descriptor and events we care about.
- */
-struct MHD_Pollfd 
-{
-  /**
-   * Socket descriptor.
-   */
-  int fd;
-
-  /**
-   * Which events do we care about for this socket?
-   */
-  enum MHD_PollActions events;
-};
-
-
-/**
  * Maximum length of a nonce in digest authentication.  32(MD5 Hex) +
  * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera
  * (already) takes more (see Mantis #1633), so we've increased the
@@ -477,17 +485,39 @@
 struct MHD_Connection
 {
 
+#if EPOLL_SUPPORT
   /**
-   * This is a doubly-linked list.
+   * Next pointer for the EDLL listing connections that are epoll-ready.
    */
+  struct MHD_Connection *nextE;
+
+  /**
+   * Previous pointer for the EDLL listing connections that are epoll-ready.
+   */
+  struct MHD_Connection *prevE;
+#endif
+
+  /**
+   * Next pointer for the DLL describing our IO state.
+   */
   struct MHD_Connection *next;
 
   /**
-   * This is a doubly-linked list.
+   * Previous pointer for the DLL describing our IO state.
    */
   struct MHD_Connection *prev;
 
   /**
+   * Next pointer for the XDLL organizing connections by timeout.
+   */
+  struct MHD_Connection *nextX;
+
+  /**
+   * Previous pointer for the XDLL organizing connections by timeout.
+   */
+  struct MHD_Connection *prevX;
+
+  /**
    * Reference to the MHD_Daemon struct.
    */
   struct MHD_Daemon *daemon;
@@ -667,11 +697,10 @@
   int socket_fd;
 
   /**
-   * Has this socket been closed for reading (i.e.
-   * other side closed the connection)?  If so,
-   * we must completely close the connection once
-   * we are done sending our response (and stop
-   * trying to read from this socket).
+   * Has this socket been closed for reading (i.e.  other side closed
+   * the connection)?  If so, we must completely close the connection
+   * once we are done sending our response (and stop trying to read
+   * from this socket).
    */
   int read_closed;
 
@@ -680,12 +709,24 @@
    */
   int thread_joined;
 
+#if EPOLL_SUPPORT
   /**
+   * What is the state of this socket in relation to epoll?
+   */
+  enum MHD_EpollState epoll_state;
+#endif
+
+  /**
    * State in the FSM for this connection.
    */
   enum MHD_CONNECTION_STATE state;
 
   /**
+   * What is this connection waiting for?
+   */
+  enum MHD_ConnectionEventLoopInfo event_loop_info;
+
+  /**
    * HTTP response code.  Only valid if response object
    * is already set.
    */
@@ -797,7 +838,11 @@
 
 
 /**
- * State kept for each MHD daemon.
+ * State kept for each MHD daemon.  All connections are kept in two
+ * doubly-linked lists.  The first one reflects the state of the
+ * connection in terms of what operations we are waiting for (read,
+ * write, locally blocked, cleanup) whereas the second is about its
+ * timeout state (default or custom).
  */
 struct MHD_Daemon
 {
@@ -813,7 +858,7 @@
   void *default_handler_cls;
 
   /**
-   * Tail of doubly-linked list of our current, active connections.
+   * Head of doubly-linked list of our current, active connections.
    */
   struct MHD_Connection *connections_head;
 
@@ -823,7 +868,7 @@
   struct MHD_Connection *connections_tail;
 
   /**
-   * Tail of doubly-linked list of connections to clean up.
+   * Head of doubly-linked list of connections to clean up.
    */
   struct MHD_Connection *cleanup_head;
 
@@ -832,11 +877,55 @@
    */
   struct MHD_Connection *cleanup_tail;
 
+#if EPOLL_SUPPORT
   /**
-   * Function to call to check if we should
-   * accept or reject an incoming request.
-   * May be NULL.
+   * Head of EDLL of connections ready for processing (in epoll mode).
    */
+  struct MHD_Connection *eready_head;
+
+  /**
+   * Tail of EDLL of connections ready for processing (in epoll mode)
+   */
+  struct MHD_Connection *eready_tail;
+#endif
+
+  /**
+   * Head of the XDLL of ALL connections with a default ('normal')
+   * timeout, sorted by timeout (earliest at the tail, most recently
+   * used connection at the head).  MHD can just look at the tail of
+   * this list to determine the timeout for all of its elements;
+   * whenever there is an event of a connection, the connection is
+   * moved back to the tail of the list.
+   *
+   * All connections by default start in this list; if a custom
+   * timeout that does not match 'connection_timeout' is set, they
+   * are moved to the 'manual_timeout_head'-XDLL.
+   */
+  struct MHD_Connection *normal_timeout_head;
+
+  /**
+   * Tail of the XDLL of ALL connections with a default timeout,
+   * sorted by timeout (earliest timeout at the tail).
+   */
+  struct MHD_Connection *normal_timeout_tail;
+
+  /**
+   * Head of the XDLL of ALL connections with a non-default/custom
+   * timeout, unsorted.  MHD will do a O(n) scan over this list to
+   * determine the current timeout.
+   */
+  struct MHD_Connection *manual_timeout_head;
+
+  /**
+   * Tail of the XDLL of ALL connections with a non-default/custom
+   * timeout, unsorted.
+   */
+  struct MHD_Connection *manual_timeout_tail;
+
+  /**
+   * Function to call to check if we should accept or reject an
+   * incoming request.  May be NULL.
+   */
   MHD_AcceptPolicyCallback apc;
 
   /**
@@ -942,7 +1031,20 @@
    */
   int socket_fd;
 
+#if EPOLL_SUPPORT
   /**
+   * File descriptor associated with our epoll loop.
+   */
+  int epoll_fd;
+
+  /**
+   * MHD_YES if the listen socket is in the 'epoll' set, 
+   * MHD_NO if not.
+   */
+  int listen_socket_in_epoll;
+#endif
+
+  /**
    * Pipe we use to signal shutdown, unless
    * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen
    * socket (which we can then 'shutdown' to stop listening).
@@ -1018,6 +1120,14 @@
    */
   const char *https_mem_trust;
 
+  /**
+   * For how many connections do we have 'tls_read_ready' set to MHD_YES?
+   * Used to avoid O(n) traversal over all connections when determining
+   * event-loop timeout (as it needs to be zero if there is any connection
+   * which might have ready data within TLS).
+   */
+  unsigned int num_tls_read_ready;
+
 #endif
 
 #ifdef DAUTH_SUPPORT
@@ -1099,10 +1209,93 @@
   (element)->prev = NULL; } while (0)
 
 
+
 /**
+ * Insert an element at the head of a XDLL. Assumes that head, tail and
+ * element are structs with prevX and nextX fields.
+ *
+ * @param head pointer to the head of the XDLL
+ * @param tail pointer to the tail of the XDLL
+ * @param element element to insert
+ */
+#define XDLL_insert(head,tail,element) do { \
+  (element)->nextX = (head); \
+  (element)->prevX = NULL; \
+  if ((tail) == NULL) \
+    (tail) = element; \
+  else \
+    (head)->prevX = element; \
+  (head) = (element); } while (0)
+
+
+/**
+ * Remove an element from a XDLL. Assumes
+ * that head, tail and element are structs
+ * with prevX and nextX fields.
+ *
+ * @param head pointer to the head of the XDLL
+ * @param tail pointer to the tail of the XDLL
+ * @param element element to remove
+ */
+#define XDLL_remove(head,tail,element) do { \
+  if ((element)->prevX == NULL) \
+    (head) = (element)->nextX;  \
+  else \
+    (element)->prevX->nextX = (element)->nextX; \
+  if ((element)->nextX == NULL) \
+    (tail) = (element)->prevX;  \
+  else \
+    (element)->nextX->prevX = (element)->prevX; \
+  (element)->nextX = NULL; \
+  (element)->prevX = NULL; } while (0)
+
+
+/**
+ * Insert an element at the head of a EDLL. Assumes that head, tail and
+ * element are structs with prevE and nextE fields.
+ *
+ * @param head pointer to the head of the EDLL
+ * @param tail pointer to the tail of the EDLL
+ * @param element element to insert
+ */
+#define EDLL_insert(head,tail,element) do { \
+  (element)->nextE = (head); \
+  (element)->prevE = NULL; \
+  if ((tail) == NULL) \
+    (tail) = element; \
+  else \
+    (head)->prevE = element; \
+  (head) = (element); } while (0)
+
+
+/**
+ * Remove an element from a EDLL. Assumes
+ * that head, tail and element are structs
+ * with prevE and nextE fields.
+ *
+ * @param head pointer to the head of the EDLL
+ * @param tail pointer to the tail of the EDLL
+ * @param element element to remove
+ */
+#define EDLL_remove(head,tail,element) do { \
+  if ((element)->prevE == NULL) \
+    (head) = (element)->nextE;  \
+  else \
+    (element)->prevE->nextE = (element)->nextE; \
+  if ((element)->nextE == NULL) \
+    (tail) = (element)->prevE;  \
+  else \
+    (element)->nextE->prevE = (element)->prevE; \
+  (element)->nextE = NULL; \
+  (element)->prevE = NULL; } while (0)
+
+
+/**
  * Equivalent to time(NULL) but tries to use some sort of monotonic
  * clock that isn't affected by someone setting the system real time
  * clock.
+ *
+ * @return 'current' time
  */
 time_t MHD_monotonic_time(void);
 

Modified: libmicrohttpd/src/microhttpd/memorypool.c
===================================================================
--- libmicrohttpd/src/microhttpd/memorypool.c   2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/microhttpd/memorypool.c   2013-07-04 15:29:56 UTC (rev 
27749)
@@ -90,10 +90,13 @@
 
   pool = malloc (sizeof (struct MemoryPool));
   if (pool == NULL)
-    return NULL;
+    return NULL; 
 #ifdef MAP_ANONYMOUS
-  pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE,
-                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (max <= 32 * 1024)
+    pool->memory = MAP_FAILED;
+  else
+    pool->memory = MMAP (NULL, max, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 #else
   pool->memory = MAP_FAILED;
 #endif

Modified: libmicrohttpd/src/testcurl/Makefile.am
===================================================================
--- libmicrohttpd/src/testcurl/Makefile.am      2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/testcurl/Makefile.am      2013-07-04 15:29:56 UTC (rev 
27749)
@@ -28,8 +28,8 @@
 
 check_PROGRAMS = \
   test_start_stop \
+  test_quiesce \
   test_get \
-  test_quiesce \
   test_get_sendfile \
   test_urlparse \
   test_put \
@@ -52,6 +52,8 @@
   $(CURL_FORK_TEST) \
   perf_get $(PERF_GET_CONCURRENT)
 
+
+
 if HAVE_POSTPROCESSOR
  check_PROGRAMS += \
   test_post \

Modified: libmicrohttpd/src/testcurl/perf_get.c
===================================================================
--- libmicrohttpd/src/testcurl/perf_get.c       2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/testcurl/perf_get.c       2013-07-04 15:29:56 UTC (rev 
27749)
@@ -219,7 +219,8 @@
        }
       curl_easy_cleanup (c);
     }
-  stop (poll_flag ? "internal poll" : "internal select");
+  stop (poll_flag == MHD_USE_POLL ? "internal poll" :
+       poll_flag == MHD_USE_EPOLL_LINUX_ONLY ? "internal epoll" : "internal 
select");
   MHD_stop_daemon (d);
   if (cbc.pos != strlen ("/hello_world"))
     return 4;
@@ -278,7 +279,8 @@
        }
       curl_easy_cleanup (c);
     }
-  stop (poll_flag ? "thread with poll" : "thread with select");
+  stop ((poll_flag & MHD_USE_POLL) ? "thread with poll" :
+       (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread with epoll" : "thread 
with select");
   MHD_stop_daemon (d);
   if (cbc.pos != strlen ("/hello_world"))
     return 64;
@@ -337,7 +339,8 @@
        }
       curl_easy_cleanup (c);
     }
-  stop (poll_flag ? "thread pool with poll" : "thread pool with select");
+  stop (0 != (poll_flag & MHD_USE_POLL) ? "thread pool with poll" : 
+       0 != (poll_flag & MHD_USE_EPOLL_LINUX_ONLY) ? "thread pool with epoll" 
: "thread pool with select");
   MHD_stop_daemon (d);
   if (cbc.pos != strlen ("/hello_world"))
     return 64;
@@ -507,6 +510,10 @@
   errorCount += testMultithreadedGet (port++, MHD_USE_POLL);
   errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL);
 #endif
+#if EPOLL_SUPPORT
+  errorCount += testInternalGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testMultithreadedPoolGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+#endif
   MHD_destroy_response (response);
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);

Modified: libmicrohttpd/src/testcurl/perf_get_concurrent.c
===================================================================
--- libmicrohttpd/src/testcurl/perf_get_concurrent.c    2013-07-04 15:27:59 UTC 
(rev 27748)
+++ libmicrohttpd/src/testcurl/perf_get_concurrent.c    2013-07-04 15:29:56 UTC 
(rev 27749)
@@ -336,6 +336,10 @@
   errorCount += testMultithreadedGet (port++, MHD_USE_POLL);
   errorCount += testMultithreadedPoolGet (port++, MHD_USE_POLL);
 #endif
+#if EPOLL_SUPPORT
+  errorCount += testInternalGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testMultithreadedPoolGet (port++, MHD_USE_EPOLL_LINUX_ONLY);
+#endif
   MHD_destroy_response (response);
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);

Modified: libmicrohttpd/src/testcurl/test_get.c
===================================================================
--- libmicrohttpd/src/testcurl/test_get.c       2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/testcurl/test_get.c       2013-07-04 15:29:56 UTC (rev 
27749)
@@ -145,6 +145,7 @@
   return 0;
 }
 
+
 static int
 testMultithreadedGet (int poll_flag)
 {
@@ -194,6 +195,7 @@
   return 0;
 }
 
+
 static int
 testMultithreadedPoolGet (int poll_flag)
 {
@@ -244,6 +246,7 @@
   return 0;
 }
 
+
 static int
 testExternalGet ()
 {
@@ -366,6 +369,7 @@
   return 0;
 }
 
+
 static int
 testUnknownPortGet (int poll_flag)
 {
@@ -506,6 +510,11 @@
   errorCount += testUnknownPortGet (MHD_USE_POLL);
   errorCount += testStopRace (MHD_USE_POLL);
 #endif
+#if EPOLL_SUPPORT
+  errorCount += testInternalGet (MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testMultithreadedPoolGet (MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testUnknownPortGet (MHD_USE_EPOLL_LINUX_ONLY);
+#endif
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   curl_global_cleanup ();

Modified: libmicrohttpd/src/testcurl/test_quiesce.c
===================================================================
--- libmicrohttpd/src/testcurl/test_quiesce.c   2013-07-04 15:27:59 UTC (rev 
27748)
+++ libmicrohttpd/src/testcurl/test_quiesce.c   2013-07-04 15:29:56 UTC (rev 
27749)
@@ -31,6 +31,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #ifndef WINDOWS
 #include <unistd.h>
@@ -38,8 +40,8 @@
 #endif
 
 static int oneone;
-static int done;
 
+
 struct CBC
 {
   char *buf;
@@ -47,6 +49,7 @@
   size_t size;
 };
 
+
 static size_t
 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
 {
@@ -59,6 +62,7 @@
   return size * nmemb;
 }
 
+
 static int
 ahc_echo (void *cls,
           struct MHD_Connection *connection,
@@ -91,24 +95,28 @@
   return ret;
 }
 
-void request_completed (void *cls, struct MHD_Connection *connection,
-      void **con_cls, enum MHD_RequestTerminationCode code)
+
+static void
+request_completed (void *cls, struct MHD_Connection *connection,
+                  void **con_cls, enum MHD_RequestTerminationCode code)
 {
   int *done = (int *)cls;
   *done = 1;
 }
 
-void ServeOneRequest(int fd)
+
+static void
+ServeOneRequest(int fd)
 {
   struct MHD_Daemon *d;
   fd_set rs;
   fd_set ws;
   fd_set es;
   int max;
-  struct CURLMsg *msg;
   time_t start;
   struct timeval tv;
   int done = 0;
+
   d = MHD_start_daemon (MHD_USE_DEBUG,
                         1082, NULL, NULL, &ahc_echo, "GET",
                         MHD_OPTION_LISTEN_SOCKET, fd,
@@ -140,9 +148,12 @@
   _exit(0);
 }
 
-CURL *setupCURL(void *cbc)
+
+static CURL *
+setupCURL (void *cbc)
 {
   CURL *c;
+
   c = curl_easy_init ();
   curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1:11080/hello_world";);
   curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
@@ -162,6 +173,7 @@
   return c;
 }
 
+
 static int
 testGet (int type, int pool_count, int poll_flag)
 {
@@ -171,18 +183,17 @@
   struct CBC cbc;
   CURLcode errornum;
   int fd;
-  pid_t pid;
 
   cbc.buf = buf;
   cbc.size = 2048;
   cbc.pos = 0;
   if (pool_count > 0) {
-    d = MHD_start_daemon (type | MHD_USE_DEBUG  | poll_flag,
+    d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | 
poll_flag,
                           11080, NULL, NULL, &ahc_echo, "GET",
                           MHD_OPTION_THREAD_POOL_SIZE, pool_count, 
MHD_OPTION_END);
 
   } else {
-    d = MHD_start_daemon (type | MHD_USE_DEBUG  | poll_flag,
+    d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | 
poll_flag,
                           11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
   }
   if (d == NULL)
@@ -211,13 +222,13 @@
     return 8;
   }
 
-  fd = MHD_quiesce_daemon(d);
+  fd = MHD_quiesce_daemon (d);
+  if (fork() == 0) 
+    {
+      ServeOneRequest (fd);
+      _exit(1);
+    }
 
-  if (fork() == 0) {
-    ServeOneRequest(fd);
-    _exit(1);
-  }
-
   cbc.pos = 0;
   if (CURLE_OK != (errornum = curl_easy_perform (c)))
     {
@@ -225,25 +236,28 @@
                "curl_easy_perform failed: `%s'\n",
                curl_easy_strerror (errornum));
       curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
       return 2;
     }
 
   waitpid(-1, NULL, 0);
 
-  if (cbc.pos != strlen ("/hello_world")) {
-    fprintf(stderr, "%s\n", cbc.buf);
-    curl_easy_cleanup (c);
-    MHD_stop_daemon (d);
-    close(fd);
-    return 4;
-  }
-  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) {
-    fprintf(stderr, "%s\n", cbc.buf);
-    curl_easy_cleanup (c);
-    MHD_stop_daemon (d);
-    close(fd);
-    return 8;
-  }
+  if (cbc.pos != strlen ("/hello_world")) 
+    {
+      fprintf(stderr, "%s\n", cbc.buf);
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      close(fd);
+      return 4;
+    }
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 
+    {
+      fprintf(stderr, "%s\n", cbc.buf);
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      close(fd);
+      return 8;
+    }
 
   /* at this point, the forked server quit, and the new
    * server has quiesced, so new requests should fail
@@ -408,6 +422,10 @@
   errorCount += testGet (MHD_USE_THREAD_PER_CONNECTION, 0, MHD_USE_POLL);
   errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 4, MHD_USE_POLL);
 #endif
+#if EPOLL_SUPPORT
+  errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 0, 
MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testGet (MHD_USE_SELECT_INTERNALLY, 4, 
MHD_USE_EPOLL_LINUX_ONLY);
+#endif
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   curl_global_cleanup ();

Modified: libmicrohttpd/src/testcurl/test_start_stop.c
===================================================================
--- libmicrohttpd/src/testcurl/test_start_stop.c        2013-07-04 15:27:59 UTC 
(rev 27748)
+++ libmicrohttpd/src/testcurl/test_start_stop.c        2013-07-04 15:29:56 UTC 
(rev 27749)
@@ -110,6 +110,10 @@
   errorCount += testMultithreadedGet (MHD_USE_POLL);
   errorCount += testMultithreadedPoolGet (MHD_USE_POLL);
 #endif
+#if EPOLL_SUPPORT
+  errorCount += testInternalGet (MHD_USE_EPOLL_LINUX_ONLY);
+  errorCount += testMultithreadedPoolGet (MHD_USE_EPOLL_LINUX_ONLY);
+#endif
   if (errorCount != 0)
     fprintf (stderr, "Error (code: %u)\n", errorCount);
   return errorCount != 0;       /* 0 == pass */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]