View | Details | Raw Unified | Return to bug 55897
Collapse All | Expand All

(-)httpd-2.4.7/configure (+19 lines)
Lines 6354-6360 Link Here
6354
6354
6355
  APACHE_VAR_SUBST="$APACHE_VAR_SUBST LTCFLAGS"
6355
  APACHE_VAR_SUBST="$APACHE_VAR_SUBST LTCFLAGS"
6356
6356
6357
case $host in
6358
    *-linux-*)
6359
        case `uname -r` in
6360
        # SO_REUSEPORT feature is only being enabled in the Linux kernel newer than 3.9
6361
        [0-2].* | 3.[0-8].*)
6362
            ;;
6363
        * )
6364
    test "x$silent" != "xyes" && echo "  forcing HAVE_SO_REUSEPORT to \"1\""
6365
    HAVE_SO_REUSEPORT="1"
6357
6366
6367
            ;;
6368
        esac
6369
        ;;
6370
esac
6358
6371
6359
case $host in
6372
case $host in
6360
  *-apple-aux3*)
6373
  *-apple-aux3*)
Lines 32191-32196 Link Here
32191
32204
32192
fi
32205
fi
32193
32206
32207
if test "$HAVE_SO_REUSEPORT" = "1"; then
32208
32209
$as_echo "#define HAVE_SO_REUSEPORT 1" >>confdefs.h
32210
32211
fi
32212
32194
if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then
32213
if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then
32195
32214
32196
$as_echo "#define AP_NONBLOCK_WHEN_MULTI_LISTEN 1" >>confdefs.h
32215
$as_echo "#define AP_NONBLOCK_WHEN_MULTI_LISTEN 1" >>confdefs.h
(-)httpd-2.4.7/configure.in (+18 lines)
Lines 307-312 Link Here
307
APACHE_SUBST(LTCFLAGS)
307
APACHE_SUBST(LTCFLAGS)
308
308
309
case $host in
309
case $host in
310
  *-linux-*)
311
      case `uname -r` in
312
        #SO_REUSEPORT is only being enabled in Linux kernel 3.9 and newer
313
        [[0-2]].* | 3.[[0-8]].* )
314
            ;;
315
        * )
316
            APR_SETVAR(HAVE_SO_REUSEPORT, [1])
317
            ;;
318
     esac
319
     ;;
320
esac
321
322
case $host in
310
  *-apple-aux3*)
323
  *-apple-aux3*)
311
      APR_SETVAR(SINGLE_LISTEN_UNSERIALIZED_ACCEPT, [1])
324
      APR_SETVAR(SINGLE_LISTEN_UNSERIALIZED_ACCEPT, [1])
312
      ;;
325
      ;;
Lines 761-766 Link Here
761
              [This platform doesn't suffer from the thundering herd problem])
774
              [This platform doesn't suffer from the thundering herd problem])
762
fi
775
fi
763
776
777
if test "$HAVE_SO_REUSEPORT" = "1"; then
778
    AC_DEFINE(HAVE_SO_REUSEPORT, 1,
779
              [This platform has SO_REUSEPORT feature enabled])
780
fi
781
764
if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then
782
if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then
765
    AC_DEFINE(AP_NONBLOCK_WHEN_MULTI_LISTEN, 1, 
783
    AC_DEFINE(AP_NONBLOCK_WHEN_MULTI_LISTEN, 1, 
766
              [Listening sockets are non-blocking when there are more than 1])
784
              [Listening sockets are non-blocking when there are more than 1])
(-)httpd-2.4.7/include/ap_config_auto.h.in (+3 lines)
Lines 229-234 Link Here
229
/* This platform doesn't suffer from the thundering herd problem */
229
/* This platform doesn't suffer from the thundering herd problem */
230
#undef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
230
#undef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
231
231
232
/* Define to 1 if you have SO_REUSEPORT enabled in your kernel. Linux kernel newer than 3.9 has this enabled */
233
#undef HAVE_SO_REUSEPORT
234
232
/* Define to 1 if you have the ANSI C header files. */
235
/* Define to 1 if you have the ANSI C header files. */
233
#undef STDC_HEADERS
236
#undef STDC_HEADERS
234
237
(-)httpd-2.4.7/include/ap_listen.h (+18 lines)
Lines 79-84 Link Here
79
AP_DECLARE_DATA extern ap_listen_rec *ap_listeners;
79
AP_DECLARE_DATA extern ap_listen_rec *ap_listeners;
80
80
81
/**
81
/**
82
 ** The listener array defined for the patch.
83
 ** */
84
AP_DECLARE_DATA extern ap_listen_rec **mpm_listen;
85
86
AP_DECLARE_DATA extern int flag;
87
88
AP_DECLARE_DATA extern int num_buckets;
89
90
/**
82
 * Setup all of the defaults for the listener list
91
 * Setup all of the defaults for the listener list
83
 */
92
 */
84
AP_DECLARE(void) ap_listen_pre_config(void);
93
AP_DECLARE(void) ap_listen_pre_config(void);
Lines 91-96 Link Here
91
 */
100
 */
92
AP_DECLARE(int) ap_setup_listeners(server_rec *s);
101
AP_DECLARE(int) ap_setup_listeners(server_rec *s);
93
102
103
/**This function is added for the patch. It creates sockets for the mpm_listen
104
 * array, executes the listen and bind on the sockets, and set the sockets to
105
 * be active. If HAVE_SO_REUSEPORT is enabled, It will duplicate ap_listeners.
106
 * @param s The global server_rec
107
 * @param p The config pool
108
 * @param num_buckets The total number of listener buckets.
109
 * */
110
AP_DECLARE(apr_status_t) ap_post_config_listeners(server_rec *s, apr_pool_t *p, int num_buckets);
111
94
/**
112
/**
95
 * Loop through the global ap_listen_rec list and close each of the sockets.
113
 * Loop through the global ap_listen_rec list and close each of the sockets.
96
 */
114
 */
(-)httpd-2.4.7/include/mpm_common.h (-2 / +4 lines)
Lines 267-282 Link Here
267
 * Write data to the pipe-of-death, signalling that one child process
267
 * Write data to the pipe-of-death, signalling that one child process
268
 * should die.
268
 * should die.
269
 * @param pod the pipe-of-death to write to.
269
 * @param pod the pipe-of-death to write to.
270
 * @param my_bucket the bucket that holds the dying child process
270
 */
271
 */
271
AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod);
272
AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int my_bucket);
272
273
273
/**
274
/**
274
 * Write data to the pipe-of-death, signalling that all child process
275
 * Write data to the pipe-of-death, signalling that all child process
275
 * should die.
276
 * should die.
276
 * @param pod The pipe-of-death to write to.
277
 * @param pod The pipe-of-death to write to.
278
 * @param my_bucket the bucket that holds the dying child process
277
 * @param num The number of child processes to kill
279
 * @param num The number of child processes to kill
278
 */
