httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yla...@apache.org
Subject svn commit: r1635521 - in /httpd/httpd/trunk: docs/log-message-tags/ include/ server/ server/mpm/event/ server/mpm/eventopt/ server/mpm/prefork/ server/mpm/worker/
Date Thu, 30 Oct 2014 15:24:59 GMT
Author: ylavic
Date: Thu Oct 30 15:24:58 2014
New Revision: 1635521

URL: http://svn.apache.org/r1635521
Log:
MPMs, core: make duplicated listeners (SO_REUSEPORT) introduced in r1599531
            less intrusive.

Submitted by: Yingqi Lu <yingqi.lu@intel.com>
Modified/Committed by: ylavic

Add ListenCoresBucketsRatio which is a configurable ratio between the number of
CPU cores (online) and the number of listeners buckets to create, defaulting to
zero (so that listeners buckets become an opt-in, ie. ncpus / ratio > 1).
This could also be made an opt-out by using the previous hardcoded value (8) as
default.

Make ap_close_listeners() act on all the listeners (including duplicated ones),
since the function is also called externally (eg. mod_cgid, mod_ssl_ct and
possibly any third party module) to cleanup opened descriptors when a process
is forked (the duplicated listeners are kept in a scoped/static variable).

Add ap_close_listeners_ex() to close a single bucket of listeners, used by the
children to close unused duplicates and internally by ap_close_listeners().

Make ap_duplicate_listeners() compute the number of buckets to be used, instead
of each MPM. This number is now based on the above ratio and will not change
unless asked to (given *num_buckets < 1, that is when the MPM does not run in
one-process mode nor after a graceful restart).

Remove some global variables (mpm_listen, enable_default_listeners) previously
used to communicate between MPMs and ap_listen, since ap_duplicate_listeners()
API can now be used to do so.
Also rename num_buckets as ap_num_listen_buckets, and prefix have_so_reuseport
with ap_ (both printed by ap_log_common(), hence kept global).
Detect ap_have_so_reuseport once only at startup.

Restore dummy_connection() as before r1599531 since sending POD signals should
not depend on the number of listeners buckets (there is still one single socket
receiving the connections).

For each MPM (concerned), move the bucket data (pod, listeners and eventually
accept mutex) into a struct and instanciate an array of them (sized by the
number of buckets), for each child to use its own data according to its bucket
index, and the parent to maintain the whole.

Modified:
    httpd/httpd/trunk/docs/log-message-tags/next-number
    httpd/httpd/trunk/include/ap_listen.h
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/server/listen.c
    httpd/httpd/trunk/server/log.c
    httpd/httpd/trunk/server/mpm/event/event.c
    httpd/httpd/trunk/server/mpm/eventopt/eventopt.c
    httpd/httpd/trunk/server/mpm/prefork/prefork.c
    httpd/httpd/trunk/server/mpm/worker/worker.c
    httpd/httpd/trunk/server/mpm_unix.c

Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
+++ httpd/httpd/trunk/docs/log-message-tags/next-number Thu Oct 30 15:24:58 2014
@@ -1 +1 @@
-2819
+2821

Modified: httpd/httpd/trunk/include/ap_listen.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_listen.h?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_listen.h (original)
+++ httpd/httpd/trunk/include/ap_listen.h Thu Oct 30 15:24:58 2014
@@ -77,14 +77,8 @@ struct ap_listen_rec {
  * The global list of ap_listen_rec structures
  */
 AP_DECLARE_DATA extern ap_listen_rec *ap_listeners;
-
-AP_DECLARE_DATA extern ap_listen_rec **mpm_listen;
-
-AP_DECLARE_DATA extern int enable_default_listener;
-
-AP_DECLARE_DATA extern int num_buckets;
-
-AP_DECLARE_DATA extern int have_so_reuseport;
+AP_DECLARE_DATA extern int ap_num_listen_buckets;
+AP_DECLARE_DATA extern int ap_have_so_reuseport;
 
 /**
  * Setup all of the defaults for the listener list
@@ -99,13 +93,22 @@ AP_DECLARE(void) ap_listen_pre_config(vo
  */
 AP_DECLARE(int) ap_setup_listeners(server_rec *s);
 
-/**This function duplicates ap_listeners.
- * @param s The global server_rec
+/**
+ * This function duplicates ap_listeners into multiple buckets when configured
+ * to (see ListenCoresBucketsRatio) and the platform supports it (eg. number of
+ * online CPU cores and SO_REUSEPORT available).
  * @param p The config pool
- * @param num_buckets The total number of listener buckets.
-**/
-AP_DECLARE(apr_status_t) ap_duplicate_listeners(server_rec *s, apr_pool_t *p, int num_buckets);
-
+ * @param s The global server_rec
+ * @param buckets The array of listeners buckets.
+ * @param num_buckets The total number of listeners buckets (array size).
+ * @remark If the given *num_buckets is 0 (input), it will be computed
+ *         according to the platform capacities, otherwise (positive) it
+ *         will be preserved. The number of listeners duplicated will
+ *         always match *num_buckets, be it computed or given.
+ */
+AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
+                                                ap_listen_rec ***buckets,
+                                                int *num_buckets);
 
 /**
  * Loop through the global ap_listen_rec list and close each of the sockets.
@@ -113,6 +116,12 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
 AP_DECLARE_NONSTD(void) ap_close_listeners(void);
 
 /**
+ * Loop through the given ap_listen_rec list and close each of the sockets.
+ * @param listener The listener to close.
+ */
+AP_DECLARE_NONSTD(void) ap_close_listeners_ex(ap_listen_rec *listeners);
+
+/**
  * FIXMEDOC
  */
 AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *);
@@ -125,6 +134,7 @@ AP_DECLARE_NONSTD(int) ap_close_selected
  * called.
  */
 AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const char *arg);
+AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg);
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
                                                 int argc, char *const argv[]);
 AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy,
@@ -136,6 +146,8 @@ AP_DECLARE_NONSTD(const char *) ap_set_r
 #define LISTEN_COMMANDS \
 AP_INIT_TAKE1("ListenBacklog", ap_set_listenbacklog, NULL, RSRC_CONF, \
   "Maximum length of the queue of pending connections, as used by listen(2)"), \
+AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, \
+  "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \
 AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \
   "A port number or a numeric IP address and a port number, and an optional protocol"), \
 AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Thu Oct 30 15:24:58 2014
@@ -470,6 +470,9 @@
  * 20140627.6 (2.5.0-dev)  Added ap_pcre_version_string(), AP_REG_PCRE_COMPILED
  *                         and AP_REG_PCRE_LOADED to ap_regex.h.
  * 20140627.7 (2.5.0-dev)  Add listener bucket in scoreboard.h's process_score.
+ * 20140627.8 (2.5.0-dev)  Add ap_set_listencbratio(), ap_close_listeners_ex(),
+ *                         ap_duplicate_listeners(), ap_num_listen_buckets and
+ *                         ap_have_so_reuseport to ap_listen.h.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -477,7 +480,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20140627
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 7                 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 8                 /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/trunk/server/listen.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/listen.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/listen.c (original)
+++ httpd/httpd/trunk/server/listen.c Thu Oct 30 15:24:58 2014
@@ -28,6 +28,11 @@
 #include "http_log.h"
 #include "mpm_common.h"
 
+#include <stdlib.h>
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #ifdef HAVE_SYSTEMD
 #include <systemd/sd-daemon.h>
 #endif
@@ -38,13 +43,23 @@
 
 AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL;
 
-AP_DECLARE_DATA ap_listen_rec **mpm_listen = NULL;
-AP_DECLARE_DATA int enable_default_listener = 1;
-AP_DECLARE_DATA int num_buckets = 1;
-AP_DECLARE_DATA int have_so_reuseport = 0;
+/* Let ap_num_listen_buckets be global so that it can
+ * be printed by ap_log_common(), but keep the listeners
+ * buckets static since it is used only here to close them
+ * all (including duplicated) with ap_close_listeners().
+ */
+AP_DECLARE_DATA int ap_num_listen_buckets;
+static ap_listen_rec **ap_listen_buckets;
+
+/* Determine once, at runtime, whether or not SO_REUSEPORT
+ * is usable on this platform, and hence whether or not
+ * listeners can be duplicated (if configured).
+ */
+AP_DECLARE_DATA int ap_have_so_reuseport = -1;
 
 static ap_listen_rec *old_listeners;
 static int ap_listenbacklog;
+static int ap_listencbratio;
 static int send_buffer_size;
 static int receive_buffer_size;
 #ifdef HAVE_SYSTEMD
