Only in httpd-2.4.7.new: 1 diff -ru httpd-2.4.7/configure httpd-2.4.7.new/configure --- httpd-2.4.7/configure 2013-11-19 12:36:02.000000000 -0500 +++ httpd-2.4.7.new/configure 2013-12-15 12:32:24.151998734 -0500 @@ -6354,7 +6354,20 @@ APACHE_VAR_SUBST="$APACHE_VAR_SUBST LTCFLAGS" +case $host in + *-linux-*) + case `uname -r` in + # SO_REUSEPORT feature is only being enabled in the Linux kernel newer than 3.9 + [0-2].* | 3.[0-8].*) + ;; + * ) + test "x$silent" != "xyes" && echo " forcing HAVE_SO_REUSEPORT to \"1\"" + HAVE_SO_REUSEPORT="1" + ;; + esac + ;; +esac case $host in *-apple-aux3*) @@ -32191,6 +32204,12 @@ fi +if test "$HAVE_SO_REUSEPORT" = "1"; then + +$as_echo "#define HAVE_SO_REUSEPORT 1" >>confdefs.h + +fi + if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then $as_echo "#define AP_NONBLOCK_WHEN_MULTI_LISTEN 1" >>confdefs.h diff -ru httpd-2.4.7/configure.in httpd-2.4.7.new/configure.in --- httpd-2.4.7/configure.in 2013-08-19 11:42:37.000000000 -0400 +++ httpd-2.4.7.new/configure.in 2013-12-15 12:32:31.207998621 -0500 @@ -307,6 +307,19 @@ APACHE_SUBST(LTCFLAGS) case $host in + *-linux-*) + case `uname -r` in + #SO_REUSEPORT is only being enabled in Linux kernel 3.9 and newer + [[0-2]].* | 3.[[0-8]].* ) + ;; + * ) + APR_SETVAR(HAVE_SO_REUSEPORT, [1]) + ;; + esac + ;; +esac + +case $host in *-apple-aux3*) APR_SETVAR(SINGLE_LISTEN_UNSERIALIZED_ACCEPT, [1]) ;; @@ -761,6 +774,11 @@ [This platform doesn't suffer from the thundering herd problem]) fi +if test "$HAVE_SO_REUSEPORT" = "1"; then + AC_DEFINE(HAVE_SO_REUSEPORT, 1, + [This platform has SO_REUSEPORT feature enabled]) +fi + if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then AC_DEFINE(AP_NONBLOCK_WHEN_MULTI_LISTEN, 1, [Listening sockets are non-blocking when there are more than 1]) diff -ru httpd-2.4.7/include/ap_config_auto.h.in httpd-2.4.7.new/include/ap_config_auto.h.in --- httpd-2.4.7/include/ap_config_auto.h.in 2013-11-19 12:36:01.000000000 -0500 +++ httpd-2.4.7.new/include/ap_config_auto.h.in 2013-12-15 12:33:03.447998106 -0500 @@ -229,6 +229,9 @@ /* This platform doesn't suffer from the thundering herd problem */ #undef SINGLE_LISTEN_UNSERIALIZED_ACCEPT +/* Define to 1 if you have SO_REUSEPORT enabled in your kernel. Linux kernel newer than 3.9 has this enabled */ +#undef HAVE_SO_REUSEPORT + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS diff -ru httpd-2.4.7/include/ap_listen.h httpd-2.4.7.new/include/ap_listen.h --- httpd-2.4.7/include/ap_listen.h 2011-09-23 14:08:42.000000000 -0400 +++ httpd-2.4.7.new/include/ap_listen.h 2013-12-17 08:33:54.396964779 -0500 @@ -79,6 +79,15 @@ AP_DECLARE_DATA extern ap_listen_rec *ap_listeners; /** + ** The listener array defined for the patch. + ** */ +AP_DECLARE_DATA extern ap_listen_rec **mpm_listen; + +AP_DECLARE_DATA extern int flag; + +AP_DECLARE_DATA extern int num_buckets; + +/** * Setup all of the defaults for the listener list */ AP_DECLARE(void) ap_listen_pre_config(void); @@ -91,6 +100,15 @@ */ AP_DECLARE(int) ap_setup_listeners(server_rec *s); +/**This function is added for the patch. It creates sockets for the mpm_listen + * array, executes the listen and bind on the sockets, and set the sockets to + * be active. If HAVE_SO_REUSEPORT is enabled, It will duplicate ap_listeners. + * @param s The global server_rec + * @param p The config pool + * @param num_buckets The total number of listener buckets. + * */ +AP_DECLARE(apr_status_t) ap_post_config_listeners(server_rec *s, apr_pool_t *p, int num_buckets); + /** * Loop through the global ap_listen_rec list and close each of the sockets. */ diff -ru httpd-2.4.7/server/listen.c httpd-2.4.7.new/server/listen.c --- httpd-2.4.7/server/listen.c 2012-12-12 09:19:54.000000000 -0500 +++ httpd-2.4.7.new/server/listen.c 2013-12-17 10:33:01.124993652 -0500 @@ -34,6 +34,10 @@ AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL; +AP_DECLARE_DATA ap_listen_rec **mpm_listen = NULL; +AP_DECLARE_DATA int flag = 1; +AP_DECLARE_DATA int num_buckets = 1; + static ap_listen_rec *old_listeners; static int ap_listenbacklog; static int send_buffer_size; @@ -131,21 +135,34 @@ ap_sock_disable_nagle(s); #endif - if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) - "make_sock: could not bind to address %pI", +#if HAVE_SO_REUSEPORT + if((stat = apr_socket_opt_set(s, APR_SO_REUSEPORT, one)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(09999) + "make_sock: for address %pI, apr_socket_opt_set: " + "(SO_REUSEPORT)", server->bind_addr); apr_socket_close(s); - return stat; + return stat; /*need to fix the APLOGNO */ } +#endif - if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) - "make_sock: unable to listen for connections " - "on address %pI", - server->bind_addr); - apr_socket_close(s); - return stat; + if (flag) { + if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) + "make_sock: could not bind to address %pI", + server->bind_addr); + apr_socket_close(s); + return stat; + } + + if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) + "make_sock: unable to listen for connections " + "on address %pI", + server->bind_addr); + apr_socket_close(s); + return stat; + } } #ifdef WIN32 @@ -170,8 +187,12 @@ #endif server->sd = s; - server->active = 1; - + if (flag) { + server->active = 1; + } + else { + server->active = 0; + } server->accept_func = NULL; return APR_SUCCESS; @@ -233,6 +254,87 @@ } } +static ap_listen_rec* ap_duplicate_listener(server_rec *s, apr_pool_t *p, + ap_listen_rec *lr) +{ + apr_status_t stat; + int use_nonblock = 0; + ap_listen_rec *duplr; + duplr = apr_palloc(p, sizeof(ap_listen_rec)); + duplr->slave = 0; + duplr->protocol = apr_pstrdup(p, lr->protocol); + apr_sockaddr_t *sa; + char *hostname; + apr_port_t port; + hostname = apr_pstrdup(p, lr->bind_addr->hostname); + port = lr->bind_addr->port; + apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p); + duplr->bind_addr = sa; + duplr->next = 0; + apr_socket_t *temps; + if ((stat = apr_socket_create(&temps, duplr->bind_addr->family, + SOCK_STREAM, 0, p)) != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(09999) + "ap_duplicate_socket: for address %pI, " + "cannot duplicate a new socket!", + duplr->bind_addr); /*need to fix the APLOGNO */ + return NULL; + } + duplr->sd = temps; + flag = 1; + stat = make_sock(p, duplr); +/* duplicate from open_listeners()*/ +#if AP_NONBLOCK_WHEN_MULTI_LISTEN + if ((stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, 1)) + != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(09999) + "unable to control socket non-blocking status"); + return NULL; + } /*need to fix the APLOGNO */ +#endif + return duplr; +} + +/* This function is added for the patch. This function duplicates + * open_listeners, alloc_listener() and re-call make_sock() for the + * duplicated listeners. In this function, the newly created sockets + * will bind and listen*/ +AP_DECLARE(apr_status_t) ap_post_config_listeners(server_rec *s, apr_pool_t *p, + int num_buckets) { + mpm_listen = apr_palloc(p, sizeof(ap_listen_rec*) * num_buckets); + int i; + ap_listen_rec *lr; +/* duplicate from alloc_listener() for the additional listen record*/ +#ifndef HAVE_SO_REUSEPORT + lr = ap_listeners; +#endif + for (i = 0; i < num_buckets; i++) { +#ifdef HAVE_SO_REUSEPORT + ap_listen_rec *templr; + lr = ap_listeners; + ap_listen_rec *last = NULL; + while (lr) { + templr = ap_duplicate_listener(s, p, lr); + + ap_apply_accept_filter(p, templr, s); + + if (last == NULL) { + mpm_listen[i] = last = templr; + } + else { + last->next = templr; + last = templr; + } + lr = lr->next; + } +#else + mpm_listen[i] = ap_duplicate_listener(s, p, lr); + lr = lr->next; +#endif + } + return APR_SUCCESS; +} + static apr_status_t close_listeners_on_exec(void *v) { ap_close_listeners(); @@ -585,11 +687,18 @@ AP_DECLARE_NONSTD(void) ap_close_listeners(void) { ap_listen_rec *lr; + int i; for (lr = ap_listeners; lr; lr = lr->next) { apr_socket_close(lr->sd); lr->active = 0; } + 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_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *slave) { diff -ru httpd-2.4.7/server/mpm/prefork/prefork.c httpd-2.4.7.new/server/mpm/prefork/prefork.c --- httpd-2.4.7/server/mpm/prefork/prefork.c 2012-10-03 06:03:32.000000000 -0400 +++ httpd-2.4.7.new/server/mpm/prefork/prefork.c 2013-12-17 09:12:46.148927507 -0500 @@ -86,7 +86,7 @@ /* config globals */ -static apr_proc_mutex_t *accept_mutex; +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; @@ -94,6 +94,7 @@ static int server_limit = 0; static int mpm_state = AP_MPMQ_STARTING; static ap_pod_t *pod; +int *bucket; /* bucket array for the httpd child processes */ /* data retained by prefork across load/unload of the module * allocated on first call to pre-config hook; located on @@ -117,7 +118,7 @@ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by * without the need to spawn. */ - int idle_spawn_rate; + int idle_spawn_rate[1025]; #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif @@ -227,9 +228,9 @@ exit(code); } -static void accept_mutex_on(void) +static void accept_mutex_on(apr_proc_mutex_t *mutex) { - apr_status_t rv = apr_proc_mutex_lock(accept_mutex); + apr_status_t rv = apr_proc_mutex_lock(mutex); if (rv != APR_SUCCESS) { const char *msg = "couldn't grab the accept mutex"; @@ -245,9 +246,9 @@ } } -static void accept_mutex_off(void) +static void accept_mutex_off(apr_proc_mutex_t *mutex) { - apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); + apr_status_t rv = apr_proc_mutex_unlock(mutex); if (rv != APR_SUCCESS) { const char *msg = "couldn't release the accept mutex"; @@ -271,10 +272,10 @@ * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT * when it's safe in the single Listen case. */ -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0) -#else +#if !defined (SINGLE_LISTEN_UNSERIALIZED_ACCEPT) || defined (HAVE_SO_REUSEPORT) #define SAFE_ACCEPT(stmt) do {stmt;} while(0) +#else +#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0) #endif static int prefork_query(int query_code, int *result, apr_status_t *rv) @@ -523,8 +524,8 @@ /* needs to be done before we switch UIDs so we have permissions */ ap_reopen_scoreboard(pchild, NULL, 0); - lockfile = apr_proc_mutex_lockfile(accept_mutex); - status = apr_proc_mutex_child_init(&accept_mutex, + lockfile = apr_proc_mutex_lockfile(accept_mutex[bucket[my_child_num]]); + status = apr_proc_mutex_child_init(&accept_mutex[bucket[my_child_num]], lockfile, pchild); if (status != APR_SUCCESS) { @@ -532,7 +533,7 @@ "Couldn't initialize cross-process lock in child " "(%s) (%s)", lockfile ? lockfile : "none", - apr_proc_mutex_name(accept_mutex)); + apr_proc_mutex_name(accept_mutex[bucket[my_child_num]])); clean_child_exit(APEXIT_CHILDFATAL); } @@ -554,7 +555,7 @@ clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */ } - for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) { + for (lr = mpm_listen[bucket[my_child_num]], i = num_listensocks; i--; lr = lr->next) { apr_pollfd_t pfd = { 0 }; pfd.desc_type = APR_POLL_SOCKET; @@ -608,11 +609,11 @@ */ /* Lock around "accept", if necessary */ - SAFE_ACCEPT(accept_mutex_on()); + SAFE_ACCEPT(accept_mutex_on(accept_mutex[bucket[my_child_num]])); if (num_listensocks == 1) { /* There is only one listener record, so refer to that one. */ - lr = ap_listeners; + lr = mpm_listen[bucket[my_child_num]]; } else { /* multiple listening sockets - need to poll */ @@ -625,7 +626,7 @@ */ if (die_now /* in graceful stop/restart */ || (one_process && shutdown_pending)) { - SAFE_ACCEPT(accept_mutex_off()); + SAFE_ACCEPT(accept_mutex_off(accept_mutex[bucket[my_child_num]])); clean_child_exit(0); } @@ -647,7 +648,7 @@ */ ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(00158) "apr_pollset_poll: (listen)"); - SAFE_ACCEPT(accept_mutex_off()); + SAFE_ACCEPT(accept_mutex_off(accept_mutex[bucket[my_child_num]])); clean_child_exit(APEXIT_CHILDSICK); } @@ -681,7 +682,7 @@ */ status = lr->accept_func(&csd, lr, ptrans); - SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ + SAFE_ACCEPT(accept_mutex_off(accept_mutex[bucket[my_child_num]])); /* unlock after "accept" */ if (status == APR_EGENERAL) { /* resource shortage or should-not-occur occured */ @@ -750,7 +751,6 @@ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, (request_rec *) NULL); - #ifdef _OSD_POSIX /* BS2000 requires a "special" version of fork() before a setuid() call */ if ((pid = os_fork(ap_unixd_config.user_name)) == -1) { @@ -815,20 +815,23 @@ if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { continue; } + bucket[i] = i % num_buckets; if (make_child(ap_server_conf, i) < 0) { break; } --number_to_start; } } - -static void perform_idle_server_maintenance(apr_pool_t *p) +/* +* patch: execute idle server maintenance on each child group. +*/ +static void perform_idle_server_maintenance(apr_pool_t *p, int my_bucket) { int i; int idle_count; worker_score *ws; int free_length; - int free_slots[MAX_SPAWN_RATE]; + int free_slots[MAX_SPAWN_RATE/num_buckets]; int last_non_dead; int total_non_dead; @@ -842,13 +845,13 @@ for (i = 0; i < ap_daemons_limit; ++i) { int status; - if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate) + if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate[my_bucket]) break; ws = &ap_scoreboard_image->servers[i][0]; status = ws->status; if (status == SERVER_DEAD) { /* try to keep children numbers as low as possible */ - if (free_length < retained->idle_spawn_rate) { + if (free_length < retained->idle_spawn_rate[my_bucket]) { free_slots[free_length] = i; ++free_length; } @@ -860,7 +863,7 @@ * So we hopefully won't need to fork more if we count it. * This depends on the ordering of SERVER_READY and SERVER_STARTING. */ - if (status <= SERVER_READY) { + if ((status <= SERVER_READY) && (bucket[i] == my_bucket)) { ++ idle_count; } @@ -869,15 +872,15 @@ } } retained->max_daemons_limit = last_non_dead + 1; - if (idle_count > ap_daemons_max_free) { + if (idle_count > ap_daemons_max_free/num_buckets) { /* kill off one child... we use the pod because that'll cause it to * shut down gracefully, in case it happened to pick up a request * while we were counting */ ap_mpm_pod_signal(pod); - retained->idle_spawn_rate = 1; + retained->idle_spawn_rate[my_bucket] = 1; } - else if (idle_count < ap_daemons_min_free) { + else if (idle_count < ap_daemons_min_free/num_buckets) { /* terminate the free list */ if (free_length == 0) { /* only report this condition once */ @@ -887,18 +890,19 @@ " raising the MaxRequestWorkers setting"); retained->maxclients_reported = 1; } - retained->idle_spawn_rate = 1; + retained->idle_spawn_rate[my_bucket] = 1; } else { - if (retained->idle_spawn_rate >= 8) { + if (retained->idle_spawn_rate[my_bucket] >= 8) { ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00162) "server seems busy, (you may need " "to increase StartServers, or Min/MaxSpareServers), " "spawning %d children, there are %d idle, and " - "%d total children", retained->idle_spawn_rate, + "%d total children", retained->idle_spawn_rate[my_bucket], idle_count, total_non_dead); } for (i = 0; i < free_length; ++i) { + bucket[free_slots[i]] = my_bucket; make_child(ap_server_conf, free_slots[i]); } /* the next time around we want to spawn twice as many if this @@ -907,13 +911,13 @@ if (retained->hold_off_on_exponential_spawning) { --retained->hold_off_on_exponential_spawning; } - else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) { - retained->idle_spawn_rate *= 2; + else if (retained->idle_spawn_rate[my_bucket] < MAX_SPAWN_RATE/num_buckets) { + retained->idle_spawn_rate[my_bucket] *= 2; } } } else { - retained->idle_spawn_rate = 1; + retained->idle_spawn_rate[my_bucket] = 1; } } @@ -926,15 +930,20 @@ 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 */ - rv = ap_proc_mutex_create(&accept_mutex, NULL, AP_ACCEPT_MUTEX_TYPE, NULL, - s, _pconf, 0); - if (rv != APR_SUCCESS) { - mpm_state = AP_MPMQ_STOPPING; - return DONE; + bucket = apr_palloc(_pconf, sizeof(int) * ap_daemons_limit); + /* 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 DONE; + } } if (!retained->is_graceful) { @@ -953,12 +962,13 @@ if (one_process) { AP_MONCONTROL(1); + bucket[0] = 0; make_child(ap_server_conf, 0); /* NOTREACHED */ } else { - if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */ - ap_daemons_max_free = ap_daemons_min_free + 1; + if (ap_daemons_max_free < ap_daemons_min_free + num_buckets) /* Don't thrash... */ + ap_daemons_max_free = ap_daemons_min_free + num_buckets; /* If we're doing a graceful_restart then we're going to see a lot * of children exiting immediately when we get into the main loop @@ -991,7 +1001,7 @@ ap_log_command_line(plog, 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), + apr_proc_mutex_name(accept_mutex[0]), apr_proc_mutex_defname()); mpm_state = AP_MPMQ_RUNNING; @@ -1041,7 +1051,7 @@ /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc) * cut the fork rate to the minimum */ - retained->idle_spawn_rate = 1; + retained->idle_spawn_rate[bucket[child_slot]] = 1; } else if (remaining_children_to_start && child_slot < ap_daemons_limit) { @@ -1086,8 +1096,9 @@ */ continue; } - - perform_idle_server_maintenance(pconf); + for (i = 0; i < num_buckets; i++) { + perform_idle_server_maintenance(pconf, i); + } } } /* one_process */ @@ -1248,12 +1259,22 @@ level_flags |= APLOG_STARTUP; } + flag = 0; /* do not bind and listen to ap_listeners */ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0, (startup ? NULL : s), "no listening sockets available, shutting down"); return DONE; } +#ifdef HAVE_SO_REUSEPORT + num_buckets = 4; +#else + if (num_listensocks > 1) { + num_buckets = num_listensocks; + num_listensocks = 1; /* partition the listener into different bucket */ + } +#endif + ap_post_config_listeners(ap_server_conf, pconf, num_buckets); if ((rv = ap_mpm_pod_open(pconf, &pod))) { ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, @@ -1292,7 +1313,10 @@ if (!retained) { retained = ap_retained_data_create(userdata_key, sizeof(*retained)); retained->max_daemons_limit = -1; - retained->idle_spawn_rate = 1; + int i; + for (i = 0; i < 1025; i++) { + retained->idle_spawn_rate[i] = 1; + } } ++retained->module_loads; if (retained->module_loads == 2) { diff -ru httpd-2.4.7/server/mpm_unix.c httpd-2.4.7.new/server/mpm_unix.c --- httpd-2.4.7/server/mpm_unix.c 2013-11-16 14:24:53.000000000 -0500 +++ httpd-2.4.7.new/server/mpm_unix.c 2013-12-17 11:21:28.941978245 -0500 @@ -607,7 +607,7 @@ * permits the MPM to skip the poll when there is only one listening * socket, because it provides a alternate way to unblock an accept() * when the pod is used. */ -static apr_status_t dummy_connection(ap_pod_t *pod) +static apr_status_t dummy_connection(ap_pod_t *pod, ap_listen_rec *lr) { const char *data; apr_status_t rv; @@ -626,12 +626,12 @@ * 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). */ - lp = ap_listeners; + lp = lr; while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) { lp = lp->next; } if (!lp) { - lp = ap_listeners; + lp = lr; } rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p); @@ -715,18 +715,26 @@ AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod) { apr_status_t rv; + int i; rv = pod_signal_internal(pod); if (rv != APR_SUCCESS) { return rv; } - - return dummy_connection(pod); + + for (i = 0; i < num_buckets; i++) { + rv = dummy_connection(pod, mpm_listen[i]); + if (rv != APR_SUCCESS) { + return rv; + } + } + return APR_SUCCESS; } void ap_mpm_pod_killpg(ap_pod_t *pod, int num) { int i; + int j; apr_status_t rv = APR_SUCCESS; /* we don't write anything to the pod here... we assume @@ -742,8 +750,11 @@ * readers stranded (a number of them could be tied up for * a while serving time-consuming requests) */ + for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = dummy_connection(pod); + for (j = 0; j < num_buckets; j++) { + rv = dummy_connection(pod, mpm_listen[j]); + } } }