280
 */
279
AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num);
281
AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int my_bucket, int num);
280
282
281
#define AP_MPM_PODX_RESTART_CHAR '$'
283
#define AP_MPM_PODX_RESTART_CHAR '$'
282
#define AP_MPM_PODX_GRACEFUL_CHAR '!'
284
#define AP_MPM_PODX_GRACEFUL_CHAR '!'
(-)httpd-2.4.7/server/listen.c (-18 / +117 lines)
Lines 34-39 Link Here
34
34
35
AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL;
35
AP_DECLARE_DATA ap_listen_rec *ap_listeners = NULL;
36
36
37
AP_DECLARE_DATA ap_listen_rec **mpm_listen = NULL;
38
AP_DECLARE_DATA int flag = 1;
39
AP_DECLARE_DATA int num_buckets = 1;
40
37
static ap_listen_rec *old_listeners;
41
static ap_listen_rec *old_listeners;
38
static int ap_listenbacklog;
42
static int ap_listenbacklog;
39
static int send_buffer_size;
43
static int send_buffer_size;
Lines 131-151 Link Here
131
    ap_sock_disable_nagle(s);
135
    ap_sock_disable_nagle(s);
132
#endif
136
#endif
133
137
134
    if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
138
#if HAVE_SO_REUSEPORT
135
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
139
#ifndef SO_REUSEPORT
136
                      "make_sock: could not bind to address %pI",
140
#define SO_REUSEPORT 15
137
                      server->bind_addr);
141
    int thesock;
138
        apr_socket_close(s);
142
    apr_os_sock_get(&thesock, s);
139
        return stat;
143
    setsockopt(thesock, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(int));
140
    }
144
#endif
145
#endif
141
146
142
    if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
147
    if (flag) {
143
        ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
148
        if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) {
144
                      "make_sock: unable to listen for connections "
149
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072)
145
                      "on address %pI",
150
                          "make_sock: could not bind to address %pI",
146
                      server->bind_addr);
151
                          server->bind_addr);
147
        apr_socket_close(s);
152
            apr_socket_close(s);
148
        return stat;
153
            return stat;
154
        }
155
156
        if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) {
157
            ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073)
158
                          "make_sock: unable to listen for connections "
159
                          "on address %pI",
160
                          server->bind_addr);
161
            apr_socket_close(s);
162
            return stat;
163
        }
149
    }
164
    }
150
165
151
#ifdef WIN32
166
#ifdef WIN32
Lines 170-176 Link Here
170
#endif
185
#endif
171
186
172
    server->sd = s;
187
    server->sd = s;
173
    server->active = 1;
188
    server->active = flag;
174
189
175
    server->accept_func = NULL;
190
    server->accept_func = NULL;
176
191
Lines 233-238 Link Here
233
    }
248
    }