@@ -129,26 +144,20 @@ static apr_status_t make_sock(apr_pool_t
     ap_sock_disable_nagle(s);
 #endif
 
-#ifdef SO_REUSEPORT
-    {
-      int thesock;
-      apr_os_sock_get(&thesock, s);
-      if (setsockopt(thesock, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(int)) < 0) {
-          /* defined by not valid? */
-          if (errno == ENOPROTOOPT) {
-              have_so_reuseport = 0;
-          } /* Check if SO_REUSEPORT is supported by the running Linux Kernel.*/
-          else {
-              ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02638)
-                      "make_sock: for address %pI, apr_socket_opt_set: (SO_REUSEPORT)",
-                       server->bind_addr);
-              apr_socket_close(s);
-              return errno;
-          }
-      }
-      else {
-          have_so_reuseport = 1;
-      }
+#if defined(SO_REUSEPORT)
+    if (ap_have_so_reuseport) {
+        int thesock;
+        apr_os_sock_get(&thesock, s);
+        if (setsockopt(thesock, SOL_SOCKET, SO_REUSEPORT,
+                       (void *)&one, sizeof(int)) < 0) {
+            stat = apr_get_netos_error();
+            ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02638)
+                          "make_sock: for address %pI, apr_socket_opt_set: "
+                          "(SO_REUSEPORT)",
+                          server->bind_addr);
+            apr_socket_close(s);
+            return stat;
+        }
     }
 #endif
 
@@ -207,7 +216,7 @@ static apr_status_t make_sock(apr_pool_t
 #endif
 
     server->sd = s;
-    server->active = enable_default_listener;
+    server->active = 1;
 
     server->accept_func = NULL;
 
@@ -596,7 +605,7 @@ static int open_listeners(apr_pool_t *po
                 }
             }
 #endif
-            if (make_sock(pool, lr, enable_default_listener) == APR_SUCCESS) {
+            if (make_sock(pool, lr, 1) == APR_SUCCESS) {
                 ++num_open;
             }
             else {
@@ -637,11 +646,7 @@ static int open_listeners(apr_pool_t *po
     }
 
     /* close the old listeners */
-    for (lr = old_listeners; lr; lr = next) {
-        apr_socket_close(lr->sd);
-        lr->active = 0;
-        next = lr->next;
-    }
+    ap_close_listeners_ex(old_listeners);
     old_listeners = NULL;
 
 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
@@ -712,7 +717,6 @@ AP_DECLARE(int) ap_setup_listeners(serve
         }
     }
 
-
 #ifdef HAVE_SYSTEMD
     if (use_systemd) {
         const char *userdata_key = "ap_open_systemd_listeners";
@@ -758,15 +762,48 @@ AP_DECLARE(int) ap_setup_listeners(serve
     return num_listeners;
 }
 
-AP_DECLARE(apr_status_t) ap_duplicate_listeners(server_rec *s, apr_pool_t *p,
-                                                  int num_buckets) {
+AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
+                                                ap_listen_rec ***buckets,
+                                                int *num_buckets)
+{
+    static int warn_once;
     int i;
     apr_status_t stat;
     int use_nonblock = 0;
     ap_listen_rec *lr;
 
-    mpm_listen = apr_palloc(p, sizeof(ap_listen_rec*) * num_buckets);
-    for (i = 0; i < num_buckets; i++) {
+    if (*num_buckets < 1) {
+        *num_buckets = 1;
+        if (ap_listencbratio > 0) {
+#ifdef _SC_NPROCESSORS_ONLN
+            if (ap_have_so_reuseport) {
+                int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN),
+                    val = num_online_cores / ap_listencbratio;
+                if (val > 1) {
+                    *num_buckets = val;
+                }
+                ap_log_perror(APLOG_MARK, APLOG_INFO, 0, p, APLOGNO(02819)
+                              "Using %i listeners bucket(s) based on %i "
+                              "online CPU cores and a ratio of %i",
+                              *num_buckets, num_online_cores,
+                              ap_listencbratio);
+            }
+            else
+#endif
+            if (!warn_once) {
+                ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, APLOGNO(02820)
+                              "ListenCoresBucketsRatio ignored without "
+                              "SO_REUSEPORT and _SC_NPROCESSORS_ONLN "
+                              "support: using a single listeners bucket");
+                warn_once = 1;
+            }
+        }
+    }
+
+    *buckets = apr_pcalloc(p, *num_buckets * sizeof(ap_listen_rec *));
+    (*buckets)[0] = ap_listeners;
+
+    for (i = 1; i < *num_buckets; i++) {
         ap_listen_rec *last = NULL;
         lr = ap_listeners;
         while (lr) {
@@ -786,7 +823,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
             else
 #endif
             {
-                duplr  = apr_palloc(p, sizeof(ap_listen_rec));
+                duplr = apr_palloc(p, sizeof(ap_listen_rec));
                 duplr->slave = NULL;
                 duplr->protocol = apr_pstrdup(p, lr->protocol);
                 hostname = apr_pstrdup(p, lr->bind_addr->hostname);
@@ -794,10 +831,11 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
                 apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
                 duplr->bind_addr = sa;
                 duplr->next = NULL;
-                if ((stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
-                                            SOCK_STREAM, 0, p)) != APR_SUCCESS) {
+                stat = apr_socket_create(&duplr->sd, duplr->bind_addr->family,
+                                         SOCK_STREAM, 0, p);
+                if (stat != APR_SUCCESS) {
                     ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(02640)
-                                "ap_duplicate_socket: for address %pI, "
+                                "ap_duplicate_listeners: for address %pI, "
                                 "cannot duplicate a new socket!",
                                 duplr->bind_addr);
                     return stat;
@@ -806,8 +844,8 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
             }
 #if AP_NONBLOCK_WHEN_MULTI_LISTEN
             use_nonblock = (ap_listeners && ap_listeners->next);
-            if ((stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock))
-                != APR_SUCCESS) {
+            stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock);
+            if (stat != APR_SUCCESS) {
                 ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02641)
                               "unable to control socket non-blocking status");
                 return stat;
@@ -816,7 +854,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
             ap_apply_accept_filter(p, duplr, s);
 
             if (last == NULL) {
-                mpm_listen[i] = last = duplr;
+                (*buckets)[i] = last = duplr;
             }
             else {
                 last->next = duplr;
@@ -825,18 +863,33 @@ AP_DECLARE(apr_status_t) ap_duplicate_li
             lr = lr->next;
         }
     }
+
+    ap_listen_buckets = *buckets;
+    ap_num_listen_buckets = *num_buckets;
     return APR_SUCCESS;
 }
 
 AP_DECLARE_NONSTD(void) ap_close_listeners(void)
 {
-    ap_listen_rec *lr;
     int i;
-    for (i = 0; i < num_buckets; i++) {
-        for (lr = mpm_listen[i]; lr; lr = lr->next) {
-            apr_socket_close(lr->sd);
-            lr->active = 0;
-        }
+
+    ap_close_listeners_ex(ap_listeners);
+
+    /* Start from index 1 since either ap_duplicate_listeners()
+     * was called and ap_listen_buckets[0] == ap_listeners, or
+     * it wasn't and ap_num_listen_buckets == 0.
+     */
+    for (i = 1; i < ap_num_listen_buckets; i++) {
+        ap_close_listeners_ex(ap_listen_buckets[i]);
+    }
+}
+
+AP_DECLARE_NONSTD(void) ap_close_listeners_ex(ap_listen_rec *listeners)
+{
+    ap_listen_rec *lr;
+    for (lr = listeners; lr; lr = lr->next) {
+        apr_socket_close(lr->sd);
+        lr->active = 0;
     }
 }
 
@@ -861,7 +914,43 @@ AP_DECLARE(void) ap_listen_pre_config(vo
 {
     old_listeners = ap_listeners;
     ap_listeners = NULL;
+    ap_listen_buckets = NULL;
+    ap_num_listen_buckets = 0;
     ap_listenbacklog = DEFAULT_LISTENBACKLOG;
+    ap_listencbratio = 0;
+
+    /* Check once whether or not SO_REUSEPORT is supported. */
+    if (ap_have_so_reuseport < 0) {
+        /* This is limited to Linux with defined SO_REUSEPORT (ie. 3.9+) for
+         * now since the implementation evenly distributes connections accross
+         * all the listening threads/processes.
+         *
+         * *BSDs have SO_REUSEPORT too but with a different semantic: the first
+         * wildcard address bound socket or the last non-wildcard address bound
+         * socket will receive connections (no evenness garantee); the rest of
+         * the sockets bound to the same port will not.
+         * This can't (always) work for httpd.
+         *
+         * TODO: latests DragonFlyBSD's SO_REUSEPORT (seems to?) have the same
+         * semantic as Linux, so we may need HAVE_SO_REUSEPORT available from
+         * configure.in some day.
+         */
+#if defined(SO_REUSEPORT) && defined(__linux__)
+        apr_socket_t *sock;
+        if (apr_socket_create(&sock, APR_UNSPEC, SOCK_STREAM, 0,
+                              ap_pglobal) == APR_SUCCESS) {
+            int thesock, on = 1;
+            apr_os_sock_get(&thesock, sock);
+            ap_have_so_reuseport = (setsockopt(thesock, SOL_SOCKET,
+                                               SO_REUSEPORT, (void *)&on,
+                                               sizeof(int)) == 0);
+            apr_socket_close(sock);
+        }
+        else
+#endif
+        ap_have_so_reuseport = 0;
+
+    }
 }
 
 AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
@@ -944,6 +1033,26 @@ AP_DECLARE_NONSTD(const char *) ap_set_l
     return NULL;
 }
 
+AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd,
+                                                     void *dummy,
+                                                     const char *arg)
+{
+    int b;
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+
+    if (err != NULL) {
+        return err;
+    }
+
+    b = atoi(arg);
+    if (b < 1) {
+        return "ListenCoresBucketsRatio must be > 0";
+    }
+
+    ap_listencbratio = b;
+    return NULL;
+}
+
 AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd,
                                                         void *dummy,
                                                         const char *arg)

