]> granicus.if.org Git - apache/commitdiff
MPMs, core: make duplicated listeners (SO_REUSEPORT) introduced in r1599531
authorYann Ylavic <ylavic@apache.org>
Thu, 30 Oct 2014 15:24:58 +0000 (15:24 +0000)
committerYann Ylavic <ylavic@apache.org>
Thu, 30 Oct 2014 15:24:58 +0000 (15:24 +0000)
            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.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1635521 13f79535-47bb-0310-9956-ffa450edef68

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

index eebd44e48e8dddcd17825505bb3492865e58f482..c5efbfab6446045a36b555d238a61deb36bb373c 100644 (file)
@@ -1 +1 @@
-2819
+2821
index 4538ef9648c1f0c7a8292d736d83f189c1b16a3a..9e3098f2c8255263a3089b32826224c05dce982f 100644 (file)
@@ -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,19 +93,34 @@ AP_DECLARE(void) ap_listen_pre_config(void);
  */
 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.
  */
 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
  */
@@ -125,6 +134,7 @@ AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *);
  * 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_receive_buffer_size(cmd_parms *cmd,
 #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, \
index eb2efc8cbc21a84170d25ea93e1205157dbdb1a6..17f83f65559b6cf70be743c9dd7c01fe203a1454 100644 (file)
  * 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" */
 #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
index 8bf0b3272ee3e4152a92269790f6eb4bd7abb616..db3186de40ae7d9c942e45eeb0896530c6411c82 100644 (file)
 #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
 
 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 *p, ap_listen_rec *server, int do_bind_
     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 *p, ap_listen_rec *server, int do_bind_
 #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 *pool)
                 }
             }
 #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 *pool)
     }
 
     /* 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(server_rec *s)
         }
     }
 
-
 #ifdef HAVE_SYSTEMD
     if (use_systemd) {
         const char *userdata_key = "ap_open_systemd_listeners";
@@ -758,15 +762,48 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
     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_listeners(server_rec *s, apr_pool_t *p,
             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_listeners(server_rec *s, apr_pool_t *p,
                 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_listeners(server_rec *s, apr_pool_t *p,
             }
 #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_listeners(server_rec *s, apr_pool_t *p,
             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_listeners(server_rec *s, apr_pool_t *p,
             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(void)
 {
     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_listenbacklog(cmd_parms *cmd,
     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)
index 2d35d35e6c37c62614eb0e5e235e2ea1c339ec2c..07fb057487e154fb796ba00a477de87978cf8eb1 100644 (file)
@@ -1493,8 +1493,8 @@ AP_DECLARE(void) ap_log_common(server_rec *s)
 {
     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)
index 2e9615ecc48d76102e113be22dea5a4abaaa0d30..24899cf511f9d973ffbc1cb6c0a64a35f85fece5 100644 (file)
@@ -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_pool_t *p)
     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, int child_bucket)
     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, int child_bucket)
     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, int child_bucket)
         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, int slot, int bucket)
     }
 
     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, int slot, int bucket)
     }
 
     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_maintenance(int child_bucket)
 
     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, apr_pool_t * plog, server_rec * s)
          * 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, apr_pool_t * plog, server_rec * s)
         /* 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, apr_pool_t * plog, server_rec * s)
          * 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, apr_pool_t * plog, server_rec * s)
                      " 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, apr_pool_t * plog, server_rec * s)
          * 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 * p, apr_pool_t * plog,
 {
     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 * p, apr_pool_t * plog,
         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 * p, apr_pool_t * plog,
         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 * pconf, apr_pool_t * plog,
         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 */
index a377865f73030a0b0a3014e75c967353fb7cd601..56f69743fb8af977393633bacfbf3a66a29d2d29 100644 (file)
@@ -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_pool_t *p)
     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, int child_bucket)
     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, int child_bucket)
     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, int child_bucket)
         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, int slot, int bucket)
     }
 
     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, int slot, int bucket)
     }
 
     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_maintenance(int child_bucket)
 
     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, apr_pool_t * plog, server_rec * s)
          * 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, apr_pool_t * plog, server_rec * s)
         /* 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, apr_pool_t * plog, server_rec * s)
          * 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, apr_pool_t * plog, server_rec * s)
                      " 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, apr_pool_t * plog, server_rec * s)
          * 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 * p, apr_pool_t * plog,
 {
     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 * p, apr_pool_t * plog,
         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 * p, apr_pool_t * plog,
         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 * pconf, apr_pool_t * plog,
         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 */
index 0b1714ba33b24f40c282ce2100874df5e08be2b1..daa8569cf239cf563170530303bb78eca7985a49 100644 (file)
 
 /* 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, int child_bucket)
     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, int 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_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, int child_bucket)
         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, int child_bucket)
 
         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, int child_bucket)
          * 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 slot, int bucket)
     }
 
     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 slot, int bucket)
 #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 slot, int bucket)
     }
 
     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_maintenance(apr_pool_t *p)
          * 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 *_pconf, apr_pool_t *plog, server_rec *s)
 {
     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 *_pconf, apr_pool_t *plog, server_rec *s)
     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 *_pconf, apr_pool_t *plog, server_rec *s)
 
         /* 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 *_pconf, apr_pool_t *plog, server_rec *s)
 
         /* 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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
 {
     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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
         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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
         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 *p, apr_pool_t *plog, apr_pool_t *ptemp
         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) {
index 70261fc11c34b4f15b9cf87a4fd73bd5b0019aa2..0296e67f23b528a1dddcfb83b1ec463c30498190 100644 (file)
@@ -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() doesn't work except in main
 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_thread(apr_thread_t *thd, void * dummy)
         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_thread(apr_thread_t *thd, void * dummy)
         /* 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_thread(apr_thread_t *thd, void * dummy)
             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_thread(apr_thread_t *thd, void * dummy)
                 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_thread(apr_thread_t *thd, void * dummy)
             }
         }
         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_thread(apr_thread_t *thd, void * dummy)
         }
     }
 
-    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, int child_bucket)
     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, int child_bucket)
     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, int child_bucket)
         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 slot, int bucket)
     }
 
     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 slot, int bucket)
     }
 
     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_maintenance(int child_bucket)
 
     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 remaining_children_to_start)
 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, apr_pool_t *plog, server_rec *s)
     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, apr_pool_t *plog, server_rec *s)
          * 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, apr_pool_t *plog, server_rec *s)
 
         /* 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, apr_pool_t *plog, server_rec *s)
          * 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, apr_pool_t *plog, server_rec *s)
                      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, apr_pool_t *plog, server_rec *s)
          * 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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
 {
     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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
         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 *p, apr_pool_t *plog, apr_pool_t *ptemp,
         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 *pconf, apr_pool_t *plog,
         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) {
index 1ea08e66d1226d7b333f635ecf1a126db8751d7d..1a7f9359c73b51e0a7dbe178f15114f0464baf7c 100644 (file)
@@ -615,7 +615,6 @@ static apr_status_t dummy_connection(ap_pod_t *pod)
     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_pod_t *pod)
      * 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;
-        }
+    lp = ap_listeners;
+    while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
+        lp = lp->next;
+    }
+    if (!lp) {
+        lp = ap_listeners;
+    }
 
-        rv = apr_socket_connect(sock, lp->bind_addr);
-        if (rv != APR_SUCCESS) {
-            int log_level = APLOG_WARNING;
+    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;
+    }
 
-            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;
-            }
+    /* 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;
+    }
 
-            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;
+    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;
         }
 
-        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);
-        }
+        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;
+    }
 
-        apr_socket_send(sock, data, &len);
-        apr_socket_close(sock);
+    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;