234
}
249
}
235
250
251
static ap_listen_rec* ap_duplicate_listener(apr_pool_t *p, ap_listen_rec *lr)
252
{
253
    apr_status_t stat;
254
    int use_nonblock = 0;
255
    ap_listen_rec *duplr;
256
    duplr  = apr_palloc(p, sizeof(ap_listen_rec));
257
    duplr->slave = 0;
258
    duplr->protocol = apr_pstrdup(p, lr->protocol);
259
    apr_sockaddr_t *sa;
260
    char *hostname;
261
    apr_port_t port;
262
    hostname = apr_pstrdup(p, lr->bind_addr->hostname);
263
    port = lr->bind_addr->port;
264
    apr_sockaddr_info_get(&sa, hostname, APR_UNSPEC, port, 0, p);
265
    duplr->bind_addr = sa;
266
    duplr->next = 0;
267
    apr_socket_t *temps;
268
    if ((stat = apr_socket_create(&temps, duplr->bind_addr->family,
269
                                  SOCK_STREAM, 0, p)) != APR_SUCCESS) {
270
        ap_log_perror(APLOG_MARK, APLOG_CRIT, 0, p, APLOGNO(09999)
271
                      "ap_duplicate_socket: for address %pI, "
272
                      "cannot duplicate a new socket!",
273
                      duplr->bind_addr); /*need to fix the APLOGNO */
274
        return NULL;
275
    }
276
    duplr->sd = temps;
277
    flag = 1;
278
    stat = make_sock(p, duplr);
279
/* duplicate from open_listeners()*/
280
#if AP_NONBLOCK_WHEN_MULTI_LISTEN
281
    use_nonblock = (ap_listeners && ap_listeners->next);
282
    if ((stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock))
283
        != APR_SUCCESS) {
284
        ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(09999)
285
                      "unable to control socket non-blocking status");
286
        return NULL;
287
    }  /*need to fix the APLOGNO */
288
#endif
289
    return duplr;
290
}
291
292
/* This function is added for the patch. This function duplicates 
293
 * open_listeners, alloc_listener() and re-call make_sock() for the 
294
 * duplicated listeners. In this function, the newly created sockets
295
 * will bind and listen*/
296
AP_DECLARE(apr_status_t) ap_post_config_listeners(server_rec *s, apr_pool_t *p,
297
                                                  int num_buckets) {
298
    mpm_listen = apr_palloc(p, sizeof(ap_listen_rec*) * num_buckets);
299
    int i;
300
    ap_listen_rec *lr;
301
/* duplicate from alloc_listener() for the additional listen record*/
302
#ifndef HAVE_SO_REUSEPORT
303
    lr = ap_listeners;
304
#endif
305
    for (i = 0; i < num_buckets; i++) {
306
#ifdef HAVE_SO_REUSEPORT
307
        ap_listen_rec *templr;
308
        lr = ap_listeners;
309
        ap_listen_rec *last = NULL;
310
        while (lr) {
311
            templr = ap_duplicate_listener(p, lr);    
312
         
313
            ap_apply_accept_filter(p, templr, s);
314
            
315
            if (last == NULL) {
316
                mpm_listen[i] = last = templr;
317
            }
318
            else {
319
                last->next = templr;
320
                last = templr;
321
            }
322
            lr = lr->next;
323
        }
324
#else
325
        mpm_listen[i] = ap_duplicate_listener(p, lr);
326
        lr = lr->next;
327
#endif
328
    }
329
    return APR_SUCCESS;
330
}
331
236
static apr_status_t close_listeners_on_exec(void *v)
332
static apr_status_t close_listeners_on_exec(void *v)
237
{
333
{
238
    ap_close_listeners();
334
    ap_close_listeners();
Lines 585-594 Link Here
585
AP_DECLARE_NONSTD(void) ap_close_listeners(void)
681
AP_DECLARE_NONSTD(void) ap_close_listeners(void)
586
{
682
{
587
    ap_listen_rec *lr;
683
    ap_listen_rec *lr;
684
    int i;
588
685
589
    for (lr = ap_listeners; lr; lr = lr->next) {
686
    for (i = 0; i < num_buckets; i++) {
590
        apr_socket_close(lr->sd);
687
        for (lr = mpm_listen[i]; lr; lr = lr->next) {
591
        lr->active = 0;
688
            apr_socket_close(lr->sd);
689
            lr->active = 0;
690
        }
592
    }
691
    }
593
}
692
}
594
AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *slave)
693
AP_DECLARE_NONSTD(int) ap_close_selected_listeners(ap_slave_t *slave)
(-)httpd-2.4.7/server/mpm/prefork/prefork.c (-54 / +117 lines)
Lines 48-53 Link Here
48
#include "ap_mmn.h"
48
#include "ap_mmn.h"
49
#include "apr_poll.h"
49
#include "apr_poll.h"
50
50
51
#include <stdlib.h>
52
51
#ifdef HAVE_TIME_H
53
#ifdef HAVE_TIME_H
52
#include <time.h>
54
#include <time.h>
53
#endif
55
#endif
Lines 86-99 Link Here
86
88
87
/* config globals */
89
/* config globals */
88
90
89
static apr_proc_mutex_t *accept_mutex;
91
static apr_proc_mutex_t **accept_mutex;
90
static int ap_daemons_to_start=0;
92
static int ap_daemons_to_start=0;
91
static int ap_daemons_min_free=0;
93
static int ap_daemons_min_free=0;
92
static int ap_daemons_max_free=0;
94
static int ap_daemons_max_free=0;
93
static int ap_daemons_limit=0;      /* MaxRequestWorkers */
95
static int ap_daemons_limit=0;      /* MaxRequestWorkers */
94
static int server_limit = 0;
96
static int server_limit = 0;
95
static int mpm_state = AP_MPMQ_STARTING;
97
static int mpm_state = AP_MPMQ_STARTING;
96
static ap_pod_t *pod;
98
static ap_pod_t **pod;
99
static ap_pod_t *child_pod;
100
static apr_proc_mutex_t *child_mutex;
101
ap_listen_rec *child_listen;
102
int *bucket;	/* bucket array for the httpd child processes */
97
103
98
/* data retained by prefork across load/unload of the module
104
/* data retained by prefork across load/unload of the module
99
 * allocated on first call to pre-config hook; located on
105
 * allocated on first call to pre-config hook; located on
Lines 117-123 Link Here
117
     * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
123
     * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
118
     * without the need to spawn.
124
     * without the need to spawn.
119
     */
125
     */
120
    int idle_spawn_rate;
126
    int idle_spawn_rate[1025];
121
#ifndef MAX_SPAWN_RATE
127
#ifndef MAX_SPAWN_RATE
122
#define MAX_SPAWN_RATE  (32)
128
#define MAX_SPAWN_RATE  (32)
123
#endif
129
#endif
Lines 222-235 Link Here
222
        prefork_note_child_killed(/* slot */ 0, 0, 0);
228
        prefork_note_child_killed(/* slot */ 0, 0, 0);
223
    }