Modified: httpd/httpd/trunk/server/log.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/log.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/log.c (original)
+++ httpd/httpd/trunk/server/log.c Thu Oct 30 15:24:58 2014
@@ -1493,8 +1493,8 @@ AP_DECLARE(void) ap_log_common(server_re
 {
     ap_log_error(APLOG_MARK, APLOG_DEBUG , 0, s, APLOGNO(02639)
                  "Using SO_REUSEPORT: %s (%d)",
-                 have_so_reuseport ? "yes" : "no",
-                 num_buckets);
+                 ap_have_so_reuseport ? "yes" : "no",
+                 ap_num_listen_buckets);
 }
 
 AP_DECLARE(void) ap_remove_pid(apr_pool_t *p, const char *rel_fname)

Modified: httpd/httpd/trunk/server/mpm/event/event.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/event/event.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/event/event.c (original)
+++ httpd/httpd/trunk/server/mpm/event/event.c Thu Oct 30 15:24:58 2014
@@ -361,11 +361,15 @@ typedef struct event_retained_data {
 } event_retained_data;
 static event_retained_data *retained;
 
-#define ID_FROM_CHILD_THREAD(c, t)    ((c * thread_limit) + t)
+typedef struct event_child_bucket {
+    ap_pod_t *pod;
+    ap_listen_rec *listeners;
+} event_child_bucket;
+static int                 num_buckets; /* Number of listeners buckets */
+static event_child_bucket *all_buckets, /* All listeners buckets */
+                          *my_bucket;   /* Current child bucket */
 
-static ap_pod_t **pod;
-static ap_pod_t *child_pod;
-static ap_listen_rec *child_listen;
+#define ID_FROM_CHILD_THREAD(c, t)    ((c * thread_limit) + t)
 
 /* The event MPM respects a couple of runtime flags that can aid
  * in debugging. Setting the -DNO_DETACH flag will prevent the root process
@@ -1211,11 +1215,12 @@ static void check_infinite_requests(void
     }
 }
 
-static void close_listeners(int process_slot, int *closed) {
+static void close_listeners(int process_slot, int *closed)
+{
     if (!*closed) {
         int i;
         disable_listensocks(process_slot);
-        ap_close_listeners();
+        ap_close_listeners_ex(my_bucket->listeners);
         *closed = 1;
         dying = 1;
         ap_scoreboard_image->parent[process_slot].quiescing = 1;
@@ -1289,7 +1294,7 @@ static apr_status_t init_pollset(apr_poo
     TO_QUEUE_INIT(short_linger_q);
 
     listener_pollfd = apr_palloc(p, sizeof(apr_pollfd_t) * num_listensocks);
-    for (lr = child_listen; lr != NULL; lr = lr->next, i++) {
+    for (lr = my_bucket->listeners; lr != NULL; lr = lr->next, i++) {
         apr_pollfd_t *pfd;
         AP_DEBUG_ASSERT(i < num_listensocks);
         pfd = &listener_pollfd[i];
@@ -2418,7 +2423,6 @@ static void child_main(int child_num_arg
     apr_thread_t *start_thread_id;
     apr_pool_t *pskip;
     int i;
-    ap_listen_rec *lr;
 
     mpm_state = AP_MPMQ_STARTING;       /* for benefit of any hooks that run as this
                                          * child initializes
@@ -2427,19 +2431,11 @@ static void child_main(int child_num_arg
     ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
-    child_listen = mpm_listen[child_bucket];
-    child_pod = pod[child_bucket];
-
     /* close unused listeners and pods */
     for (i = 0; i < num_buckets; i++) {
         if (i != child_bucket) {
-            lr = mpm_listen[i];
-            while(lr) {
-                apr_socket_close(lr->sd);
-                lr->active = 0;
-                lr = lr->next;
-            }
-            ap_mpm_podx_close(pod[i]);
+            ap_close_listeners_ex(all_buckets[i].listeners);
+            ap_mpm_podx_close(all_buckets[i].pod);
         }
     }
 