229
    }
224
230
225
    ap_mpm_pod_close(pod);
231
    ap_mpm_pod_close(child_pod);
226
    chdir_for_gprof();
232
    chdir_for_gprof();
227
    exit(code);
233
    exit(code);
228
}
234
}
229
235
230
static void accept_mutex_on(void)
236
static void accept_mutex_on(void)
231
{
237
{
232
    apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
238
    apr_status_t rv = apr_proc_mutex_lock(child_mutex);
233
    if (rv != APR_SUCCESS) {
239
    if (rv != APR_SUCCESS) {
234
        const char *msg = "couldn't grab the accept mutex";
240
        const char *msg = "couldn't grab the accept mutex";
235
241
Lines 247-253 Link Here
247
253
248
static void accept_mutex_off(void)
254
static void accept_mutex_off(void)
249
{
255
{
250
    apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
256
    apr_status_t rv = apr_proc_mutex_unlock(child_mutex);
251
    if (rv != APR_SUCCESS) {
257
    if (rv != APR_SUCCESS) {
252
        const char *msg = "couldn't release the accept mutex";
258
        const char *msg = "couldn't release the accept mutex";
253
259
Lines 272-282 Link Here
272
 * when it's safe in the single Listen case.
278
 * when it's safe in the single Listen case.
273
 */
279
 */
274
#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
280
#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
275
#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
281
#define SAFE_ACCEPT(stmt) do {if (child_listen->next) {stmt;}} while(0)
276
#else
282
#else
277
#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
283
#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
278
#endif
284
#endif
279
280
static int prefork_query(int query_code, int *result, apr_status_t *rv)
285
static int prefork_query(int query_code, int *result, apr_status_t *rv)
281
{
286
{
282
    *rv = APR_SUCCESS;
287
    *rv = APR_SUCCESS;
Lines 521-530 Link Here
521
    apr_pool_create(&ptrans, pchild);
526
    apr_pool_create(&ptrans, pchild);
522
    apr_pool_tag(ptrans, "transaction");
527
    apr_pool_tag(ptrans, "transaction");
523
528
524
    /* needs to be done before we switch UIDs so we have permissions */
529
/* close unused listeners and pods */
530
    for (i = 0; i < num_buckets; i++) {
531
        if (i != bucket[my_child_num]) {
532
            lr = mpm_listen[i];
533
            while(lr) {
534
                apr_socket_close(lr->sd);
535
                lr = lr->next;
536
            }
537
            mpm_listen[i]->active = 0;
538
            ap_mpm_pod_close(pod[i]);
539
        }
540
    }
541
542
/* needs to be done before we switch UIDs so we have permissions */
525
    ap_reopen_scoreboard(pchild, NULL, 0);
543
    ap_reopen_scoreboard(pchild, NULL, 0);
526
    lockfile = apr_proc_mutex_lockfile(accept_mutex);
544
    lockfile = apr_proc_mutex_lockfile(child_mutex);
527
    status = apr_proc_mutex_child_init(&accept_mutex,
545
    status = apr_proc_mutex_child_init(&child_mutex,
528
                                       lockfile,
546
                                       lockfile,
529
                                       pchild);
547
                                       pchild);
530
    if (status != APR_SUCCESS) {
548
    if (status != APR_SUCCESS) {
Lines 532-538 Link Here
532
                     "Couldn't initialize cross-process lock in child "
550
                     "Couldn't initialize cross-process lock in child "
533
                     "(%s) (%s)",
551
                     "(%s) (%s)",
534
                     lockfile ? lockfile : "none",
552
                     lockfile ? lockfile : "none",
535
                     apr_proc_mutex_name(accept_mutex));
553
                     apr_proc_mutex_name(child_mutex));
536
        clean_child_exit(APEXIT_CHILDFATAL);
554
        clean_child_exit(APEXIT_CHILDFATAL);
537
    }
555
    }
538
556
Lines 554-560 Link Here
554
        clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */
572
        clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */
555
    }
573
    }
556
574
557
    for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {
575
    for (lr = child_listen, i = num_listensocks; i--; lr = lr->next) {
558
        apr_pollfd_t pfd = { 0 };
576
        apr_pollfd_t pfd = { 0 };
559
577
560
        pfd.desc_type = APR_POLL_SOCKET;
578
        pfd.desc_type = APR_POLL_SOCKET;
Lines 612-618 Link Here
612
630
613
        if (num_listensocks == 1) {
631
        if (num_listensocks == 1) {
614
            /* There is only one listener record, so refer to that one. */
632
            /* There is only one listener record, so refer to that one. */
615
            lr = ap_listeners;
633
            lr = child_listen;
616
        }
634
        }
617
        else {
635
        else {
618
            /* multiple listening sockets - need to poll */
636
            /* multiple listening sockets - need to poll */
Lines 710-716 Link Here
710
         * while we were processing the connection or we are the lucky
728
         * while we were processing the connection or we are the lucky
711
         * idle server process that gets to die.
729
         * idle server process that gets to die.
712
         */
730
         */
713
        if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
731
        if (ap_mpm_pod_check(child_pod) == APR_SUCCESS) { /* selected as idle? */
714
            die_now = 1;
732
            die_now = 1;
715
        }
733
        }
716
        else if (retained->my_generation !=
734
        else if (retained->my_generation !=
Lines 750-756 Link Here
750
    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
768
    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
751
                                               (request_rec *) NULL);
769
                                               (request_rec *) NULL);
752
770
753
771
    child_listen = mpm_listen[bucket[slot]];
772
    child_mutex = accept_mutex[bucket[slot]];
773
    child_pod = pod[bucket[slot]];
754
#ifdef _OSD_POSIX
774
#ifdef _OSD_POSIX
755
    /* BS2000 requires a "special" version of fork() before a setuid() call */
775
    /* BS2000 requires a "special" version of fork() before a setuid() call */
756
    if ((pid = os_fork(ap_unixd_config.user_name)) == -1) {
776
    if ((pid = os_fork(ap_unixd_config.user_name)) == -1) {
Lines 815-834 Link Here
815
        if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
835
        if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
816
            continue;
836
            continue;
817
        }
837
        }
838
	bucket[i] = i % num_buckets;
818
        if (make_child(ap_server_conf, i) < 0) {
839
        if (make_child(ap_server_conf, i) < 0) {
819
            break;
840
            break;
820
        }
841
        }
821
        --number_to_start;
842
        --number_to_start;
822
    }
843
    }
823
}
844
}
824
845
/*
825
static void perform_idle_server_maintenance(apr_pool_t *p)
846
* patch: execute idle server maintenance on each child group.
847
*/
848
static void perform_idle_server_maintenance(apr_pool_t *p, int my_bucket)
826
{
849
{
827
    int i;
850
    int i;
828
    int idle_count;
851
    int idle_count;
829
    worker_score *ws;
852
    worker_score *ws;
830
    int free_length;
853
    int free_length;
831
    int free_slots[MAX_SPAWN_RATE];
854
    int free_slots[MAX_SPAWN_RATE/num_buckets];
832
    int last_non_dead;
855
    int last_non_dead;
833
    int total_non_dead;
856
    int total_non_dead;
834
857
Lines 842-854 Link Here
842
    for (i = 0; i < ap_daemons_limit; ++i) {
865
    for (i = 0; i < ap_daemons_limit; ++i) {
843
        int status;
866
        int status;
844
867
845
        if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate)
868
        if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate[my_bucket])
846
            break;
869
            break;
847
        ws = &ap_scoreboard_image->servers[i][0];
870
        ws = &ap_scoreboard_image->servers[i][0];
848
        status = ws->status;
871
        status = ws->status;
849
        if (status == SERVER_DEAD) {
872
        if (status == SERVER_DEAD) {
850
            /* try to keep children numbers as low as possible */
873
            /* try to keep children numbers as low as possible */
851
            if (free_length < retained->idle_spawn_rate) {
874
            if (free_length < retained->idle_spawn_rate[my_bucket]) {
852
                free_slots[free_length] = i;
875
                free_slots[free_length] = i;
853
                ++free_length;
876
                ++free_length;
854
            }
877
            }
Lines 860-866 Link Here
860
             * So we hopefully won't need to fork more if we count it.
883
             * So we hopefully won't need to fork more if we count it.
861
             * This depends on the ordering of SERVER_READY and SERVER_STARTING.
884
             * This depends on the ordering of SERVER_READY and SERVER_STARTING.
862
             */
885
             */
863
            if (status <= SERVER_READY) {
886
            if ((status <= SERVER_READY) && (bucket[i] == my_bucket)) {
864
                ++ idle_count;
887
                ++ idle_count;
865
            }
888
            }
866
889
Lines 869-883 Link Here
869
        }
892
        }
870
    }
893
    }
871
    retained->max_daemons_limit = last_non_dead + 1;
894
    retained->max_daemons_limit = last_non_dead + 1;
872
    if (idle_count > ap_daemons_max_free) {
895
    if (idle_count > ap_daemons_max_free/num_buckets) {
873
        /* kill off one child... we use the pod because that'll cause it to
896
        /* kill off one child... we use the pod because that'll cause it to
874
         * shut down gracefully, in case it happened to pick up a request
897
         * shut down gracefully, in case it happened to pick up a request
875
         * while we were counting
898
         * while we were counting
876
         */
899
         */
877
        ap_mpm_pod_signal(pod);
900
        ap_mpm_pod_signal(pod[my_bucket], my_bucket);
878
        retained->idle_spawn_rate = 1;
901
        retained->idle_spawn_rate[my_bucket] = 1;
879
    }
902
    }
880
    else if (idle_count < ap_daemons_min_free) {
903
    else if (idle_count < ap_daemons_min_free/num_buckets) {
881
        /* terminate the free list */
904
        /* terminate the free list */
882
        if (free_length == 0) {
905
        if (free_length == 0) {
883
            /* only report this condition once */
906
            /* only report this condition once */
Lines 887-904 Link Here
887
                            " raising the MaxRequestWorkers setting");
910
                            " raising the MaxRequestWorkers setting");
888
                retained->maxclients_reported = 1;
911
                retained->maxclients_reported = 1;
889
            }
912
            }
890
            retained->idle_spawn_rate = 1;
913
            retained->idle_spawn_rate[my_bucket] = 1;
891
        }
914
        }
892
        else {
915
        else {
893
            if (retained->idle_spawn_rate >= 8) {
916
            if (retained->idle_spawn_rate[my_bucket] >= 8) {
894
                ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00162)
917
                ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00162)
895
                    "server seems busy, (you may need "
918
                    "server seems busy, (you may need "
896
                    "to increase StartServers, or Min/MaxSpareServers), "
919
                    "to increase StartServers, or Min/MaxSpareServers), "
897
                    "spawning %d children, there are %d idle, and "
920
                    "spawning %d children, there are %d idle, and "
898
                    "%d total children", retained->idle_spawn_rate,
921
                    "%d total children", retained->idle_spawn_rate[my_bucket],
899
                    idle_count, total_non_dead);
922
                    idle_count, total_non_dead);
900
            }
923
            }
901
            for (i = 0; i < free_length; ++i) {
924
            for (i = 0; i < free_length; ++i) {
925
		bucket[free_slots[i]] = my_bucket; 
902
                make_child(ap_server_conf, free_slots[i]);
926
                make_child(ap_server_conf, free_slots[i]);
903
            }
927
            }
904
            /* the next time around we want to spawn twice as many if this
928
            /* the next time around we want to spawn twice as many if this
Lines 907-919 Link Here
907
            if (retained->hold_off_on_exponential_spawning) {
931
            if (retained->hold_off_on_exponential_spawning) {
908
                --retained->hold_off_on_exponential_spawning;
932
                --retained->hold_off_on_exponential_spawning;
909
            }
933
            }
910
            else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) {
934
            else if (retained->idle_spawn_rate[my_bucket] < MAX_SPAWN_RATE/num_buckets) {
911
                retained->idle_spawn_rate *= 2;
935
                retained->idle_spawn_rate[my_bucket] *= 2;
912
            }
936
            }
913
        }
937
        }
914
    }
938
    }
915
    else {
939
    else {
916
        retained->idle_spawn_rate = 1;
940
        retained->idle_spawn_rate[my_bucket] = 1;
917
    }
941
    }
918
}
942
}
919
943
Lines 926-940 Link Here
926
    int index;
950
    int index;
927
    int remaining_children_to_start;
951
    int remaining_children_to_start;
928
    apr_status_t rv;
952
    apr_status_t rv;
953
    int i;
929
954
930
    ap_log_pid(pconf, ap_pid_fname);
955
    ap_log_pid(pconf, ap_pid_fname);
931
956
932
    /* Initialize cross-process accept lock */
957
    bucket = apr_palloc(_pconf, sizeof(int) *  ap_daemons_limit);
933
    rv = ap_proc_mutex_create(&accept_mutex, NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
958
    /* Initialize cross-process accept lock for each bucket*/
934
                              s, _pconf, 0);
959
    accept_mutex = apr_palloc(_pconf, sizeof(apr_proc_mutex_t *) * num_buckets);
935
    if (rv != APR_SUCCESS) {
960
    for (i = 0; i < num_buckets; i++) {
936
        mpm_state = AP_MPMQ_STOPPING;
961
        rv = ap_proc_mutex_create(&accept_mutex[i], NULL, AP_ACCEPT_MUTEX_TYPE, NULL,
937
        return DONE;
962
                                  s, _pconf, 0);
963
        if (rv != APR_SUCCESS) {
964
            mpm_state = AP_MPMQ_STOPPING;
965
            return DONE;
966
        }
938
    }
967
    }
939
968
940
    if (!retained->is_graceful) {
969
    if (!retained->is_graceful) {
Lines 953-964 Link Here
953
982
954
    if (one_process) {
983
    if (one_process) {
955
        AP_MONCONTROL(1);
984
        AP_MONCONTROL(1);
985
	bucket[0] = 0;
956
        make_child(ap_server_conf, 0);
986
        make_child(ap_server_conf, 0);
957
        /* NOTREACHED */
987
        /* NOTREACHED */
958
    }
988
    }
959
    else {
989
    else {
960
    if (ap_daemons_max_free < ap_daemons_min_free + 1)  /* Don't thrash... */
990
    if (ap_daemons_max_free < ap_daemons_min_free + num_buckets)  /* Don't thrash... */
961
        ap_daemons_max_free = ap_daemons_min_free + 1;
991
        ap_daemons_max_free = ap_daemons_min_free + num_buckets;
962
992
963
    /* If we're doing a graceful_restart then we're going to see a lot
993
    /* If we're doing a graceful_restart then we're going to see a lot
964
     * of children exiting immediately when we get into the main loop
994
     * of children exiting immediately when we get into the main loop
Lines 991-997 Link Here
991
    ap_log_command_line(plog, s);
1021
    ap_log_command_line(plog, s);
992
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00165)
1022
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00165)
993
                "Accept mutex: %s (default: %s)",
1023
                "Accept mutex: %s (default: %s)",
994
                apr_proc_mutex_name(accept_mutex),
1024
                apr_proc_mutex_name(accept_mutex[0]),
995
                apr_proc_mutex_defname());
1025
                apr_proc_mutex_defname());
996
1026
997
    mpm_state = AP_MPMQ_RUNNING;
1027
    mpm_state = AP_MPMQ_RUNNING;
Lines 1041-1047 Link Here
1041
                    /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
1071
                    /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
1042
                     * cut the fork rate to the minimum
1072
                     * cut the fork rate to the minimum
1043
                     */
1073
                     */
1044
                    retained->idle_spawn_rate = 1;
1074
                    retained->idle_spawn_rate[bucket[child_slot]] = 1;
1045
                }
1075
                }
1046
                else if (remaining_children_to_start
1076
                else if (remaining_children_to_start
1047
                    && child_slot < ap_daemons_limit) {
1077
                    && child_slot < ap_daemons_limit) {
Lines 1086-1093 Link Here
1086
             */
1116
             */
1087
            continue;
1117
            continue;
1088
        }
1118
        }
1089
1119
        for (i = 0; i < num_buckets; i++) {
1090
        perform_idle_server_maintenance(pconf);
1120
            perform_idle_server_maintenance(pconf, i);
1121
        }
1091
    }
1122
    }
1092
    } /* one_process */
1123
    } /* one_process */
1093
1124
Lines 1122-1128 Link Here
1122
        ap_close_listeners();
1153
        ap_close_listeners();
1123
1154
1124
        /* kill off the idle ones */
1155
        /* kill off the idle ones */
1125
        ap_mpm_pod_killpg(pod, retained->max_daemons_limit);
1156
        for (i = 0; i < num_buckets; i++) {
1157
            ap_mpm_pod_killpg(pod[i], i, retained->max_daemons_limit);
1158
        }
1126
1159
1127
        /* Send SIGUSR1 to the active children */
1160
        /* Send SIGUSR1 to the active children */
1128
        active_children = 0;
1161
        active_children = 0;
Lines 1196-1203 Link Here
1196
                    "Graceful restart requested, doing restart");
1229
                    "Graceful restart requested, doing restart");
1197
1230
1198
        /* kill off the idle ones */
1231
        /* kill off the idle ones */
1199
        ap_mpm_pod_killpg(pod, retained->max_daemons_limit);
1232
        for (i = 0; i < num_buckets; i++) {
1200
1233
            ap_mpm_pod_killpg(pod[i], i, retained->max_daemons_limit);
1234
        }
1201
        /* This is mostly for debugging... so that we know what is still
1235
        /* This is mostly for debugging... so that we know what is still
1202
         * gracefully dealing with existing request.  This will break
1236
         * gracefully dealing with existing request.  This will break
1203
         * in a very nasty way if we ever have the scoreboard totally
1237
         * in a very nasty way if we ever have the scoreboard totally
Lines 1238-1243 Link Here
1238
{
1272
{
1239
    int startup = 0;
1273
    int startup = 0;
1240
    int level_flags = 0;
1274
    int level_flags = 0;
1275
    int i;
1276
    int num_of_cores = 0;
1277
    ap_listen_rec *lr;
1241
    apr_status_t rv;
1278
    apr_status_t rv;
1242
1279
1243
    pconf = p;
1280
    pconf = p;
Lines 1248-1265 Link Here
1248
        level_flags |= APLOG_STARTUP;
1285
        level_flags |= APLOG_STARTUP;
1249
    }
1286
    }
1250
1287
1288
    flag = 0; /* do not bind and listen to ap_listeners */