@@ -2553,7 +2549,7 @@ static void child_main(int child_num_arg
         apr_signal(SIGTERM, dummy_signal_handler);
         /* Watch for any messages from the parent over the POD */
         while (1) {
-            rv = ap_mpm_podx_check(child_pod);
+            rv = ap_mpm_podx_check(my_bucket->pod);
             if (rv == AP_MPM_PODX_NORESTART) {
                 /* see if termination was triggered while we slept */
                 switch (terminate_mode) {
@@ -2600,9 +2596,11 @@ static int make_child(server_rec * s, in
     }
 
     if (one_process) {
+        my_bucket = &all_buckets[0];
+
         set_signals();
         event_note_child_started(slot, getpid());
-        child_main(0, 0);
+        child_main(slot, 0);
         /* NOTREACHED */
         ap_assert(0);
         return -1;
@@ -2628,6 +2626,8 @@ static int make_child(server_rec * s, in
     }
 
     if (!pid) {
+        my_bucket = &all_buckets[bucket];
+
 #ifdef HAVE_BINDPROCESSOR
         /* By default, AIX binds to a single processor.  This bit unbinds
          * children which will then bind to another CPU.
@@ -2806,7 +2806,8 @@ static void perform_idle_server_maintena
 
     if (idle_thread_count > max_spare_threads / num_buckets) {
         /* Kill off one child */
-        ap_mpm_podx_signal(pod[child_bucket], AP_MPM_PODX_GRACEFUL);
+        ap_mpm_podx_signal(all_buckets[child_bucket].pod,
+                           AP_MPM_PODX_GRACEFUL);
         retained->idle_spawn_rate[child_bucket] = 1;
     }
     else if (idle_thread_count < min_spare_threads / num_buckets) {
@@ -3052,7 +3053,8 @@ static int event_run(apr_pool_t * _pconf
          * Kill child processes, tell them to call child_exit, etc...
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, /* Start with SIGTERM */
                                    event_note_child_killed);
@@ -3075,7 +3077,8 @@ static int event_run(apr_pool_t * _pconf
         /* Close our listeners, and then ask our children to do same */
         ap_close_listeners();
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
         ap_relieve_child_processes(event_note_child_killed);
 
@@ -3117,7 +3120,8 @@ static int event_run(apr_pool_t * _pconf
          * really dead.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, event_note_child_killed);
 
@@ -3145,7 +3149,8 @@ static int event_run(apr_pool_t * _pconf
                      " received.  Doing graceful restart");
         /* wake up the children...time to die.  But we'll have more soon */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
 
         /* This is mostly for debugging... so that we know what is still
@@ -3159,7 +3164,8 @@ static int event_run(apr_pool_t * _pconf
          * pthreads are stealing signals from us left and right.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
 
         ap_reclaim_child_processes(1,  /* Start with SIGTERM */
@@ -3179,6 +3185,7 @@ static int event_open_logs(apr_pool_t * 
 {
     int startup = 0;
     int level_flags = 0;
+    ap_listen_rec **listen_buckets;
     apr_status_t rv;
     int i;
 
@@ -3190,7 +3197,6 @@ static int event_open_logs(apr_pool_t * 
         level_flags |= APLOG_STARTUP;
     }
 
-    enable_default_listener = 0;
     if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
         ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
                      (startup ? NULL : s),
@@ -3198,21 +3204,33 @@ static int event_open_logs(apr_pool_t * 
         return DONE;
     }
 
-    enable_default_listener = 1;
-    ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
-
-    pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
-
-    if (!one_process) {
-        for (i = 0; i < num_buckets; i++) {
-            if ((rv = ap_mpm_podx_open(pconf, &pod[i]))) {
-                ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
-                             (startup ? NULL : s),
-                             "could not open pipe-of-death");
-                return DONE;
-            }
+    if (one_process) {
+        num_buckets = 1;
+    }
+    else if (!retained->is_graceful) { /* Preserve the number of buckets
+                                          on graceful restarts. */
+        num_buckets = 0;
+    }
+    if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
+                                     &listen_buckets, &num_buckets))) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                     (startup ? NULL : s),
+                     "could not duplicate listeners");
+        return DONE;
+    }
+    all_buckets = apr_pcalloc(pconf, num_buckets *
+                                     sizeof(event_child_bucket));
+    for (i = 0; i < num_buckets; i++) {
+        if (!one_process && /* no POD in one_process mode */
+                (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                         (startup ? NULL : s),
+                         "could not open pipe-of-death");
+            return DONE;
         }
+        all_buckets[i].listeners = listen_buckets[i];
     }
+
     /* for skiplist */
     srand((unsigned int)apr_time_now());
     return OK;
@@ -3246,17 +3264,6 @@ static int event_pre_config(apr_pool_t *
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
         retained->max_daemons_limit = -1;
     }
-    if (!retained->is_graceful) {
-        num_buckets = 1;
-#ifdef _SC_NPROCESSORS_ONLN
-        if (have_so_reuseport) {
-            int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN);
-            if (num_online_cores > 8) {
-                num_buckets = num_online_cores / 8;
-            }
-        }
-#endif
-    }
     ++retained->module_loads;
     if (retained->module_loads == 2) {
         /* test for correct operation of fdqueue */

Modified: httpd/httpd/trunk/server/mpm/eventopt/eventopt.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/eventopt/eventopt.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/eventopt/eventopt.c (original)
+++ httpd/httpd/trunk/server/mpm/eventopt/eventopt.c Thu Oct 30 15:24:58 2014
@@ -346,11 +346,15 @@ typedef struct event_retained_data {
 } event_retained_data;
 static event_retained_data *retained;
 
-#define ID_FROM_CHILD_THREAD(c, t)    ((c * thread_limit) + t)
+typedef struct event_child_bucket {
+    ap_pod_t *pod;
+    ap_listen_rec *listeners;
+} event_child_bucket;
+static int                 num_buckets; /* Number of listeners buckets */
+static event_child_bucket *all_buckets, /* All listeners buckets */
+                          *my_bucket;   /* Current child bucket */
 
-static ap_pod_t **pod;
-static ap_pod_t *child_pod;
-static ap_listen_rec *child_listen;
+#define ID_FROM_CHILD_THREAD(c, t)    ((c * thread_limit) + t)
 
 /* The eventopt MPM respects a couple of runtime flags that can aid
  * in debugging. Setting the -DNO_DETACH flag will prevent the root process
@@ -1172,11 +1176,12 @@ static void check_infinite_requests(void
     }
 }
 
-static void close_listeners(int process_slot, int *closed) {
+static void close_listeners(int process_slot, int *closed)
+{
     if (!*closed) {
         int i;
         disable_listensocks(process_slot);
-        ap_close_listeners();
+        ap_close_listeners_ex(my_bucket->listeners);
         *closed = 1;
         dying = 1;
         ap_scoreboard_image->parent[process_slot].quiescing = 1;
@@ -1250,7 +1255,7 @@ static apr_status_t init_pollset(apr_poo
     TO_QUEUE_INIT(short_linger_q);
 
     listener_pollfd = apr_palloc(p, sizeof(apr_pollfd_t) * num_listensocks);
-    for (lr = child_listen; lr != NULL; lr = lr->next, i++) {
+    for (lr = my_bucket->listeners; lr != NULL; lr = lr->next, i++) {
         apr_pollfd_t *pfd;
         AP_DEBUG_ASSERT(i < num_listensocks);
         pfd = &listener_pollfd[i];
@@ -2240,7 +2245,6 @@ static void child_main(int child_num_arg
     apr_thread_t *start_thread_id;
     apr_pool_t *pskip;
     int i;
-    ap_listen_rec *lr;
 
     mpm_state = AP_MPMQ_STARTING;       /* for benefit of any hooks that run as this
                                          * child initializes
@@ -2249,19 +2253,11 @@ static void child_main(int child_num_arg
     ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
-    child_listen = mpm_listen[child_bucket];
-    child_pod = pod[child_bucket];
-
     /* close unused listeners and pods */
     for (i = 0; i < num_buckets; i++) {
         if (i != child_bucket) {
-            lr = mpm_listen[i];
-            while(lr) {
-                apr_socket_close(lr->sd);
-                lr->active = 0;
-                lr = lr->next;
-            }
-            ap_mpm_podx_close(pod[i]);
+            ap_close_listeners_ex(all_buckets[i].listeners);
+            ap_mpm_podx_close(all_buckets[i].pod);
         }
     }
 
@@ -2375,7 +2371,7 @@ static void child_main(int child_num_arg
         apr_signal(SIGTERM, dummy_signal_handler);
         /* Watch for any messages from the parent over the POD */
         while (1) {
-            rv = ap_mpm_podx_check(child_pod);
+            rv = ap_mpm_podx_check(my_bucket->pod);
             if (rv == AP_MPM_PODX_NORESTART) {
                 /* see if termination was triggered while we slept */
                 switch (terminate_mode) {
@@ -2422,9 +2418,11 @@ static int make_child(server_rec * s, in
     }
 
     if (one_process) {
+        my_bucket = &all_buckets[0];
+
         set_signals();
         event_note_child_started(slot, getpid());
-        child_main(0, 0);
+        child_main(slot, 0);
         /* NOTREACHED */
         ap_assert(0);
         return -1;
@@ -2450,6 +2448,8 @@ static int make_child(server_rec * s, in
     }
 
     if (!pid) {
+        my_bucket = &all_buckets[bucket];
+
 #ifdef HAVE_BINDPROCESSOR
         /* By default, AIX binds to a single processor.  This bit unbinds
          * children which will then bind to another CPU.
@@ -2627,7 +2627,8 @@ static void perform_idle_server_maintena
 
     if (idle_thread_count > max_spare_threads / num_buckets) {
         /* Kill off one child */
-        ap_mpm_podx_signal(pod[child_bucket], AP_MPM_PODX_GRACEFUL);
+        ap_mpm_podx_signal(all_buckets[child_bucket].pod,
+                           AP_MPM_PODX_GRACEFUL);
         retained->idle_spawn_rate[child_bucket] = 1;
     }
     else if (idle_thread_count < min_spare_threads / num_buckets) {
@@ -2873,7 +2874,8 @@ static int event_run(apr_pool_t * _pconf
          * Kill child processes, tell them to call child_exit, etc...
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, /* Start with SIGTERM */
                                    event_note_child_killed);
@@ -2896,7 +2898,8 @@ static int event_run(apr_pool_t * _pconf
         /* Close our listeners, and then ask our children to do same */
         ap_close_listeners();
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
         ap_relieve_child_processes(event_note_child_killed);
 
@@ -2938,7 +2941,8 @@ static int event_run(apr_pool_t * _pconf
          * really dead.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, event_note_child_killed);
 
@@ -2966,7 +2970,8 @@ static int event_run(apr_pool_t * _pconf
                      " received.  Doing graceful restart");
         /* wake up the children...time to die.  But we'll have more soon */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
 
         /* This is mostly for debugging... so that we know what is still
@@ -2980,7 +2985,8 @@ static int event_run(apr_pool_t * _pconf
          * pthreads are stealing signals from us left and right.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
 
         ap_reclaim_child_processes(1,  /* Start with SIGTERM */
@@ -3000,6 +3006,7 @@ static int event_open_logs(apr_pool_t * 
 {
     int startup = 0;
     int level_flags = 0;
+    ap_listen_rec **listen_buckets;
     apr_status_t rv;
     int i;
 
@@ -3011,7 +3018,6 @@ static int event_open_logs(apr_pool_t * 
         level_flags |= APLOG_STARTUP;
     }
 
-    enable_default_listener = 0;
     if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
         ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
                      (startup ? NULL : s),
@@ -3019,21 +3025,33 @@ static int event_open_logs(apr_pool_t * 
         return DONE;
     }
 
-    enable_default_listener = 1;
-    ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
-
-    pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
-
-    if (!one_process) {
-        for (i = 0; i < num_buckets; i++) {
-            if ((rv = ap_mpm_podx_open(pconf, &pod[i]))) {
-                ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
-                             (startup ? NULL : s),
-                             "could not open pipe-of-death");
-                return DONE;
-            }
+    if (one_process) {
+        num_buckets = 1;
+    }
+    else if (!retained->is_graceful) { /* Preserve the number of buckets
+                                          on graceful restarts. */
+        num_buckets = 0;
+    }
+    if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
+                                     &listen_buckets, &num_buckets))) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                     (startup ? NULL : s),
+                     "could not duplicate listeners");
+        return DONE;
+    }
+    all_buckets = apr_pcalloc(pconf, num_buckets *
+                                     sizeof(event_child_bucket));
+    for (i = 0; i < num_buckets; i++) {
+        if (!one_process && /* no POD in one_process mode */
+                (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                         (startup ? NULL : s),
+                         "could not open pipe-of-death");
+            return DONE;
         }
+        all_buckets[i].listeners = listen_buckets[i];
     }
+
     /* for skiplist */
     srand((unsigned int)apr_time_now());
     return OK;
@@ -3067,17 +3085,6 @@ static int event_pre_config(apr_pool_t *
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
         retained->max_daemons_limit = -1;
     }
-    if (!retained->is_graceful) {
-        num_buckets = 1;
-#ifdef _SC_NPROCESSORS_ONLN
-        if (have_so_reuseport) {
-            int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN);
-            if (num_online_cores > 8) {
-                num_buckets = num_online_cores / 8;
-            }
-        }
-#endif
-    }
     ++retained->module_loads;
     if (retained->module_loads == 2) {
         /* test for correct operation of fdqueue */

Modified: httpd/httpd/trunk/server/mpm/prefork/prefork.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/prefork/prefork.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/prefork/prefork.c (original)
+++ httpd/httpd/trunk/server/mpm/prefork/prefork.c Thu Oct 30 15:24:58 2014
@@ -89,18 +89,12 @@
 
 /* config globals */
 
-static apr_proc_mutex_t **accept_mutex;
 static int ap_daemons_to_start=0;
 static int ap_daemons_min_free=0;
 static int ap_daemons_max_free=0;
 static int ap_daemons_limit=0;      /* MaxRequestWorkers */
 static int server_limit = 0;
 static int mpm_state = AP_MPMQ_STARTING;
-static ap_pod_t **pod;
-static ap_pod_t *child_pod;
-static apr_proc_mutex_t *child_mutex;
-static ap_listen_rec *child_listen;
-
 
 /* data retained by prefork across load/unload of the module
  * allocated on first call to pre-config hook; located on
@@ -132,6 +126,15 @@ typedef struct prefork_retained_data {
 } prefork_retained_data;
 static prefork_retained_data *retained;
 
+typedef struct prefork_child_bucket {
+    ap_pod_t *pod;
+    ap_listen_rec *listeners;
+    apr_proc_mutex_t *mutex;
+} prefork_child_bucket;
+static int                   num_buckets; /* Number of listeners buckets */
+static prefork_child_bucket *all_buckets, /* All listeners buckets */
+                            *my_bucket;   /* Current child bucket */
+
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
 
 /* one_process --- debugging mode variable; can be set from the command line
@@ -232,14 +235,14 @@ static void clean_child_exit(int code)
         prefork_note_child_killed(/* slot */ 0, 0, 0);
     }
 
-    ap_mpm_pod_close(child_pod);
+    ap_mpm_pod_close(my_bucket->pod);
     chdir_for_gprof();
     exit(code);
 }
 
-static void accept_mutex_on(void)
+static apr_status_t accept_mutex_on(void)
 {
-    apr_status_t rv = apr_proc_mutex_lock(child_mutex);
+    apr_status_t rv = apr_proc_mutex_lock(my_bucket->mutex);
     if (rv != APR_SUCCESS) {
         const char *msg = "couldn't grab the accept mutex";
 
@@ -253,11 +256,12 @@ static void accept_mutex_on(void)
             exit(APEXIT_CHILDFATAL);
         }
     }
+    return APR_SUCCESS;
 }
 
-static void accept_mutex_off(void)
+static apr_status_t accept_mutex_off(void)
 {
-    apr_status_t rv = apr_proc_mutex_unlock(child_mutex);
+    apr_status_t rv = apr_proc_mutex_unlock(my_bucket->mutex);
     if (rv != APR_SUCCESS) {
         const char *msg = "couldn't release the accept mutex";
 
@@ -274,6 +278,7 @@ static void accept_mutex_off(void)
             exit(APEXIT_CHILDFATAL);
         }
     }
+    return APR_SUCCESS;
 }
 
 /* On some architectures it's safe to do unserialized accept()s in the single
@@ -282,9 +287,9 @@ static void accept_mutex_off(void)
  * when it's safe in the single Listen case.
  */
 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
-#define SAFE_ACCEPT(stmt) do {if (child_listen->next) {stmt;}} while(0)
+#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)
 #else
-#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
+#define SAFE_ACCEPT(stmt) (stmt)
 #endif
 
 static int prefork_query(int query_code, int *result, apr_status_t *rv)
@@ -362,7 +367,7 @@ static int volatile die_now = 0;
 static void stop_listening(int sig)
 {
     mpm_state = AP_MPMQ_STOPPING;
-    ap_close_listeners();
+    ap_close_listeners_ex(my_bucket->listeners);
 
     /* For a graceful stop, we want the child to exit when done */
     die_now = 1;
@@ -512,10 +517,6 @@ static void child_main(int child_num_arg
     ap_my_pid = getpid();
     requests_this_child = 0;
 
-    child_listen = mpm_listen[child_bucket];
-    child_mutex = accept_mutex[child_bucket];
-    child_pod = pod[child_bucket];
-
     ap_fatal_signal_child_setup(ap_server_conf);
 
     /* Get a sub context for global allocations in this child, so that
@@ -538,28 +539,23 @@ static void child_main(int child_num_arg
     /* close unused listeners and pods */
     for (i = 0; i < num_buckets; i++) {
         if (i != child_bucket) {
-            lr = mpm_listen[i];
-            while(lr) {
-                apr_socket_close(lr->sd);
-                lr->active = 0;
-                lr = lr->next;
-            }
-            ap_mpm_pod_close(pod[i]);
+            ap_close_listeners_ex(all_buckets[i].listeners);
+            ap_mpm_pod_close(all_buckets[i].pod);
         }
     }
 
     /* needs to be done before we switch UIDs so we have permissions */
     ap_reopen_scoreboard(pchild, NULL, 0);
-    lockfile = apr_proc_mutex_lockfile(child_mutex);
-    status = apr_proc_mutex_child_init(&child_mutex,
-                                       lockfile,
-                                       pchild);
+    status = SAFE_ACCEPT(apr_proc_mutex_child_init(&my_bucket->mutex,
+                                    apr_proc_mutex_lockfile(my_bucket->mutex),
+                                    pchild));
     if (status != APR_SUCCESS) {
+        lockfile = apr_proc_mutex_lockfile(my_bucket->mutex);
         ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, APLOGNO(00155)
                      "Couldn't initialize cross-process lock in child "
                      "(%s) (%s)",
                      lockfile ? lockfile : "none",
-                     apr_proc_mutex_name(child_mutex));
+                     apr_proc_mutex_name(my_bucket->mutex));
         clean_child_exit(APEXIT_CHILDFATAL);
     }
 
@@ -581,7 +577,7 @@ static void child_main(int child_num_arg
         clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */
     }
 
-    for (lr = child_listen, i = num_listensocks; i--; lr = lr->next) {
+    for (lr = my_bucket->listeners, i = num_listensocks; i--; lr = lr->next) {
         apr_pollfd_t pfd = { 0 };
 
         pfd.desc_type = APR_POLL_SOCKET;
@@ -639,7 +635,7 @@ static void child_main(int child_num_arg
 
         if (num_listensocks == 1) {
             /* There is only one listener record, so refer to that one. */
-            lr = child_listen;
+            lr = my_bucket->listeners;
         }
         else {
             /* multiple listening sockets - need to poll */
@@ -737,7 +733,7 @@ static void child_main(int child_num_arg
          * while we were processing the connection or we are the lucky
          * idle server process that gets to die.
          */
-        if (ap_mpm_pod_check(child_pod) == APR_SUCCESS) { /* selected as idle? */
+        if (ap_mpm_pod_check(my_bucket->pod) == APR_SUCCESS) { /* selected as idle? */
             die_now = 1;
         }
         else if (retained->my_generation !=
@@ -762,6 +758,8 @@ static int make_child(server_rec *s, int
     }
 
     if (one_process) {
+        my_bucket = &all_buckets[0];
+
         apr_signal(SIGHUP, sig_term);
         /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
         apr_signal(SIGINT, sig_term);
@@ -770,7 +768,7 @@ static int make_child(server_rec *s, int
 #endif
         apr_signal(SIGTERM, sig_term);
         prefork_note_child_started(slot, getpid());
-        child_main(slot, bucket);
+        child_main(slot, 0);
         /* NOTREACHED */
         ap_assert(0);
         return -1;
@@ -803,6 +801,8 @@ static int make_child(server_rec *s, int
     }
 
     if (!pid) {
+        my_bucket = &all_buckets[bucket];
+
 #ifdef HAVE_BINDPROCESSOR
         /* by default AIX binds to a single processor
          * this bit unbinds children which will then bind to another cpu
@@ -913,7 +913,7 @@ static void perform_idle_server_maintena
          * while we were counting
          */
         bucket_kill_child_record = (bucket_kill_child_record + 1) % num_buckets;
-        ap_mpm_pod_signal(pod[bucket_kill_child_record]);
+        ap_mpm_pod_signal(all_buckets[bucket_kill_child_record].pod);
         retained->idle_spawn_rate = 1;
     }
     else if (idle_count < ap_daemons_min_free) {
@@ -966,22 +966,10 @@ static int prefork_run(apr_pool_t *_pcon
 {
     int index;
     int remaining_children_to_start;
-    apr_status_t rv;
     int i;
 
     ap_log_pid(pconf, ap_pid_fname);
 
-    /* Initialize cross-process accept lock for each bucket*/
-    accept_mutex = apr_palloc(_pconf, sizeof(apr_proc_mutex_t *) * num_buckets);
-    for (i = 0; i < num_buckets; i++) {
-        rv = ap_proc_mutex_create(&accept_mutex[i], NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
-                                  s, _pconf, 0);
-        if (rv != APR_SUCCESS) {
-            mpm_state = AP_MPMQ_STOPPING;
-            return !OK;
-        }
-     }
-
     if (!retained->is_graceful) {
         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
             mpm_state = AP_MPMQ_STOPPING;
@@ -1040,7 +1028,7 @@ static int prefork_run(apr_pool_t *_pcon
     ap_log_common(s);
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00165)
                 "Accept mutex: %s (default: %s)",
-                apr_proc_mutex_name(accept_mutex[0]),
+                apr_proc_mutex_name(all_buckets[0].mutex),
                 apr_proc_mutex_defname());
 
     mpm_state = AP_MPMQ_RUNNING;
@@ -1172,7 +1160,7 @@ static int prefork_run(apr_pool_t *_pcon
 
         /* kill off the idle ones */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_pod_killpg(pod[i], retained->max_daemons_limit);
+            ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit);
         }
 
         /* Send SIGUSR1 to the active children */
@@ -1248,7 +1236,7 @@ static int prefork_run(apr_pool_t *_pcon
 
         /* kill off the idle ones */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_pod_killpg(pod[i], retained->max_daemons_limit);
+            ap_mpm_pod_killpg(all_buckets[i].pod, retained->max_daemons_limit);
         }
 
         /* This is mostly for debugging... so that we know what is still
@@ -1291,6 +1279,7 @@ static int prefork_open_logs(apr_pool_t 
 {
     int startup = 0;
     int level_flags = 0;
+    ap_listen_rec **listen_buckets;
     apr_status_t rv;
     int i;
 
@@ -1302,7 +1291,6 @@ static int prefork_open_logs(apr_pool_t 
         level_flags |= APLOG_STARTUP;
     }
 
-    enable_default_listener = 0;
     if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
         ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
                      (startup ? NULL : s),
@@ -1310,18 +1298,41 @@ static int prefork_open_logs(apr_pool_t 
         return DONE;
     }
 
-    enable_default_listener = 1;
-    ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
-
-    pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
+    if (one_process) {
+        num_buckets = 1;
+    }
+    else if (!retained->is_graceful) { /* Preserve the number of buckets
+                                          on graceful restarts. */
+        num_buckets = 0;
+    }
+    if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
+                                     &listen_buckets, &num_buckets))) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                     (startup ? NULL : s),
+                     "could not duplicate listeners");
+        return DONE;
+    }
+    all_buckets = apr_pcalloc(pconf, num_buckets *
+                                     sizeof(prefork_child_bucket));
     for (i = 0; i < num_buckets; i++) {
-        if ((rv = ap_mpm_pod_open(pconf, &pod[i]))) {
+        if (!one_process && /* no POD in one_process mode */
+                (rv = ap_mpm_pod_open(pconf, &all_buckets[i].pod))) {
             ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
                          (startup ? NULL : s),
                          "could not open pipe-of-death");
             return DONE;
         }
-     }
+        /* Initialize cross-process accept lock when safe accept is needed */
+        if ((rv = SAFE_ACCEPT(ap_proc_mutex_create(&all_buckets[i].mutex, NULL,
+                                                   AP_ACCEPT_MUTEX_TYPE, NULL,
+                                                   s, pconf, 0)))) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                         (startup ? NULL : s),
+                         "could not create accept mutex");
+            return DONE;
+        }
+        all_buckets[i].listeners = listen_buckets[i];
+    }
 
     return OK;
 }
@@ -1356,17 +1367,6 @@ static int prefork_pre_config(apr_pool_t
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
-    if (!retained->is_graceful) {
-        num_buckets = 1;
-#ifdef _SC_NPROCESSORS_ONLN
-        if (have_so_reuseport) {
-            int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN);
-            if (num_online_cores > 8) {
-                num_buckets = num_online_cores / 8;
-            }
-        }
-#endif
-    }
     ++retained->module_loads;
     if (retained->module_loads == 2) {
         if (!one_process && !foreground) {

Modified: httpd/httpd/trunk/server/mpm/worker/worker.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm/worker/worker.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm/worker/worker.c (original)
+++ httpd/httpd/trunk/server/mpm/worker/worker.c Thu Oct 30 15:24:58 2014
@@ -171,6 +171,15 @@ typedef struct worker_retained_data {
 } worker_retained_data;
 static worker_retained_data *retained;
 
+typedef struct worker_child_bucket {
+    ap_pod_t *pod;
+    ap_listen_rec *listeners;
+    apr_proc_mutex_t *mutex;
+} worker_child_bucket;
+static int                  num_buckets; /* Number of listeners buckets */
+static worker_child_bucket *all_buckets, /* All listeners buckets */
+                           *my_bucket;   /* Current child bucket */
+
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
 
 /* The structure used to pass unique initialization info to each thread */
@@ -192,9 +201,6 @@ typedef struct {
 
 #define ID_FROM_CHILD_THREAD(c, t)    ((c * thread_limit) + t)
 
-static ap_pod_t **pod;
-static ap_pod_t *child_pod;
-
 /* The worker MPM respects a couple of runtime flags that can aid
  * in debugging. Setting the -DNO_DETACH flag will prevent the root process
  * from detaching from its controlling terminal. Additionally, setting
@@ -222,13 +228,8 @@ static pid_t ap_my_pid; /* Linux getpid(
 static pid_t parent_pid;
 static apr_os_thread_t *listener_os_thread;
 
-/* Locks for accept serialization */
-static apr_proc_mutex_t **accept_mutex;
-static apr_proc_mutex_t *child_mutex;
-static ap_listen_rec *child_listen;
-
 #ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
-#define SAFE_ACCEPT(stmt) (child_listen->next ? (stmt) : APR_SUCCESS)
+#define SAFE_ACCEPT(stmt) (ap_listeners->next ? (stmt) : APR_SUCCESS)
 #else
 #define SAFE_ACCEPT(stmt) (stmt)
 #endif
@@ -708,7 +709,7 @@ static void * APR_THREAD_FUNC listener_t
         clean_child_exit(APEXIT_CHILDSICK);
     }
 
-    for (lr = child_listen; lr != NULL; lr = lr->next) {
+    for (lr = my_bucket->listeners; lr != NULL; lr = lr->next) {
         apr_pollfd_t pfd = { 0 };
 
         pfd.desc_type = APR_POLL_SOCKET;
@@ -765,7 +766,7 @@ static void * APR_THREAD_FUNC listener_t
         /* We've already decremented the idle worker count inside
          * ap_queue_info_wait_for_idler. */
 
-        if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(child_mutex)))
+        if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(my_bucket->mutex)))
             != APR_SUCCESS) {
 
             if (!listener_may_exit) {
@@ -774,9 +775,9 @@ static void * APR_THREAD_FUNC listener_t
             break;                    /* skip the lock release */
         }
 
-        if (!child_listen->next) {
+        if (!my_bucket->listeners->next) {
             /* Only one listener, so skip the poll */
-            lr = child_listen;
+            lr = my_bucket->listeners;
         }
         else {
             while (!listener_may_exit) {
@@ -846,7 +847,7 @@ static void * APR_THREAD_FUNC listener_t
                 resource_shortage = 1;
                 signal_threads(ST_GRACEFUL);
             }
-            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(child_mutex)))
+            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(my_bucket->mutex)))
                 != APR_SUCCESS) {
 
                 if (listener_may_exit) {
@@ -870,7 +871,7 @@ static void * APR_THREAD_FUNC listener_t
             }
         }
         else {
-            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(child_mutex)))
+            if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(my_bucket->mutex)))
                 != APR_SUCCESS) {
                 int level = APLOG_EMERG;
 
@@ -887,7 +888,7 @@ static void * APR_THREAD_FUNC listener_t
         }
     }
 