1251
    if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1289
    if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1252
        ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
1290
        ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0,
1253
                     (startup ? NULL : s),
1291
                     (startup ? NULL : s),
1254
                     "no listening sockets available, shutting down");
1292
                     "no listening sockets available, shutting down");
1255
        return DONE;
1293
        return DONE;
1256
    }
1294
    }
1257
1295
#ifdef HAVE_SO_REUSEPORT
1258
    if ((rv = ap_mpm_pod_open(pconf, &pod))) {
1296
    num_of_cores = sysconf(_SC_NPROCESSORS_ONLN);
1259
        ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
1297
    if (num_of_cores > 8) {
1260
                     (startup ? NULL : s),
1298
        num_buckets = sysconf(_SC_NPROCESSORS_ONLN)/8;
1261
                     "could not open pipe-of-death");
1299
    }
1262
        return DONE;
1300
    else {
1301
        num_buckets = 1;
1302
    }
1303
#else
1304
    if (num_listensocks > 1) {
1305
        num_buckets = num_listensocks;
1306
        num_listensocks = 1; /* partition the listener into different bucket */
1307
    }        
1308
#endif
1309
    ap_post_config_listeners(ap_server_conf, pconf, num_buckets);
1310
1311
    for (lr = ap_listeners; lr; lr=lr->next) {
1312
        apr_socket_close(lr->sd);
1313
    }