-    ap_close_listeners();
+    ap_close_listeners_ex(my_bucket->listeners);
     ap_queue_term(worker_queue);
     dying = 1;
     ap_scoreboard_image->parent[process_slot].quiescing = 1;
@@ -1225,7 +1226,6 @@ static void child_main(int child_num_arg
     apr_threadattr_t *thread_attr;
     apr_thread_t *start_thread_id;
     int i;
-    ap_listen_rec *lr;
 
     mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
                                    * child initializes
@@ -1234,29 +1234,20 @@ static void child_main(int child_num_arg
     ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
-    child_listen = mpm_listen[child_bucket];
-    child_mutex = accept_mutex[child_bucket];
-    child_pod = pod[child_bucket];
-
     /* close unused listeners and pods */
     for (i = 0; i < num_buckets; i++) {
         if (i != child_bucket) {
-            lr = mpm_listen[i];
-            while(lr) {
-                apr_socket_close(lr->sd);
-                lr->active = 0;
-                lr = lr->next;
-            }
-            ap_mpm_podx_close(pod[i]);
+            ap_close_listeners_ex(all_buckets[i].listeners);
+            ap_mpm_podx_close(all_buckets[i].pod);
         }
     }
 
     /*stuff to do before we switch id's, so we have permissions.*/
     ap_reopen_scoreboard(pchild, NULL, 0);
 
-    rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&child_mutex,
-                                               apr_proc_mutex_lockfile(child_mutex),
-                                               pchild));
+    rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&my_bucket->mutex,
+                                    apr_proc_mutex_lockfile(my_bucket->mutex),
+                                    pchild));
     if (rv != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, APLOGNO(00280)
                      "Couldn't initialize cross-process lock in child");