1314
1315
    pod = apr_palloc(pconf, sizeof(ap_pod_t *) * num_buckets);
1316
    for (i = 0; i < num_buckets; i++) {   
1317
        if ((rv = ap_mpm_pod_open(pconf, &pod[i]))) {
1318
            ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv,
1319
                         (startup ? NULL : s),
1320
                         "could not open pipe-of-death");
1321
            return DONE;
1322
        }
1263
    }
1323
    }
1264
    return OK;
1324
    return OK;
1265
}
1325
}
Lines 1292-1298 Link Here
1292
    if (!retained) {
1352
    if (!retained) {
1293
        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
1353
        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
1294
        retained->max_daemons_limit = -1;
1354
        retained->max_daemons_limit = -1;
1295
        retained->idle_spawn_rate = 1;
1355
        int i;
1356
        for (i = 0; i < 1025; i++) {
1357
            retained->idle_spawn_rate[i] = 1;
1358
        }
1296
    }
1359
    }
1297
    ++retained->module_loads;
1360
    ++retained->module_loads;
1298
    if (retained->module_loads == 2) {
1361
    if (retained->module_loads == 2) {
(-)httpd-2.4.7/server/mpm_unix.c (-8 / +10 lines)
Lines 607-613 Link Here
607
 * permits the MPM to skip the poll when there is only one listening
607
 * permits the MPM to skip the poll when there is only one listening
608
 * socket, because it provides a alternate way to unblock an accept()
608
 * socket, because it provides a alternate way to unblock an accept()
609
 * when the pod is used.  */
609
 * when the pod is used.  */
610
static apr_status_t dummy_connection(ap_pod_t *pod)
610
static apr_status_t dummy_connection(ap_pod_t *pod, int my_bucket)
611
{
611
{
612
    const char *data;
612
    const char *data;
613
    apr_status_t rv;
613
    apr_status_t rv;
Lines 626-637 Link Here
626
     * plain-HTTP, not SSL; using an SSL port would either be
626
     * plain-HTTP, not SSL; using an SSL port would either be
627
     * expensive to do correctly (performing a complete SSL handshake)
627
     * expensive to do correctly (performing a complete SSL handshake)
628
     * or cause log spam by doing incorrectly (simply sending EOF). */
628
     * or cause log spam by doing incorrectly (simply sending EOF). */
629
    lp = ap_listeners;
629
    lp = mpm_listen[my_bucket];
630
    while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
630
    while (lp && lp->protocol && strcasecmp(lp->protocol, "http") != 0) {
631
        lp = lp->next;
631
        lp = lp->next;
632
    }
632
    }
633
    if (!lp) {
633
    if (!lp) {
634
        lp = ap_listeners;
634
        lp = mpm_listen[my_bucket];
635
    }
635
    }
636
636
637
    rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
637
    rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p);
Lines 712-730 Link Here
712
    return rv;
712
    return rv;
713
}
713
}
714
714
715
AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod)
715
AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod, int my_bucket)
716
{
716
{
717
    apr_status_t rv;
717
    apr_status_t rv;
718
    int i;
718
719
719
    rv = pod_signal_internal(pod);
720
    rv = pod_signal_internal(pod);
720
    if (rv != APR_SUCCESS) {
721
    if (rv != APR_SUCCESS) {
721
        return rv;
722
        return rv;
722
    }
723
    }
723
724
    
724
    return dummy_connection(pod);
725
    return dummy_connection(pod, my_bucket);
725
}
726
}
726
727
727
void ap_mpm_pod_killpg(ap_pod_t *pod, int num)
728
void ap_mpm_pod_killpg(ap_pod_t *pod, int my_bucket, int num)
728
{
729
{
729
    int i;
730
    int i;
730
    apr_status_t rv = APR_SUCCESS;
731
    apr_status_t rv = APR_SUCCESS;
Lines 742-749 Link Here
742
     * readers stranded (a number of them could be tied up for
743
     * readers stranded (a number of them could be tied up for
743
     * a while serving time-consuming requests)
744
     * a while serving time-consuming requests)
744
     */
745
     */
746
745
    for (i = 0; i < num && rv == APR_SUCCESS; i++) {
747
    for (i = 0; i < num && rv == APR_SUCCESS; i++) {
746
        rv = dummy_connection(pod);
748
        rv = dummy_connection(pod, my_bucket);
747
    }
749
    }
748
}
750
}
749
751

Return to bug 55897