@@ -1364,7 +1355,7 @@ static void child_main(int child_num_arg
         apr_signal(SIGTERM, dummy_signal_handler);
         /* Watch for any messages from the parent over the POD */
         while (1) {
-            rv = ap_mpm_podx_check(child_pod);
+            rv = ap_mpm_podx_check(my_bucket->pod);
             if (rv == AP_MPM_PODX_NORESTART) {
                 /* see if termination was triggered while we slept */
                 switch(terminate_mode) {
@@ -1411,9 +1402,11 @@ static int make_child(server_rec *s, int
     }
 
     if (one_process) {
+        my_bucket = &all_buckets[0];
+
         set_signals();
         worker_note_child_started(slot, getpid());
-        child_main(0, 0);
+        child_main(slot, 0);
         /* NOTREACHED */
         ap_assert(0);
         return -1;
@@ -1438,6 +1431,8 @@ static int make_child(server_rec *s, int
     }
 
     if (!pid) {
+        my_bucket = &all_buckets[bucket];
+
 #ifdef HAVE_BINDPROCESSOR
         /* By default, AIX binds to a single processor.  This bit unbinds
          * children which will then bind to another CPU.
@@ -1613,7 +1608,8 @@ static void perform_idle_server_maintena
 
     if (idle_thread_count > max_spare_threads / num_buckets) {
         /* Kill off one child */
-        ap_mpm_podx_signal(pod[child_bucket], AP_MPM_PODX_GRACEFUL);
+        ap_mpm_podx_signal(all_buckets[child_bucket].pod,
+                           AP_MPM_PODX_GRACEFUL);
         retained->idle_spawn_rate[child_bucket] = 1;
     }
     else if (idle_thread_count < min_spare_threads / num_buckets) {
@@ -1805,22 +1801,10 @@ static void server_main_loop(int remaini
 static int worker_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
 {
     int remaining_children_to_start;
-    apr_status_t rv;
     int i;
 
     ap_log_pid(pconf, ap_pid_fname);
 
-    /* Initialize cross-process accept lock */
-    accept_mutex = apr_palloc(_pconf, sizeof(apr_proc_mutex_t *) * num_buckets);
-    for (i = 0; i < num_buckets; i++) {
-        rv = ap_proc_mutex_create(&accept_mutex[i], NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
-                                  s, _pconf, 0);
-        if (rv != APR_SUCCESS) {
-            mpm_state = AP_MPMQ_STOPPING;
-            return !OK;
-        }
-    }
-
     if (!retained->is_graceful) {
         if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
             mpm_state = AP_MPMQ_STOPPING;
@@ -1873,7 +1857,7 @@ static int worker_run(apr_pool_t *_pconf
     ap_log_common(s);
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00294)
                 "Accept mutex: %s (default: %s)",
-                apr_proc_mutex_name(accept_mutex[0]),
+                apr_proc_mutex_name(all_buckets[0].mutex),
                 apr_proc_mutex_defname());
     mpm_state = AP_MPMQ_RUNNING;
 
@@ -1885,7 +1869,8 @@ static int worker_run(apr_pool_t *_pconf
          * Kill child processes, tell them to call child_exit, etc...
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, /* Start with SIGTERM */
                                    worker_note_child_killed);
@@ -1907,8 +1892,10 @@ static int worker_run(apr_pool_t *_pconf
 
         /* Close our listeners, and then ask our children to do same */
         ap_close_listeners();
+
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
         ap_relieve_child_processes(worker_note_child_killed);
 
@@ -1950,7 +1937,8 @@ static int worker_run(apr_pool_t *_pconf
          * really dead.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
         ap_reclaim_child_processes(1, worker_note_child_killed);
 
@@ -1977,7 +1965,8 @@ static int worker_run(apr_pool_t *_pconf
                      AP_SIG_GRACEFUL_STRING " received.  Doing graceful restart");
         /* wake up the children...time to die.  But we'll have more soon */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_GRACEFUL);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_GRACEFUL);
         }
 
         /* This is mostly for debugging... so that we know what is still
@@ -1991,7 +1980,8 @@ static int worker_run(apr_pool_t *_pconf
          * pthreads are stealing signals from us left and right.
          */
         for (i = 0; i < num_buckets; i++) {
-            ap_mpm_podx_killpg(pod[i], ap_daemons_limit, AP_MPM_PODX_RESTART);
+            ap_mpm_podx_killpg(all_buckets[i].pod, ap_daemons_limit,
+                               AP_MPM_PODX_RESTART);
         }
 
         ap_reclaim_child_processes(1, /* Start with SIGTERM */
@@ -2010,6 +2000,7 @@ static int worker_open_logs(apr_pool_t *
 {
     int startup = 0;
     int level_flags = 0;
+    ap_listen_rec **listen_buckets;
     apr_status_t rv;
     int i;
 
@@ -2021,7 +2012,6 @@ static int worker_open_logs(apr_pool_t *
         level_flags |= APLOG_STARTUP;
     }
 
-    enable_default_listener = 0;
     if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
         ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
                      (startup ? NULL : s),
@@ -2029,20 +2019,42 @@ static int worker_open_logs(apr_pool_t *
         return DONE;
     }
 
-    enable_default_listener = 1;
-    ap_duplicate_listeners(ap_server_conf, pconf, num_buckets);
-
-    pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
-    if (!one_process) {
-        for (i = 0; i < num_buckets; i++) {
-            if ((rv = ap_mpm_podx_open(pconf, &pod[i]))) {
-                ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
-                             (startup ? NULL : s),
-                             "could not open pipe-of-death");
-                return DONE;
-            }
+    if (one_process) {
+        num_buckets = 1;
+    }
+    else if (!retained->is_graceful) { /* Preserve the number of buckets
+                                          on graceful restarts. */
+        num_buckets = 0;
+    }
+    if ((rv = ap_duplicate_listeners(pconf, ap_server_conf,
+                                     &listen_buckets, &num_buckets))) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                     (startup ? NULL : s),
+                     "could not duplicate listeners");
+        return DONE;
+    }
+    all_buckets = apr_pcalloc(pconf, num_buckets *
+                                     sizeof(worker_child_bucket));
+    for (i = 0; i < num_buckets; i++) {
+        if (!one_process && /* no POD in one_process mode */
+                (rv = ap_mpm_podx_open(pconf, &all_buckets[i].pod))) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                         (startup ? NULL : s),
+                         "could not open pipe-of-death");
+            return DONE;
+        }
+        /* Initialize cross-process accept lock when safe accept is needed */
+        if ((rv = SAFE_ACCEPT(ap_proc_mutex_create(&all_buckets[i].mutex, NULL,
+                                                   AP_ACCEPT_MUTEX_TYPE, NULL,
+                                                   s, pconf, 0)))) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
+                         (startup ? NULL : s),
+                         "could not create accept mutex");
+            return DONE;
         }
+        all_buckets[i].listeners = listen_buckets[i];
     }
+
     return OK;
 }
 
@@ -2076,17 +2088,6 @@ static int worker_pre_config(apr_pool_t 
         retained = ap_retained_data_create(userdata_key, sizeof(*retained));
         retained->max_daemons_limit = -1;
     }
-    if (!retained->is_graceful) {
-        num_buckets = 1;
-#ifdef _SC_NPROCESSORS_ONLN
-        if (have_so_reuseport) {
-            int num_online_cores = sysconf(_SC_NPROCESSORS_ONLN);
-            if (num_online_cores > 8) {
-                num_buckets = num_online_cores / 8;
-            }
-        }
-#endif
-    }
     ++retained->module_loads;
     if (retained->module_loads == 2) {
         if (!one_process && !foreground) {

Modified: httpd/httpd/trunk/server/mpm_unix.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/mpm_unix.c?rev=1635521&r1=1635520&r2=1635521&view=diff
==============================================================================
--- httpd/httpd/trunk/server/mpm_unix.c (original)
+++ httpd/httpd/trunk/server/mpm_unix.c Thu Oct 30 15:24:58 2014
@@ -615,7 +615,6 @@ static apr_status_t dummy_connection(ap_
     apr_pool_t *p;
     apr_size_t len;
     ap_listen_rec *lp;
-    int i;
 
     /* create a temporary pool for the socket.  pconf stays around too long */
     rv = apr_pool_create(&p, pod->p);
@@ -627,89 +626,87 @@ static apr_status_t dummy_connection(ap_
      * plain-HTTP, not SSL; using an SSL port would either be
      * expensive to do correctly (performing a complete SSL handshake)
      * or cause log spam by doing incorrectly (simply sending EOF). */
-    for (i = 0; i < num_buckets; i++) {
-        lp = mpm_listen[i];
-        while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
-            lp = lp->next;
-        }
-        if (!lp) {
-            lp = mpm_listen[i];
-        }
-
-        rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
-        if (rv != APR_SUCCESS) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054)
-                         "get socket to connect to listener");
-            apr_pool_destroy(p);
-            return rv;
-        }
-
-        /* on some platforms (e.g., FreeBSD), the kernel won't accept many
-         * queued connections before it starts blocking local connects...
-         * we need to keep from blocking too long and instead return an error,
-         * because the MPM won't want to hold up a graceful restart for a
-         * long time
-         */
-        rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
-        if (rv != APR_SUCCESS) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055)
-                         "set timeout on socket to connect to listener");
-            apr_socket_close(sock);
-            apr_pool_destroy(p);
-            return rv;
-        }
-
-        rv = apr_socket_connect(sock, lp->bind_addr);
-        if (rv != APR_SUCCESS) {
-            int log_level = APLOG_WARNING;
-
-            if (APR_STATUS_IS_TIMEUP(rv)) {
-                /* probably some server processes bailed out already and there
-                 * is nobody around to call accept and clear out the kernel
-                 * connection queue; usually this is not worth logging
-                 */
-                log_level = APLOG_DEBUG;
-            }
+    lp = ap_listeners;
+    while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
+        lp = lp->next;
+    }
+    if (!lp) {
+        lp = ap_listeners;
+    }
 
-            ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056)
-                         "connect to listener on %pI", lp->bind_addr);
-            apr_pool_destroy(p);
-            return rv;
-        }
-
-        if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) {
-            /* Send a TLS 1.0 close_notify alert.  This is perhaps the
-             * "least wrong" way to open and cleanly terminate an SSL
-             * connection.  It should "work" without noisy error logs if
-             * the server actually expects SSLv3/TLSv1.  With
-             * SSLv23_server_method() OpenSSL's SSL_accept() fails
-             * ungracefully on receipt of this message, since it requires
-             * an 11-byte ClientHello message and this is too short. */
-            static const unsigned char tls10_close_notify[7] = {
-                '\x15',         /* TLSPlainText.type = Alert (21) */
-                '\x03', '\x01', /* TLSPlainText.version = {3, 1} */
-                '\x00', '\x02', /* TLSPlainText.length = 2 */
-                '\x01',         /* Alert.level = warning (1) */
-                '\x00'          /* Alert.description = close_notify (0) */
-            };
-            data = (const char *)tls10_close_notify;
-            len = sizeof(tls10_close_notify);
-        }
-        else /* ... XXX other request types here? */ {
-            /* Create an HTTP request string.  We include a User-Agent so
-             * that adminstrators can track down the cause of the
-             * odd-looking requests in their logs.  A complete request is
-             * used since kernel-level filtering may require that much
-             * data before returning from accept(). */
-            data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
-                               ap_get_server_description(),
-                               " (internal dummy connection)\r\n\r\n", NULL);
-            len = strlen(data);
-        }
+    rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054)
+                     "get socket to connect to listener");
+        apr_pool_destroy(p);
+        return rv;
+    }
 
-        apr_socket_send(sock, data, &len);
+    /* on some platforms (e.g., FreeBSD), the kernel won't accept many
+     * queued connections before it starts blocking local connects...
+     * we need to keep from blocking too long and instead return an error,
+     * because the MPM won't want to hold up a graceful restart for a
+     * long time
+     */
+    rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055)
+                     "set timeout on socket to connect to listener");
         apr_socket_close(sock);
+        apr_pool_destroy(p);
+        return rv;
     }
+
+    rv = apr_socket_connect(sock, lp->bind_addr);
+    if (rv != APR_SUCCESS) {
+        int log_level = APLOG_WARNING;
+
+        if (APR_STATUS_IS_TIMEUP(rv)) {
+            /* probably some server processes bailed out already and there
+             * is nobody around to call accept and clear out the kernel
+             * connection queue; usually this is not worth logging
+             */
+            log_level = APLOG_DEBUG;
+        }
+
+        ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056)
+                     "connect to listener on %pI", lp->bind_addr);
+        apr_pool_destroy(p);
+        return rv;
+    }
+
+    if (lp->protocol && strcasecmp(lp->protocol, "https") == 0) {
+        /* Send a TLS 1.0 close_notify alert.  This is perhaps the
+         * "least wrong" way to open and cleanly terminate an SSL
+         * connection.  It should "work" without noisy error logs if
+         * the server actually expects SSLv3/TLSv1.  With
+         * SSLv23_server_method() OpenSSL's SSL_accept() fails
+         * ungracefully on receipt of this message, since it requires
+         * an 11-byte ClientHello message and this is too short. */
+        static const unsigned char tls10_close_notify[7] = {
+            '\x15',         /* TLSPlainText.type = Alert (21) */
+            '\x03', '\x01', /* TLSPlainText.version = {3, 1} */
+            '\x00', '\x02', /* TLSPlainText.length = 2 */
+            '\x01',         /* Alert.level = warning (1) */
+            '\x00'          /* Alert.description = close_notify (0) */
+        };
+        data = (const char *)tls10_close_notify;
+        len = sizeof(tls10_close_notify);
+    }
+    else /* ... XXX other request types here? */ {
+        /* Create an HTTP request string.  We include a User-Agent so
+         * that adminstrators can track down the cause of the
+         * odd-looking requests in their logs.  A complete request is
+         * used since kernel-level filtering may require that much
+         * data before returning from accept(). */
+        data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ",
+                           ap_get_server_description(),
+                           " (internal dummy connection)\r\n\r\n", NULL);
+        len = strlen(data);
+    }
+
+    apr_socket_send(sock, data, &len);
+    apr_socket_close(sock);
     apr_pool_destroy(p);
 
     return rv;



Mime
View raw message