You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jeff Trawick <tr...@attglobal.net> on 2001/12/17 23:52:32 UTC

[PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

primary goal: 

be able to change equivalent of HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
without rebuilding the server

this is trivial to implement with the caveat that you don't allow the
admin to change it across a restart

currently, to allow the admin a lot of choices in how they split httpd
threads among processes, lots of unused shared memory is required;
this is much worse with a threaded MPM than it ever was with
prefork/Apache 1.3 because the amount of resource consumed is
threads*servers

what module code has to change with this patch?

  *If* module is being bad and isn't using the MPM query API, it must
  start doing it, because we don't allow modules to see equivalent of
  today's HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.  Hopefully third-party
  modules aren't doing that, because it is a problem that they must be
  rebuilt if somebody rebuilds/reconfigures httpd with different
  HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.

  *Otherwise* just a recompile is necessary to tell the C compiler to
  generate different code to walk through the scoreboard arrays.

benefits:

* we have an MPM query API; don't let the module bypass it

  the changes below to mod_status keep mod_status from needing a
  recompile if you're using an MPM that is stuck with hard limits and
  you have to rebuild the server

* an MPM needs power to implement softer HARD_THREAD_LIMIT /
  HARD_SERVER_LIMIT; since it is easy for the MPM to do that, don't
  stand in the MPM's way 

Of course I would want worker to be softer about these limits than it
is today but independent of that we should certainly allow somebody
to patch it or implement their own MPM that is nice in that regard.

(The main reason there is no patch here to make worker do that is
because there are issues to discuss about the user interface which
shouldn't cloud the issue of being able to do such a thing.)

One of the details of limiting HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
to being the MPM's concern is that the way to do
ap_update_child_status() needed to change.  Now, there is a handle to
scoreboard information in the conn_rec which most code uses.
Currently that handle just has access to the server and thread indices
but with a few lines of code this could also have pointers to the
appropriate status structures.  That didn't seem important for the
current goal.

Changes not here in the patch are necessary for MPMs other than worker
and prefork.  They need to get HARD_SERVER_LIMIT/HARD_THREAD_LIMIT out
of mpm_default.h and just refer to them locally.

Index: include/http_connection.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/http_connection.h,v
retrieving revision 1.47
diff -u -r1.47 http_connection.h
--- include/http_connection.h	2001/11/15 20:49:53	1.47
+++ include/http_connection.h	2001/12/17 22:27:57
@@ -127,10 +127,11 @@
  * @param csd The socket that has been accepted
  * @param conn_id A unique identifier for this connection.  The ID only
  *                needs to be unique at that time, not forever.
+ * @param sbh A handle to scoreboard information for this connection.
  * @return An allocated connection record or NULL.
  */
 AP_DECLARE_HOOK(conn_rec *, create_connection,
-                (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id))
+                (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id, void *sbh))
 
 #ifdef __cplusplus
 }
Index: include/httpd.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/httpd.h,v
retrieving revision 1.173
diff -u -r1.173 httpd.h
--- include/httpd.h	2001/12/13 19:13:23	1.173
+++ include/httpd.h	2001/12/17 22:27:58
@@ -982,6 +982,8 @@
     struct ap_filter_t *input_filters;
     /** A list of output filters to be used for this connection */
     struct ap_filter_t *output_filters;
+    /** handle to scoreboard information for this connection */
+    void *sbh;
 };
 
 /* Per-vhost config... */
Index: include/scoreboard.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/scoreboard.h,v
retrieving revision 1.33
diff -u -r1.33 scoreboard.h
--- include/scoreboard.h	2001/12/07 22:19:38	1.33
+++ include/scoreboard.h	2001/12/17 22:27:59
@@ -185,8 +185,8 @@
 
 typedef struct {
     global_score global;
-    process_score parent[HARD_SERVER_LIMIT];
-    worker_score servers[HARD_SERVER_LIMIT][HARD_THREAD_LIMIT];
+    process_score *parent;
+    worker_score **servers;
 } scoreboard;
 
 #define KEY_LENGTH 16
@@ -196,11 +196,12 @@
     char value[VALUE_LENGTH];
 } status_table_entry;
 
+/* XXX what should mod_ssl init use instead of this? */
 #define SCOREBOARD_SIZE		sizeof(scoreboard)
 
 AP_DECLARE(int) ap_exists_scoreboard_image(void);
 AP_DECLARE_NONSTD(void) ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e t);
-AP_DECLARE(void) ap_increment_counts(int child_num, int thread_num, request_rec *r);
+AP_DECLARE(void) ap_increment_counts(void *sbh, request_rec *r);
 
 apr_status_t ap_cleanup_scoreboard(void *d);
 
@@ -208,9 +209,14 @@
 
 void ap_sync_scoreboard_image(void);
 
+AP_DECLARE(void) ap_create_sb_handle(void **new_handle, apr_pool_t *p,
+                                     int child_num, int thread_num);
+    
 void update_scoreboard_global(void);
 AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid);
-AP_DECLARE(int) ap_update_child_status(int child_num, int thread_num, int status, request_rec *r);
+AP_DECLARE(int) ap_update_child_status(void *sbh, int status, request_rec *r);
+AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, int thread_num,
+                                                    int status, request_rec *r);
 void ap_time_process_request(int child_num, int thread_num, int status);
 AP_DECLARE(worker_score *) ap_get_servers_scoreboard(int x, int y);
 AP_DECLARE(process_score *) ap_get_parent_scoreboard(int x);
Index: modules/generators/mod_status.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_status.c,v
retrieving revision 1.49
diff -u -r1.49 mod_status.c
--- modules/generators/mod_status.c	2001/11/23 16:35:21	1.49
+++ modules/generators/mod_status.c	2001/12/17 22:27:59
@@ -102,6 +102,7 @@
 #include "http_core.h"
 #include "http_protocol.h"
 #include "http_main.h"
+#include "ap_mpm.h"
 #include "util_script.h"
 #include <time.h>
 #include "scoreboard.h"
@@ -138,6 +139,8 @@
 
 module AP_MODULE_DECLARE_DATA status_module;
 
+int server_limit, thread_limit;
+
 /*
  *command-related code. This is here to prevent use of ExtendedStatus
  * without status_module included.
@@ -251,8 +254,8 @@
     int no_table_report = 0;
     worker_score ws_record;
     process_score ps_record;
-    char stat_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT];
-    pid_t pid_buffer[HARD_SERVER_LIMIT];
+    char *stat_buffer;
+    pid_t *pid_buffer;
     clock_t tu, ts, tcu, tcs;
     server_rec *vhost;
 
@@ -260,6 +263,9 @@
         return DECLINED;
     }
 
+    pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
+    stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
+
     nowtime = apr_time_now();
     tu = ts = tcu = tcs = 0;
 
@@ -311,9 +317,9 @@
 	return 0;
 
 /*    ap_sync_scoreboard_image(); */
-    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
-        for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
-            int indx = (i * HARD_THREAD_LIMIT) + j;
+    for (i = 0; i < server_limit; ++i) {
+        for (j = 0; j < thread_limit; ++j) {
+            int indx = (i * thread_limit) + j;
 
 	    ws_record = ap_scoreboard_image->servers[i][j];
 	    ps_record = ap_scoreboard_image->parent[i];
@@ -450,9 +456,9 @@
     else
 	ap_rputs("Scoreboard: ", r);
 
-    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
-        for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
-            int indx = (i * HARD_THREAD_LIMIT) + j;
+    for (i = 0; i < server_limit; ++i) {
+        for (j = 0; j < thread_limit; ++j) {
+            int indx = (i * thread_limit) + j;
 	    ap_rputc(stat_buffer[indx], r);
 	    if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1)) && !short_report)
 	        ap_rputs("\n", r);
@@ -481,9 +487,9 @@
             int k = 0;
 	    ap_rputs("PID Key: <br />\n", r);
 	    ap_rputs("<pre>\n", r);
-	    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
-                for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
-                    int indx = (i * HARD_THREAD_LIMIT) + j;
+	    for (i = 0; i < server_limit; ++i) {
+                for (j = 0; j < thread_limit; ++j) {
+                    int indx = (i * thread_limit) + j;
 
 		    if (stat_buffer[indx] != '.') {
 		        ap_rprintf(r, "   %" APR_OS_PROC_T_FMT 
@@ -515,8 +521,8 @@
 #endif
 	}
 
-	for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
-	for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
+	for (i = 0; i < server_limit; ++i) {
+	for (j = 0; j < thread_limit; ++j) {
 	    ws_record = ap_scoreboard_image->servers[i][j];
 	    ps_record = ap_scoreboard_image->parent[i];
 	    vhost = ws_record.vhostrec;
@@ -780,6 +786,12 @@
     status_flags[SERVER_CLOSING] = 'C';
     status_flags[SERVER_GRACEFUL] = 'G';
     status_flags[SERVER_IDLE_KILL] = 'I';
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+    if (thread_limit == 0) {
+        /* XXX prefork! */
+        thread_limit = 1;
+    }
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
     return OK;
 }
 
Index: modules/http/http_core.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/http/http_core.c,v
retrieving revision 1.288
diff -u -r1.288 http_core.c
--- modules/http/http_core.c	2001/12/14 21:30:16	1.288
+++ modules/http/http_core.c	2001/12/17 22:28:00
@@ -269,23 +269,23 @@
      * until no requests are left or we decide to close.
      */
  
-    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_READ, NULL);
+    ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
     while ((r = ap_read_request(c)) != NULL) {
  
         c->keepalive = 0;
         /* process the request if it was read without error */
  
-        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_WRITE, r);
+        ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
         if (r->status == HTTP_OK)
             ap_process_request(r);
  
         if (ap_extended_status)
-            ap_increment_counts(AP_CHILD_THREAD_FROM_ID(c->id), r);
+            ap_increment_counts(c->sbh, r);
  
         if (!c->keepalive || c->aborted)
             break;
  
-        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_KEEPALIVE, r);
+        ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r);
         apr_pool_destroy(r->pool);
  
         if (ap_graceful_stop_signalled())
Index: server/connection.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/connection.c,v
retrieving revision 1.94
diff -u -r1.94 connection.c
--- server/connection.c	2001/11/15 20:49:53	1.94
+++ server/connection.c	2001/12/17 22:28:00
@@ -83,8 +83,8 @@
 AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c),(c),OK,DECLINED)
 AP_IMPLEMENT_HOOK_RUN_FIRST(int,process_connection,(conn_rec *c),(c),DECLINED)
 AP_IMPLEMENT_HOOK_RUN_FIRST(conn_rec *,create_connection,
-                     (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id),
-                     (p, server, csd, conn_id), NULL)
+                     (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id, void *sbh),
+                     (p, server, csd, conn_id, sbh), NULL)
 
 /*
  * More machine-dependent networking gooo... on some systems,
@@ -167,7 +167,7 @@
         return;
     }
 
-    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_CLOSING, NULL);
+    ap_update_child_status(c->sbh, SERVER_CLOSING, NULL);
 
 #ifdef NO_LINGCLOSE
     ap_flush_conn(c);	/* just close it */
Index: server/core.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/core.c,v
retrieving revision 1.120
diff -u -r1.120 core.c
--- server/core.c	2001/12/13 19:44:45	1.120
+++ server/core.c	2001/12/17 22:28:03
@@ -3426,7 +3426,7 @@
 }
 
 static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
-                                  apr_socket_t *csd, int conn_id)
+                                  apr_socket_t *csd, int conn_id, void *sbh)
 {
     core_net_rec *net = apr_palloc(ptrans, sizeof(*net));
     apr_status_t rv;
@@ -3438,9 +3438,9 @@
     net->in_ctx = NULL;
     net->out_ctx = NULL;
     net->c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
- 
-    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(conn_id),
-                                  SERVER_BUSY_READ, (request_rec *) NULL);
+
+    net->c->sbh = sbh;
+    (void) ap_update_child_status(net->c->sbh, SERVER_BUSY_READ, (request_rec *) NULL);
  
     /* Got a connection structure, so initialize what fields we can
      * (the rest are zeroed out by pcalloc).
Index: server/scoreboard.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
retrieving revision 1.39
diff -u -r1.39 scoreboard.c
--- server/scoreboard.c	2001/12/07 19:08:50	1.39
+++ server/scoreboard.c	2001/12/17 22:28:03
@@ -97,6 +97,14 @@
                        (apr_pool_t *p, ap_scoreboard_e sb_type),
                        (p, sb_type))
 
+typedef struct sb_handle {
+    int child_num;
+    int thread_num;
+} sb_handle;
+
+static int server_limit, thread_limit;
+static apr_size_t scoreboard_size;
+
 /*
  * ToDo:
  * This function should be renamed to cleanup_shared
@@ -115,6 +123,39 @@
     return APR_SUCCESS;
 }
 
+static void calc_scoreboard_size(void)
+{
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
+    /* XXX whassup with prefork? */
+    if (thread_limit == 0) {
+        thread_limit = 1;
+    }
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
+    scoreboard_size = sizeof(scoreboard);
+    scoreboard_size += sizeof(process_score) * server_limit;
+    scoreboard_size += sizeof(worker_score * ) * server_limit;
+    scoreboard_size += sizeof(worker_score) * server_limit * thread_limit;
+}
+
+static void init_scoreboard(void)
+{
+    char *more_storage;
+    int i;
+
+    memset(ap_scoreboard_image, 0, scoreboard_size);
+    more_storage = (char *)(ap_scoreboard_image + 1);
+    ap_scoreboard_image->parent = (process_score *)more_storage;
+    more_storage += sizeof(process_score) * server_limit;
+    ap_scoreboard_image->servers = (worker_score **)more_storage;
+    more_storage += server_limit * sizeof(worker_score *);
+
+    for (i = 0; i < server_limit; i++) {
+        ap_scoreboard_image->servers[i] = (worker_score *)more_storage;
+        more_storage += thread_limit * sizeof(worker_score);
+    }
+    ap_assert(more_storage - (char *)ap_scoreboard_image == scoreboard_size);
+}
+
 /* ToDo: This function should be made to handle setting up 
  * a scoreboard shared between processes using any IPC technique, 
  * not just a shared memory segment
@@ -128,14 +169,14 @@
     apr_status_t rv;
 
     fname = ap_server_root_relative(p, ap_scoreboard_fname);
-    rv = apr_shm_init(&scoreboard_shm, SCOREBOARD_SIZE, fname, p);
+    rv = apr_shm_init(&scoreboard_shm, scoreboard_size, fname, p);
     if (rv != APR_SUCCESS) {
         apr_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard: (%d)%s",
                     ap_server_argv0, rv, apr_strerror(rv, errmsg, sizeof errmsg));
         fprintf(stderr, "%s\n", buf);
         exit(APEXIT_INIT);
     }
-    ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, SCOREBOARD_SIZE);
+    ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, scoreboard_size);
     if (ap_scoreboard_image == NULL) {
         apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard",
                     ap_server_argv0);
@@ -143,6 +184,8 @@
         apr_shm_destroy(scoreboard_shm);
         exit(APEXIT_INIT);
     }
+    init_scoreboard();
+
     ap_scoreboard_image->global.running_generation = 0;
 #endif
 }
@@ -180,13 +223,14 @@
     if (ap_scoreboard_image)
 	running_gen = ap_scoreboard_image->global.running_generation;
     if (ap_scoreboard_image == NULL) {
+        calc_scoreboard_size();
         if (sb_type == SB_SHARED) {
             setup_shared(p);
         }
         else {
             /* A simple malloc will suffice */
             char buf[512];
-            ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
+            ap_scoreboard_image = (scoreboard *) malloc(scoreboard_size);
             if (ap_scoreboard_image == NULL) {
                 apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard",
                              ap_server_argv0);
@@ -195,7 +239,7 @@
             }
         }
     }
-    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
+    init_scoreboard(); /* can't just memset() */
     ap_scoreboard_image->global.sb_type = sb_type;
     ap_scoreboard_image->global.running_generation = running_gen;
     ap_restart_time = apr_time_now();
@@ -242,11 +286,12 @@
 #endif
 }
 
-AP_DECLARE(void) ap_increment_counts(int child_num, int thread_num, request_rec *r)
+AP_DECLARE(void) ap_increment_counts(void *sbh, request_rec *r)
 {
+    sb_handle *sb = sbh;
     worker_score *ws;
 
-    ws = &ap_scoreboard_image->servers[child_num][thread_num];
+    ws = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num];
 
 #ifdef HAVE_TIMES
     times(&ws->times);
@@ -258,7 +303,7 @@
     ws->my_bytes_served += r->bytes_sent;
     ws->conn_bytes += r->bytes_sent;
 
-    put_scoreboard_info(child_num, thread_num, ws);
+    put_scoreboard_info(sb->child_num, sb->thread_num, ws);
 }
 
 AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid)
@@ -275,8 +320,20 @@
     return -1;
 }
 
-AP_DECLARE(int) ap_update_child_status(int child_num, int thread_num, int status, request_rec *r)
+AP_DECLARE(void) ap_create_sb_handle(void **new_handle, apr_pool_t *p,
+                                     int child_num, int thread_num)
 {
+    sb_handle *sbh;
+
+    sbh = (sb_handle *)apr_palloc(p, sizeof *sbh);
+    *new_handle = sbh;
+    sbh->child_num = child_num;
+    sbh->thread_num = thread_num;
+}
+
+AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, int thread_num,
+                                                    int status, request_rec *r)
+{
     int old_status, i;
     worker_score *ws;
     process_score *ps;
@@ -292,9 +349,9 @@
     
     if (status == SERVER_READY
 	&& old_status == SERVER_STARTING) {
-        ws->thread_num = child_num * HARD_SERVER_LIMIT + thread_num;
+        ws->thread_num = child_num * server_limit + thread_num;
         if (ps->generation != ap_my_generation) {
-            for (i = 0; i < HARD_THREAD_LIMIT; i++) {
+            for (i = 0; i < thread_limit; i++) {
                 ap_scoreboard_image->servers[child_num][i].vhostrec = NULL;
             }
             ps->generation = ap_my_generation;
@@ -337,6 +394,14 @@
     return old_status;
 }
 
+AP_DECLARE(int)ap_update_child_status(void *sbh, int status, request_rec *r)
+{
+    sb_handle *sb = sbh;
+    
+    return ap_update_child_status_from_indexes(sb->child_num, sb->thread_num,
+                                               status, r);
+}
+
 void ap_time_process_request(int child_num, int thread_num, int status)
 {
     worker_score *ws;
@@ -357,8 +422,8 @@
 
 AP_DECLARE(worker_score *) ap_get_servers_scoreboard(int x, int y)
 {
-    if (((x < 0) || (HARD_SERVER_LIMIT < x)) ||
-        ((y < 0) || (HARD_THREAD_LIMIT < y))) {
+    if (((x < 0) || (server_limit < x)) ||
+        ((y < 0) || (thread_limit < y))) {
         return(NULL); /* Out of range */
     }
     return(&ap_scoreboard_image->servers[x][y]);
@@ -366,7 +431,7 @@
 
 AP_DECLARE(process_score *) ap_get_parent_scoreboard(int x)
 {
-    if ((x < 0) || (HARD_SERVER_LIMIT < x)) {
+    if ((x < 0) || (server_limit < x)) {
         return(NULL); /* Out of range */
     }
     return(&ap_scoreboard_image->parent[x]);
Index: server/mpm/prefork/mpm_default.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/prefork/mpm_default.h,v
retrieving revision 1.6
diff -u -r1.6 mpm_default.h
--- server/mpm/prefork/mpm_default.h	2001/02/16 04:26:51	1.6
+++ server/mpm/prefork/mpm_default.h	2001/12/17 22:28:03
@@ -59,10 +59,6 @@
 #ifndef APACHE_MPM_DEFAULT_H
 #define APACHE_MPM_DEFAULT_H
 
-#define AP_ID_FROM_CHILD_THREAD(c, t)    c
-#define AP_CHILD_THREAD_FROM_ID(i)       i, 0
-
-
 /* Number of servers to spawn off by default --- also, if fewer than
  * this free when the caretaker checks, it will spawn more.
  */
@@ -82,25 +78,6 @@
 
 #ifndef DEFAULT_MIN_FREE_DAEMON
 #define DEFAULT_MIN_FREE_DAEMON 5
-#endif
-
-/* Limit on the total --- clients will be locked out if more servers than
- * this are needed.  It is intended solely to keep the server from crashing
- * when things get out of hand.
- *
- * We keep a hard maximum number of servers, for two reasons --- first off,
- * in case something goes seriously wrong, we want to stop the fork bomb
- * short of actually crashing the machine we're running on by filling some
- * kernel table.  Secondly, it keeps the size of the scoreboard file small
- * enough that we can read the whole thing without worrying too much about
- * the overhead.
- */
-#ifndef HARD_SERVER_LIMIT
-#define HARD_SERVER_LIMIT 256
-#endif
-
-#ifndef HARD_THREAD_LIMIT
-#define HARD_THREAD_LIMIT 1
 #endif
 
 /* File used for accept locking, when we use a file */
Index: server/mpm/prefork/prefork.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/prefork/prefork.c,v
retrieving revision 1.224
diff -u -r1.224 prefork.c
--- server/mpm/prefork/prefork.c	2001/12/14 16:20:48	1.224
+++ server/mpm/prefork/prefork.c	2001/12/17 22:28:04
@@ -103,6 +103,25 @@
 #include <signal.h>
 #include <sys/times.h>
 
+/* Limit on the total --- clients will be locked out if more servers than
+ * this are needed.  It is intended solely to keep the server from crashing
+ * when things get out of hand.
+ *
+ * We keep a hard maximum number of servers, for two reasons --- first off,
+ * in case something goes seriously wrong, we want to stop the fork bomb
+ * short of actually crashing the machine we're running on by filling some
+ * kernel table.  Secondly, it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifndef HARD_SERVER_LIMIT
+#define HARD_SERVER_LIMIT 256
+#endif
+
+#ifndef HARD_THREAD_LIMIT
+#define HARD_THREAD_LIMIT 1
+#endif
+
 /* config globals */
 
 int ap_threads_per_child=0;         /* Worker threads per child */
@@ -343,7 +362,7 @@
         ap_sync_scoreboard_image();
 	if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
 		kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
-	    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(n), SERVER_DEAD, NULL);
+	    ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL);
 	    /* just mark it as having a successful exit status */
             *status = APR_PROC_EXIT;
             *exitcode = 0;
@@ -549,6 +568,7 @@
     apr_pollfd_t *pollset;
     int offset;
     void *csd;
+    void *sbh;
 
     my_child_num = child_num_arg;
     ap_my_pid = getpid();
@@ -571,8 +591,10 @@
     }
 
     ap_run_child_init(pchild, ap_server_conf);
+
+    ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
 
-    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL);
+    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
 
     ap_sync_scoreboard_image();
 
@@ -602,7 +624,7 @@
 	    clean_child_exit(0);
 	}
 
-	(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL);
+	(void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
 
 	/*
 	 * Wait for an acceptable connection to arrive.
@@ -679,7 +701,7 @@
 	 * socket options, file descriptors, and read/write buffers.
 	 */
 
-	current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num);
+	current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh);
         if (current_conn) {
             ap_process_connection(current_conn);
             ap_lingering_close(current_conn);
@@ -720,7 +742,8 @@
 	child_main(slot);
     }
 
-    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_STARTING, (request_rec *) NULL);
+    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
+                                               (request_rec *) NULL);
 
 
 #ifdef _OSD_POSIX
@@ -736,7 +759,8 @@
 	/* fork didn't succeed. Fix the scoreboard or else
 	 * it will say SERVER_STARTING forever and ever
 	 */
-	(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_DEAD, (request_rec *) NULL);
+	(void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
+                                                   (request_rec *) NULL);
 
 	/* In case system resources are maxxed out, we don't want
 	   Apache running away with the CPU trying to fork over and
@@ -1029,8 +1053,8 @@
 	    ap_sync_scoreboard_image();
 	    child_slot = find_child_by_pid(&pid);
 	    if (child_slot >= 0) {
-		(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(child_slot), SERVER_DEAD,
-					    (request_rec *) NULL);
+		(void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
+                                                           (request_rec *) NULL);
 		if (remaining_children_to_start
 		    && child_slot < ap_daemons_limit) {
 		    /* we're still doing a 1-for-1 replacement of dead
Index: server/mpm/worker/mpm_default.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/mpm_default.h,v
retrieving revision 1.2
diff -u -r1.2 mpm_default.h
--- server/mpm/worker/mpm_default.h	2001/09/24 23:03:42	1.2
+++ server/mpm/worker/mpm_default.h	2001/12/17 22:28:04
@@ -59,9 +59,6 @@
 #ifndef APACHE_MPM_DEFAULT_H
 #define APACHE_MPM_DEFAULT_H
 
-#define AP_ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_THREAD_LIMIT) + t)
-#define AP_CHILD_THREAD_FROM_ID(i)    (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT)
-
 /* Number of servers to spawn off by default --- also, if fewer than
  * this free when the caretaker checks, it will spawn more.
  */
@@ -81,32 +78,6 @@
 
 #ifndef DEFAULT_MIN_FREE_DAEMON
 #define DEFAULT_MIN_FREE_DAEMON 3
-#endif
-
-/* Limit on the total --- clients will be locked out if more servers than
- * this are needed.  It is intended solely to keep the server from crashing
- * when things get out of hand.
- *
- * We keep a hard maximum number of servers, for two reasons --- first off,
- * in case something goes seriously wrong, we want to stop the fork bomb
- * short of actually crashing the machine we're running on by filling some
- * kernel table.  Secondly, it keeps the size of the scoreboard file small
- * enough that we can read the whole thing without worrying too much about
- * the overhead.
- */
-#ifndef HARD_SERVER_LIMIT
-#define HARD_SERVER_LIMIT 16
-#endif
-
-/* Limit on the threads per process.  Clients will be locked out if more than
- * this  * HARD_SERVER_LIMIT are needed.
- *
- * We keep this for one reason it keeps the size of the scoreboard file small
- * enough that we can read the whole thing without worrying too much about
- * the overhead.
- */
-#ifndef HARD_THREAD_LIMIT
-#define HARD_THREAD_LIMIT 64 
 #endif
 
 #ifndef DEFAULT_THREADS_PER_CHILD
Index: server/mpm/worker/worker.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.47
diff -u -r1.47 worker.c
--- server/mpm/worker/worker.c	2001/12/14 16:29:43	1.47
+++ server/mpm/worker/worker.c	2001/12/17 22:28:06
@@ -110,6 +110,32 @@
 #include <signal.h>
 #include <limits.h>             /* for INT_MAX */
 
+/* Limit on the total --- clients will be locked out if more servers than
+ * this are needed.  It is intended solely to keep the server from crashing
+ * when things get out of hand.
+ *
+ * We keep a hard maximum number of servers, for two reasons --- first off,
+ * in case something goes seriously wrong, we want to stop the fork bomb
+ * short of actually crashing the machine we're running on by filling some
+ * kernel table.  Secondly, it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifndef HARD_SERVER_LIMIT
+#define HARD_SERVER_LIMIT 16
+#endif
+
+/* Limit on the threads per process.  Clients will be locked out if more than
+ * this  * HARD_SERVER_LIMIT are needed.
+ *
+ * We keep this for one reason it keeps the size of the scoreboard file small
+ * enough that we can read the whole thing without worrying too much about
+ * the overhead.
+ */
+#ifndef HARD_THREAD_LIMIT
+#define HARD_THREAD_LIMIT 64 
+#endif
+
 /*
  * Actual definitions of config globals
  */
@@ -141,6 +167,8 @@
     apr_threadattr_t *threadattr;
 } thread_starter;
 
+#define ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_THREAD_LIMIT) + t)
+
 /*
  * The max child slot ever assigned, preserved across restarts.  Necessary
  * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts.  We 
@@ -495,9 +523,11 @@
                            int my_thread_num)
 {
     conn_rec *current_conn;
-    long conn_id = AP_ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
+    long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
     int csd;
+    void *sbh;
 
+    ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
     apr_os_sock_get(&csd, sock);
 
     if (csd >= FD_SETSIZE) {
@@ -510,7 +540,7 @@
         return;
     }
 
-    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id);
+    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, sbh);
     if (current_conn) {
         ap_process_connection(current_conn);
         ap_lingering_close(current_conn);
@@ -694,9 +724,9 @@
         }
     }
 
-    ap_update_child_status(process_slot, thread_slot, 
-                           (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
-                           (request_rec *) NULL);
+    ap_update_child_status_from_indexes(process_slot, thread_slot, 
+                                        (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
+                                        (request_rec *) NULL);
     dying = 1;
     ap_scoreboard_image->parent[process_slot].quiescing = 1;
     kill(ap_my_pid, SIGTERM);
@@ -718,9 +748,9 @@
 
     free(ti);
 
-    ap_update_child_status(process_slot, thread_slot, SERVER_STARTING, NULL);
+    ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL);
     while (!workers_may_exit) {
-        ap_update_child_status(process_slot, thread_slot, SERVER_READY, NULL);
+        ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL);
         rv = ap_queue_pop(worker_queue, &csd, &ptrans);
         /* We get FD_QUEUE_EINTR whenever ap_queue_pop() has been interrupted
          * from an explicit call to ap_queue_interrupt_all(). This allows
@@ -734,7 +764,7 @@
         apr_pool_destroy(ptrans);
     }
 
-    ap_update_child_status(process_slot, thread_slot,
+    ap_update_child_status_from_indexes(process_slot, thread_slot,
         (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);
     apr_thread_mutex_lock(worker_thread_count_mutex);
     worker_thread_count--;
@@ -797,7 +827,7 @@
             my_info->sd = 0;
         
               /* We are creating threads right now */
-            ap_update_child_status(my_child_num, i, SERVER_STARTING, NULL);
+            ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, NULL);
             /* We let each thread update its own scoreboard entry.  This is
              * done because it lets us deal with tid better.
              */
@@ -821,8 +851,8 @@
     
     /* What state should this child_main process be listed as in the 
      * scoreboard...?
-     *  ap_update_child_status(my_child_num, i, SERVER_STARTING, 
-     *                         (request_rec *) NULL);
+     *  ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING, 
+     *                                      (request_rec *) NULL);
      * 
      *  This state should be listed separately in the scoreboard, in some kind
      *  of process_status, not mixed in with the worker threads' status.   
@@ -965,7 +995,7 @@
         /* fork didn't succeed. Fix the scoreboard or else
          * it will say SERVER_STARTING forever and ever
          */
-        ap_update_child_status(slot, 0, SERVER_DEAD, NULL);
+        ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL);
 
         /* In case system resources are maxxed out, we don't want
            Apache running away with the CPU trying to fork over and
@@ -1222,8 +1252,8 @@
             child_slot = find_child_by_pid(&pid);
             if (child_slot >= 0) {
                 for (i = 0; i < ap_threads_per_child; i++)
-                    ap_update_child_status(child_slot, i, SERVER_DEAD, 
-                                           (request_rec *) NULL);
+                    ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD, 
+                                                        (request_rec *) NULL);
                 
                 ap_scoreboard_image->parent[child_slot].pid = 0;
                 ap_scoreboard_image->parent[child_slot].quiescing = 0;

-- 
Jeff Trawick | trawick@attglobal.net | PGP public key at web site:
       http://www.geocities.com/SiliconValley/Park/9289/
             Born in Roswell... married an alien...

Re: [PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

Posted by Jeff Trawick <tr...@attglobal.net>.
Jeff Trawick <tr...@attglobal.net> writes:

mod_status and scoreboard.c in my patch have this gorp:

> +    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
> +    if (thread_limit == 0) {
> +        /* XXX prefork! */
> +        thread_limit = 1;
> +    }

the thread_limit==0 gorp isn't necessary here...  (sorry for confusing
the patch)

the gorpy logic is necessary with AP_MPMQ_MAX_THREADS...  I would
think that is a bug (i.e., prefork should return 1, not zero)...  

a module should use AP_MPMQ_IS_THREADED to find out that information
instead of calling AP_MPMQ_MAX_THREADS and then compare the value with
zero

-- 
Jeff Trawick | trawick@attglobal.net | PGP public key at web site:
       http://www.geocities.com/SiliconValley/Park/9289/
             Born in Roswell... married an alien...

Re: [PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

Posted by Ryan Bloom <rb...@covalent.net>.
On Monday 17 December 2001 08:30 pm, Jeff Trawick wrote:

Cool.  Thanks for showing me what I was missing.  In that case, +1.
I am not sure how much more useful this is than what we have now,
but it is a step in the right direction.

Ryan

> Ryan Bloom <rb...@covalent.net> writes:
> 
> > I'm missing something major here.  This patch doesn't remove the dependence
> > on HARD_SERVER_LIMIT and HARD_THREAD_LIMIT, it just hides the actual
> > macros.  The dependence is still there, but it is queried through the ap_mpm_query
> > function.  In fact, you are computing the size of the scoreboard based on those
> > values.
> 
> Yep.  The missing piece is a way for an MPM to return something
> dynamically-configured from the mpm query function, instead of just
> returning HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.  As I mentioned in the
> brief description, I didn't want to clutter expected discussions of
> the user interface for setting those values with the bulk of the code.
> 
> What I meant from the subject line is that with this patch an MPM can
> *choose* to implement softer limits for servers and threads.  In other
> words, with this patch the core code now gives an MPM the power to
> allow the admin to set those limits at startup.  How we choose to do
> that with our own beloved MPMs remains to be seen.
> 
> I would doubt that prefork would bother with it since it doesn't take
> so much scoreboard storage to support a wide range of values for
> MaxClients, and so prefork.c would continue to use the 
> HARD_SERVER_LIMIT/HARD_THREAD_LIMIT defines internally.
> 
> I'd think that both perchild and worker would benefit from it.  I
> dunno about other MPMs.
> 
> > Having said that, the changes to mod_status are all goodness, and I would
> > encourage those to be committed immediately, even without the other stuff. 
> > This has been on my list for a while, but I kept forgetting about
> > it.
> 
> I'll do that shortly.
> 
> > I would appreciate an explanation of how this removes the H_S_L and H_T_L
> > dependance though.
> 
> easy explanation: that capability isn't here (yet)
> 
> -- 
> Jeff Trawick | trawick@attglobal.net | PGP public key at web site:
>        http://www.geocities.com/SiliconValley/Park/9289/
>              Born in Roswell... married an alien...
> 
> 

-- 

______________________________________________________________
Ryan Bloom				rbb@apache.org
Covalent Technologies			rbb@covalent.net
--------------------------------------------------------------

Re: [PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

Posted by Jeff Trawick <tr...@attglobal.net>.
Ryan Bloom <rb...@covalent.net> writes:

> I'm missing something major here.  This patch doesn't remove the dependence
> on HARD_SERVER_LIMIT and HARD_THREAD_LIMIT, it just hides the actual
> macros.  The dependence is still there, but it is queried through the ap_mpm_query
> function.  In fact, you are computing the size of the scoreboard based on those
> values.

Yep.  The missing piece is a way for an MPM to return something
dynamically-configured from the mpm query function, instead of just
returning HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.  As I mentioned in the
brief description, I didn't want to clutter expected discussions of
the user interface for setting those values with the bulk of the code.

What I meant from the subject line is that with this patch an MPM can
*choose* to implement softer limits for servers and threads.  In other
words, with this patch the core code now gives an MPM the power to
allow the admin to set those limits at startup.  How we choose to do
that with our own beloved MPMs remains to be seen.

I would doubt that prefork would bother with it since it doesn't take
so much scoreboard storage to support a wide range of values for
MaxClients, and so prefork.c would continue to use the 
HARD_SERVER_LIMIT/HARD_THREAD_LIMIT defines internally.

I'd think that both perchild and worker would benefit from it.  I
dunno about other MPMs.

> Having said that, the changes to mod_status are all goodness, and I would
> encourage those to be committed immediately, even without the other stuff. 
> This has been on my list for a while, but I kept forgetting about
> it.

I'll do that shortly.

> I would appreciate an explanation of how this removes the H_S_L and H_T_L
> dependance though.

easy explanation: that capability isn't here (yet)

-- 
Jeff Trawick | trawick@attglobal.net | PGP public key at web site:
       http://www.geocities.com/SiliconValley/Park/9289/
             Born in Roswell... married an alien...

Re: [PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

Posted by Ryan Bloom <rb...@covalent.net>.
I'm missing something major here.  This patch doesn't remove the dependence
on HARD_SERVER_LIMIT and HARD_THREAD_LIMIT, it just hides the actual
macros.  The dependence is still there, but it is queried through the ap_mpm_query
function.  In fact, you are computing the size of the scoreboard based on those
values.

Having said that, the changes to mod_status are all goodness, and I would
encourage those to be committed immediately, even without the other stuff. 
This has been on my list for a while, but I kept forgetting about it.

I would appreciate an explanation of how this removes the H_S_L and H_T_L
dependance though.

Ryan

On Monday 17 December 2001 07:30 pm, Bill Stoddard wrote:
> ++1
> 
> Removing the restriction of a compiled in HARD_SERVER_LIMIT and HARD_THREAD_LIMIT and
> doing it w/o requiring scoreboard locking as you have done is total goodness. Each MPM can
> define defaults and possibly max limits, if that is what the MPM needs to do, or not.
> 
> Bill
> 
> > primary goal:
> >
> > be able to change equivalent of HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
> > without rebuilding the server
> >
> > this is trivial to implement with the caveat that you don't allow the
> > admin to change it across a restart
> >
> > currently, to allow the admin a lot of choices in how they split httpd
> > threads among processes, lots of unused shared memory is required;
> > this is much worse with a threaded MPM than it ever was with
> > prefork/Apache 1.3 because the amount of resource consumed is
> > threads*servers
> >
> > what module code has to change with this patch?
> >
> >   *If* module is being bad and isn't using the MPM query API, it must
> >   start doing it, because we don't allow modules to see equivalent of
> >   today's HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.  Hopefully third-party
> >   modules aren't doing that, because it is a problem that they must be
> >   rebuilt if somebody rebuilds/reconfigures httpd with different
> >   HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.
> >
> >   *Otherwise* just a recompile is necessary to tell the C compiler to
> >   generate different code to walk through the scoreboard arrays.
> >
> > benefits:
> >
> > * we have an MPM query API; don't let the module bypass it
> >
> >   the changes below to mod_status keep mod_status from needing a
> >   recompile if you're using an MPM that is stuck with hard limits and
> >   you have to rebuild the server
> >
> > * an MPM needs power to implement softer HARD_THREAD_LIMIT /
> >   HARD_SERVER_LIMIT; since it is easy for the MPM to do that, don't
> >   stand in the MPM's way
> >
> > Of course I would want worker to be softer about these limits than it
> > is today but independent of that we should certainly allow somebody
> > to patch it or implement their own MPM that is nice in that regard.
> >
> > (The main reason there is no patch here to make worker do that is
> > because there are issues to discuss about the user interface which
> > shouldn't cloud the issue of being able to do such a thing.)
> >
> > One of the details of limiting HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
> > to being the MPM's concern is that the way to do
> > ap_update_child_status() needed to change.  Now, there is a handle to
> > scoreboard information in the conn_rec which most code uses.
> > Currently that handle just has access to the server and thread indices
> > but with a few lines of code this could also have pointers to the
> > appropriate status structures.  That didn't seem important for the
> > current goal.
> >
> > Changes not here in the patch are necessary for MPMs other than worker
> > and prefork.  They need to get HARD_SERVER_LIMIT/HARD_THREAD_LIMIT out
> > of mpm_default.h and just refer to them locally.

______________________________________________________________
Ryan Bloom				rbb@apache.org
Covalent Technologies			rbb@covalent.net
--------------------------------------------------------------

Re: [PATCH] allow MPM to change HARD_SERVER_LIMIT/HARD_THREAD_LIMIT at startup

Posted by Bill Stoddard <bi...@wstoddard.com>.
++1

Removing the restriction of a compiled in HARD_SERVER_LIMIT and HARD_THREAD_LIMIT and
doing it w/o requiring scoreboard locking as you have done is total goodness. Each MPM can
define defaults and possibly max limits, if that is what the MPM needs to do, or not.

Bill

> primary goal:
>
> be able to change equivalent of HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
> without rebuilding the server
>
> this is trivial to implement with the caveat that you don't allow the
> admin to change it across a restart
>
> currently, to allow the admin a lot of choices in how they split httpd
> threads among processes, lots of unused shared memory is required;
> this is much worse with a threaded MPM than it ever was with
> prefork/Apache 1.3 because the amount of resource consumed is
> threads*servers
>
> what module code has to change with this patch?
>
>   *If* module is being bad and isn't using the MPM query API, it must
>   start doing it, because we don't allow modules to see equivalent of
>   today's HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.  Hopefully third-party
>   modules aren't doing that, because it is a problem that they must be
>   rebuilt if somebody rebuilds/reconfigures httpd with different
>   HARD_SERVER_LIMIT/HARD_THREAD_LIMIT.
>
>   *Otherwise* just a recompile is necessary to tell the C compiler to
>   generate different code to walk through the scoreboard arrays.
>
> benefits:
>
> * we have an MPM query API; don't let the module bypass it
>
>   the changes below to mod_status keep mod_status from needing a
>   recompile if you're using an MPM that is stuck with hard limits and
>   you have to rebuild the server
>
> * an MPM needs power to implement softer HARD_THREAD_LIMIT /
>   HARD_SERVER_LIMIT; since it is easy for the MPM to do that, don't
>   stand in the MPM's way
>
> Of course I would want worker to be softer about these limits than it
> is today but independent of that we should certainly allow somebody
> to patch it or implement their own MPM that is nice in that regard.
>
> (The main reason there is no patch here to make worker do that is
> because there are issues to discuss about the user interface which
> shouldn't cloud the issue of being able to do such a thing.)
>
> One of the details of limiting HARD_SERVER_LIMIT/HARD_THREAD_LIMIT
> to being the MPM's concern is that the way to do
> ap_update_child_status() needed to change.  Now, there is a handle to
> scoreboard information in the conn_rec which most code uses.
> Currently that handle just has access to the server and thread indices
> but with a few lines of code this could also have pointers to the
> appropriate status structures.  That didn't seem important for the
> current goal.
>
> Changes not here in the patch are necessary for MPMs other than worker
> and prefork.  They need to get HARD_SERVER_LIMIT/HARD_THREAD_LIMIT out
> of mpm_default.h and just refer to them locally.
>
> Index: include/http_connection.h
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/include/http_connection.h,v
> retrieving revision 1.47
> diff -u -r1.47 http_connection.h
> --- include/http_connection.h 2001/11/15 20:49:53 1.47
> +++ include/http_connection.h 2001/12/17 22:27:57
> @@ -127,10 +127,11 @@
>   * @param csd The socket that has been accepted
>   * @param conn_id A unique identifier for this connection.  The ID only
>   *                needs to be unique at that time, not forever.
> + * @param sbh A handle to scoreboard information for this connection.
>   * @return An allocated connection record or NULL.
>   */
>  AP_DECLARE_HOOK(conn_rec *, create_connection,
> -                (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id))
> +                (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int conn_id,
void *sbh))
>
>  #ifdef __cplusplus
>  }
> Index: include/httpd.h
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/include/httpd.h,v
> retrieving revision 1.173
> diff -u -r1.173 httpd.h
> --- include/httpd.h 2001/12/13 19:13:23 1.173
> +++ include/httpd.h 2001/12/17 22:27:58
> @@ -982,6 +982,8 @@
>      struct ap_filter_t *input_filters;
>      /** A list of output filters to be used for this connection */
>      struct ap_filter_t *output_filters;
> +    /** handle to scoreboard information for this connection */
> +    void *sbh;
>  };
>
>  /* Per-vhost config... */
> Index: include/scoreboard.h
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/include/scoreboard.h,v
> retrieving revision 1.33
> diff -u -r1.33 scoreboard.h
> --- include/scoreboard.h 2001/12/07 22:19:38 1.33
> +++ include/scoreboard.h 2001/12/17 22:27:59
> @@ -185,8 +185,8 @@
>
>  typedef struct {
>      global_score global;
> -    process_score parent[HARD_SERVER_LIMIT];
> -    worker_score servers[HARD_SERVER_LIMIT][HARD_THREAD_LIMIT];
> +    process_score *parent;
> +    worker_score **servers;
>  } scoreboard;
>
>  #define KEY_LENGTH 16
> @@ -196,11 +196,12 @@
>      char value[VALUE_LENGTH];
>  } status_table_entry;
>
> +/* XXX what should mod_ssl init use instead of this? */
>  #define SCOREBOARD_SIZE sizeof(scoreboard)
>
>  AP_DECLARE(int) ap_exists_scoreboard_image(void);
>  AP_DECLARE_NONSTD(void) ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e t);
> -AP_DECLARE(void) ap_increment_counts(int child_num, int thread_num, request_rec *r);
> +AP_DECLARE(void) ap_increment_counts(void *sbh, request_rec *r);
>
>  apr_status_t ap_cleanup_scoreboard(void *d);
>
> @@ -208,9 +209,14 @@
>
>  void ap_sync_scoreboard_image(void);
>
> +AP_DECLARE(void) ap_create_sb_handle(void **new_handle, apr_pool_t *p,
> +                                     int child_num, int thread_num);
> +
>  void update_scoreboard_global(void);
>  AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid);
> -AP_DECLARE(int) ap_update_child_status(int child_num, int thread_num, int status,
request_rec *r);
> +AP_DECLARE(int) ap_update_child_status(void *sbh, int status, request_rec *r);
> +AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, int thread_num,
> +                                                    int status, request_rec *r);
>  void ap_time_process_request(int child_num, int thread_num, int status);
>  AP_DECLARE(worker_score *) ap_get_servers_scoreboard(int x, int y);
>  AP_DECLARE(process_score *) ap_get_parent_scoreboard(int x);
> Index: modules/generators/mod_status.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_status.c,v
> retrieving revision 1.49
> diff -u -r1.49 mod_status.c
> --- modules/generators/mod_status.c 2001/11/23 16:35:21 1.49
> +++ modules/generators/mod_status.c 2001/12/17 22:27:59
> @@ -102,6 +102,7 @@
>  #include "http_core.h"
>  #include "http_protocol.h"
>  #include "http_main.h"
> +#include "ap_mpm.h"
>  #include "util_script.h"
>  #include <time.h>
>  #include "scoreboard.h"
> @@ -138,6 +139,8 @@
>
>  module AP_MODULE_DECLARE_DATA status_module;
>
> +int server_limit, thread_limit;
> +
>  /*
>   *command-related code. This is here to prevent use of ExtendedStatus
>   * without status_module included.
> @@ -251,8 +254,8 @@
>      int no_table_report = 0;
>      worker_score ws_record;
>      process_score ps_record;
> -    char stat_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT];
> -    pid_t pid_buffer[HARD_SERVER_LIMIT];
> +    char *stat_buffer;
> +    pid_t *pid_buffer;
>      clock_t tu, ts, tcu, tcs;
>      server_rec *vhost;
>
> @@ -260,6 +263,9 @@
>          return DECLINED;
>      }
>
> +    pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
> +    stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
> +
>      nowtime = apr_time_now();
>      tu = ts = tcu = tcs = 0;
>
> @@ -311,9 +317,9 @@
>   return 0;
>
>  /*    ap_sync_scoreboard_image(); */
> -    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
> -        for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
> -            int indx = (i * HARD_THREAD_LIMIT) + j;
> +    for (i = 0; i < server_limit; ++i) {
> +        for (j = 0; j < thread_limit; ++j) {
> +            int indx = (i * thread_limit) + j;
>
>       ws_record = ap_scoreboard_image->servers[i][j];
>       ps_record = ap_scoreboard_image->parent[i];
> @@ -450,9 +456,9 @@
>      else
>   ap_rputs("Scoreboard: ", r);
>
> -    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
> -        for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
> -            int indx = (i * HARD_THREAD_LIMIT) + j;
> +    for (i = 0; i < server_limit; ++i) {
> +        for (j = 0; j < thread_limit; ++j) {
> +            int indx = (i * thread_limit) + j;
>       ap_rputc(stat_buffer[indx], r);
>       if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1)) && !short_report)
>           ap_rputs("\n", r);
> @@ -481,9 +487,9 @@
>              int k = 0;
>       ap_rputs("PID Key: <br />\n", r);
>       ap_rputs("<pre>\n", r);
> -     for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
> -                for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
> -                    int indx = (i * HARD_THREAD_LIMIT) + j;
> +     for (i = 0; i < server_limit; ++i) {
> +                for (j = 0; j < thread_limit; ++j) {
> +                    int indx = (i * thread_limit) + j;
>
>       if (stat_buffer[indx] != '.') {
>           ap_rprintf(r, "   %" APR_OS_PROC_T_FMT
> @@ -515,8 +521,8 @@
>  #endif
>   }
>
> - for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
> - for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
> + for (i = 0; i < server_limit; ++i) {
> + for (j = 0; j < thread_limit; ++j) {
>       ws_record = ap_scoreboard_image->servers[i][j];
>       ps_record = ap_scoreboard_image->parent[i];
>       vhost = ws_record.vhostrec;
> @@ -780,6 +786,12 @@
>      status_flags[SERVER_CLOSING] = 'C';
>      status_flags[SERVER_GRACEFUL] = 'G';
>      status_flags[SERVER_IDLE_KILL] = 'I';
> +    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
> +    if (thread_limit == 0) {
> +        /* XXX prefork! */
> +        thread_limit = 1;
> +    }
> +    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
>      return OK;
>  }
>
> Index: modules/http/http_core.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/modules/http/http_core.c,v
> retrieving revision 1.288
> diff -u -r1.288 http_core.c
> --- modules/http/http_core.c 2001/12/14 21:30:16 1.288
> +++ modules/http/http_core.c 2001/12/17 22:28:00
> @@ -269,23 +269,23 @@
>       * until no requests are left or we decide to close.
>       */
>
> -    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_READ, NULL);
> +    ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
>      while ((r = ap_read_request(c)) != NULL) {
>
>          c->keepalive = 0;
>          /* process the request if it was read without error */
>
> -        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_WRITE, r);
> +        ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
>          if (r->status == HTTP_OK)
>              ap_process_request(r);
>
>          if (ap_extended_status)
> -            ap_increment_counts(AP_CHILD_THREAD_FROM_ID(c->id), r);
> +            ap_increment_counts(c->sbh, r);
>
>          if (!c->keepalive || c->aborted)
>              break;
>
> -        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_KEEPALIVE,
r);
> +        ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r);
>          apr_pool_destroy(r->pool);
>
>          if (ap_graceful_stop_signalled())
> Index: server/connection.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/connection.c,v
> retrieving revision 1.94
> diff -u -r1.94 connection.c
> --- server/connection.c 2001/11/15 20:49:53 1.94
> +++ server/connection.c 2001/12/17 22:28:00
> @@ -83,8 +83,8 @@
>  AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c),(c),OK,DECLINED)
>  AP_IMPLEMENT_HOOK_RUN_FIRST(int,process_connection,(conn_rec *c),(c),DECLINED)
>  AP_IMPLEMENT_HOOK_RUN_FIRST(conn_rec *,create_connection,
> -                     (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int
conn_id),
> -                     (p, server, csd, conn_id), NULL)
> +                     (apr_pool_t *p, server_rec *server, apr_socket_t *csd, int
conn_id, void *sbh),
> +                     (p, server, csd, conn_id, sbh), NULL)
>
>  /*
>   * More machine-dependent networking gooo... on some systems,
> @@ -167,7 +167,7 @@
>          return;
>      }
>
> -    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_CLOSING, NULL);
> +    ap_update_child_status(c->sbh, SERVER_CLOSING, NULL);
>
>  #ifdef NO_LINGCLOSE
>      ap_flush_conn(c); /* just close it */
> Index: server/core.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/core.c,v
> retrieving revision 1.120
> diff -u -r1.120 core.c
> --- server/core.c 2001/12/13 19:44:45 1.120
> +++ server/core.c 2001/12/17 22:28:03
> @@ -3426,7 +3426,7 @@
>  }
>
>  static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *server,
> -                                  apr_socket_t *csd, int conn_id)
> +                                  apr_socket_t *csd, int conn_id, void *sbh)
>  {
>      core_net_rec *net = apr_palloc(ptrans, sizeof(*net));
>      apr_status_t rv;
> @@ -3438,9 +3438,9 @@
>      net->in_ctx = NULL;
>      net->out_ctx = NULL;
>      net->c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
> -
> -    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(conn_id),
> -                                  SERVER_BUSY_READ, (request_rec *) NULL);
> +
> +    net->c->sbh = sbh;
> +    (void) ap_update_child_status(net->c->sbh, SERVER_BUSY_READ, (request_rec *) NULL);
>
>      /* Got a connection structure, so initialize what fields we can
>       * (the rest are zeroed out by pcalloc).
> Index: server/scoreboard.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/scoreboard.c,v
> retrieving revision 1.39
> diff -u -r1.39 scoreboard.c
> --- server/scoreboard.c 2001/12/07 19:08:50 1.39
> +++ server/scoreboard.c 2001/12/17 22:28:03
> @@ -97,6 +97,14 @@
>                         (apr_pool_t *p, ap_scoreboard_e sb_type),
>                         (p, sb_type))
>
> +typedef struct sb_handle {
> +    int child_num;
> +    int thread_num;
> +} sb_handle;
> +
> +static int server_limit, thread_limit;
> +static apr_size_t scoreboard_size;
> +
>  /*
>   * ToDo:
>   * This function should be renamed to cleanup_shared
> @@ -115,6 +123,39 @@
>      return APR_SUCCESS;
>  }
>
> +static void calc_scoreboard_size(void)
> +{
> +    ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
> +    /* XXX whassup with prefork? */
> +    if (thread_limit == 0) {
> +        thread_limit = 1;
> +    }
> +    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
> +    scoreboard_size = sizeof(scoreboard);
> +    scoreboard_size += sizeof(process_score) * server_limit;
> +    scoreboard_size += sizeof(worker_score * ) * server_limit;
> +    scoreboard_size += sizeof(worker_score) * server_limit * thread_limit;
> +}
> +
> +static void init_scoreboard(void)
> +{
> +    char *more_storage;
> +    int i;
> +
> +    memset(ap_scoreboard_image, 0, scoreboard_size);
> +    more_storage = (char *)(ap_scoreboard_image + 1);
> +    ap_scoreboard_image->parent = (process_score *)more_storage;
> +    more_storage += sizeof(process_score) * server_limit;
> +    ap_scoreboard_image->servers = (worker_score **)more_storage;
> +    more_storage += server_limit * sizeof(worker_score *);
> +
> +    for (i = 0; i < server_limit; i++) {
> +        ap_scoreboard_image->servers[i] = (worker_score *)more_storage;
> +        more_storage += thread_limit * sizeof(worker_score);
> +    }
> +    ap_assert(more_storage - (char *)ap_scoreboard_image == scoreboard_size);
> +}
> +
>  /* ToDo: This function should be made to handle setting up
>   * a scoreboard shared between processes using any IPC technique,
>   * not just a shared memory segment
> @@ -128,14 +169,14 @@
>      apr_status_t rv;
>
>      fname = ap_server_root_relative(p, ap_scoreboard_fname);
> -    rv = apr_shm_init(&scoreboard_shm, SCOREBOARD_SIZE, fname, p);
> +    rv = apr_shm_init(&scoreboard_shm, scoreboard_size, fname, p);
>      if (rv != APR_SUCCESS) {
>          apr_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard: (%d)%s",
>                      ap_server_argv0, rv, apr_strerror(rv, errmsg, sizeof errmsg));
>          fprintf(stderr, "%s\n", buf);
>          exit(APEXIT_INIT);
>      }
> -    ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, SCOREBOARD_SIZE);
> +    ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, scoreboard_size);
>      if (ap_scoreboard_image == NULL) {
>          apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard",
>                      ap_server_argv0);
> @@ -143,6 +184,8 @@
>          apr_shm_destroy(scoreboard_shm);
>          exit(APEXIT_INIT);
>      }
> +    init_scoreboard();
> +
>      ap_scoreboard_image->global.running_generation = 0;
>  #endif
>  }
> @@ -180,13 +223,14 @@
>      if (ap_scoreboard_image)
>   running_gen = ap_scoreboard_image->global.running_generation;
>      if (ap_scoreboard_image == NULL) {
> +        calc_scoreboard_size();
>          if (sb_type == SB_SHARED) {
>              setup_shared(p);
>          }
>          else {
>              /* A simple malloc will suffice */
>              char buf[512];
> -            ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE);
> +            ap_scoreboard_image = (scoreboard *) malloc(scoreboard_size);
>              if (ap_scoreboard_image == NULL) {
>                  apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard",
>                               ap_server_argv0);
> @@ -195,7 +239,7 @@
>              }
>          }
>      }
> -    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
> +    init_scoreboard(); /* can't just memset() */
>      ap_scoreboard_image->global.sb_type = sb_type;
>      ap_scoreboard_image->global.running_generation = running_gen;
>      ap_restart_time = apr_time_now();
> @@ -242,11 +286,12 @@
>  #endif
>  }
>
> -AP_DECLARE(void) ap_increment_counts(int child_num, int thread_num, request_rec *r)
> +AP_DECLARE(void) ap_increment_counts(void *sbh, request_rec *r)
>  {
> +    sb_handle *sb = sbh;
>      worker_score *ws;
>
> -    ws = &ap_scoreboard_image->servers[child_num][thread_num];
> +    ws = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num];
>
>  #ifdef HAVE_TIMES
>      times(&ws->times);
> @@ -258,7 +303,7 @@
>      ws->my_bytes_served += r->bytes_sent;
>      ws->conn_bytes += r->bytes_sent;
>
> -    put_scoreboard_info(child_num, thread_num, ws);
> +    put_scoreboard_info(sb->child_num, sb->thread_num, ws);
>  }
>
>  AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid)
> @@ -275,8 +320,20 @@
>      return -1;
>  }
>
> -AP_DECLARE(int) ap_update_child_status(int child_num, int thread_num, int status,
request_rec *r)
> +AP_DECLARE(void) ap_create_sb_handle(void **new_handle, apr_pool_t *p,
> +                                     int child_num, int thread_num)
>  {
> +    sb_handle *sbh;
> +
> +    sbh = (sb_handle *)apr_palloc(p, sizeof *sbh);
> +    *new_handle = sbh;
> +    sbh->child_num = child_num;
> +    sbh->thread_num = thread_num;
> +}
> +
> +AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, int thread_num,
> +                                                    int status, request_rec *r)
> +{
>      int old_status, i;
>      worker_score *ws;
>      process_score *ps;
> @@ -292,9 +349,9 @@
>
>      if (status == SERVER_READY
>   && old_status == SERVER_STARTING) {
> -        ws->thread_num = child_num * HARD_SERVER_LIMIT + thread_num;
> +        ws->thread_num = child_num * server_limit + thread_num;
>          if (ps->generation != ap_my_generation) {
> -            for (i = 0; i < HARD_THREAD_LIMIT; i++) {
> +            for (i = 0; i < thread_limit; i++) {
>                  ap_scoreboard_image->servers[child_num][i].vhostrec = NULL;
>              }
>              ps->generation = ap_my_generation;
> @@ -337,6 +394,14 @@
>      return old_status;
>  }
>
> +AP_DECLARE(int)ap_update_child_status(void *sbh, int status, request_rec *r)
> +{
> +    sb_handle *sb = sbh;
> +
> +    return ap_update_child_status_from_indexes(sb->child_num, sb->thread_num,
> +                                               status, r);
> +}
> +
>  void ap_time_process_request(int child_num, int thread_num, int status)
>  {
>      worker_score *ws;
> @@ -357,8 +422,8 @@
>
>  AP_DECLARE(worker_score *) ap_get_servers_scoreboard(int x, int y)
>  {
> -    if (((x < 0) || (HARD_SERVER_LIMIT < x)) ||
> -        ((y < 0) || (HARD_THREAD_LIMIT < y))) {
> +    if (((x < 0) || (server_limit < x)) ||
> +        ((y < 0) || (thread_limit < y))) {
>          return(NULL); /* Out of range */
>      }
>      return(&ap_scoreboard_image->servers[x][y]);
> @@ -366,7 +431,7 @@
>
>  AP_DECLARE(process_score *) ap_get_parent_scoreboard(int x)
>  {
> -    if ((x < 0) || (HARD_SERVER_LIMIT < x)) {
> +    if ((x < 0) || (server_limit < x)) {
>          return(NULL); /* Out of range */
>      }
>      return(&ap_scoreboard_image->parent[x]);
> Index: server/mpm/prefork/mpm_default.h
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/mpm/prefork/mpm_default.h,v
> retrieving revision 1.6
> diff -u -r1.6 mpm_default.h
> --- server/mpm/prefork/mpm_default.h 2001/02/16 04:26:51 1.6
> +++ server/mpm/prefork/mpm_default.h 2001/12/17 22:28:03
> @@ -59,10 +59,6 @@
>  #ifndef APACHE_MPM_DEFAULT_H
>  #define APACHE_MPM_DEFAULT_H
>
> -#define AP_ID_FROM_CHILD_THREAD(c, t)    c
> -#define AP_CHILD_THREAD_FROM_ID(i)       i, 0
> -
> -
>  /* Number of servers to spawn off by default --- also, if fewer than
>   * this free when the caretaker checks, it will spawn more.
>   */
> @@ -82,25 +78,6 @@
>
>  #ifndef DEFAULT_MIN_FREE_DAEMON
>  #define DEFAULT_MIN_FREE_DAEMON 5
> -#endif
> -
> -/* Limit on the total --- clients will be locked out if more servers than
> - * this are needed.  It is intended solely to keep the server from crashing
> - * when things get out of hand.
> - *
> - * We keep a hard maximum number of servers, for two reasons --- first off,
> - * in case something goes seriously wrong, we want to stop the fork bomb
> - * short of actually crashing the machine we're running on by filling some
> - * kernel table.  Secondly, it keeps the size of the scoreboard file small
> - * enough that we can read the whole thing without worrying too much about
> - * the overhead.
> - */
> -#ifndef HARD_SERVER_LIMIT
> -#define HARD_SERVER_LIMIT 256
> -#endif
> -
> -#ifndef HARD_THREAD_LIMIT
> -#define HARD_THREAD_LIMIT 1
>  #endif
>
>  /* File used for accept locking, when we use a file */
> Index: server/mpm/prefork/prefork.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/mpm/prefork/prefork.c,v
> retrieving revision 1.224
> diff -u -r1.224 prefork.c
> --- server/mpm/prefork/prefork.c 2001/12/14 16:20:48 1.224
> +++ server/mpm/prefork/prefork.c 2001/12/17 22:28:04
> @@ -103,6 +103,25 @@
>  #include <signal.h>
>  #include <sys/times.h>
>
> +/* Limit on the total --- clients will be locked out if more servers than
> + * this are needed.  It is intended solely to keep the server from crashing
> + * when things get out of hand.
> + *
> + * We keep a hard maximum number of servers, for two reasons --- first off,
> + * in case something goes seriously wrong, we want to stop the fork bomb
> + * short of actually crashing the machine we're running on by filling some
> + * kernel table.  Secondly, it keeps the size of the scoreboard file small
> + * enough that we can read the whole thing without worrying too much about
> + * the overhead.
> + */
> +#ifndef HARD_SERVER_LIMIT
> +#define HARD_SERVER_LIMIT 256
> +#endif
> +
> +#ifndef HARD_THREAD_LIMIT
> +#define HARD_THREAD_LIMIT 1
> +#endif
> +
>  /* config globals */
>
>  int ap_threads_per_child=0;         /* Worker threads per child */
> @@ -343,7 +362,7 @@
>          ap_sync_scoreboard_image();
>   if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
>   kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
> -     ap_update_child_status(AP_CHILD_THREAD_FROM_ID(n), SERVER_DEAD, NULL);
> +     ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL);
>       /* just mark it as having a successful exit status */
>              *status = APR_PROC_EXIT;
>              *exitcode = 0;
> @@ -549,6 +568,7 @@
>      apr_pollfd_t *pollset;
>      int offset;
>      void *csd;
> +    void *sbh;
>
>      my_child_num = child_num_arg;
>      ap_my_pid = getpid();
> @@ -571,8 +591,10 @@
>      }
>
>      ap_run_child_init(pchild, ap_server_conf);
> +
> +    ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
>
> -    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY,
(request_rec *) NULL);
> +    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
>
>      ap_sync_scoreboard_image();
>
> @@ -602,7 +624,7 @@
>       clean_child_exit(0);
>   }
>
> - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY,
(request_rec *) NULL);
> + (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
>
>   /*
>   * Wait for an acceptable connection to arrive.
> @@ -679,7 +701,7 @@
>   * socket options, file descriptors, and read/write buffers.
>   */
>
> - current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num);
> + current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num,
sbh);
>          if (current_conn) {
>              ap_process_connection(current_conn);
>              ap_lingering_close(current_conn);
> @@ -720,7 +742,8 @@
>   child_main(slot);
>      }
>
> -    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_STARTING,
(request_rec *) NULL);
> +    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
> +                                               (request_rec *) NULL);
>
>
>  #ifdef _OSD_POSIX
> @@ -736,7 +759,8 @@
>   /* fork didn't succeed. Fix the scoreboard or else
>   * it will say SERVER_STARTING forever and ever
>   */
> - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_DEAD, (request_rec
*) NULL);
> + (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
> +                                                   (request_rec *) NULL);
>
>   /* In case system resources are maxxed out, we don't want
>      Apache running away with the CPU trying to fork over and
> @@ -1029,8 +1053,8 @@
>       ap_sync_scoreboard_image();
>       child_slot = find_child_by_pid(&pid);
>       if (child_slot >= 0) {
> - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(child_slot), SERVER_DEAD,
> -     (request_rec *) NULL);
> + (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
> +                                                           (request_rec *) NULL);
>   if (remaining_children_to_start
>       && child_slot < ap_daemons_limit) {
>       /* we're still doing a 1-for-1 replacement of dead
> Index: server/mpm/worker/mpm_default.h
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/mpm_default.h,v
> retrieving revision 1.2
> diff -u -r1.2 mpm_default.h
> --- server/mpm/worker/mpm_default.h 2001/09/24 23:03:42 1.2
> +++ server/mpm/worker/mpm_default.h 2001/12/17 22:28:04
> @@ -59,9 +59,6 @@
>  #ifndef APACHE_MPM_DEFAULT_H
>  #define APACHE_MPM_DEFAULT_H
>
> -#define AP_ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_THREAD_LIMIT) + t)
> -#define AP_CHILD_THREAD_FROM_ID(i)    (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT)
> -
>  /* Number of servers to spawn off by default --- also, if fewer than
>   * this free when the caretaker checks, it will spawn more.
>   */
> @@ -81,32 +78,6 @@
>
>  #ifndef DEFAULT_MIN_FREE_DAEMON
>  #define DEFAULT_MIN_FREE_DAEMON 3
> -#endif
> -
> -/* Limit on the total --- clients will be locked out if more servers than
> - * this are needed.  It is intended solely to keep the server from crashing
> - * when things get out of hand.
> - *
> - * We keep a hard maximum number of servers, for two reasons --- first off,
> - * in case something goes seriously wrong, we want to stop the fork bomb
> - * short of actually crashing the machine we're running on by filling some
> - * kernel table.  Secondly, it keeps the size of the scoreboard file small
> - * enough that we can read the whole thing without worrying too much about
> - * the overhead.
> - */
> -#ifndef HARD_SERVER_LIMIT
> -#define HARD_SERVER_LIMIT 16
> -#endif
> -
> -/* Limit on the threads per process.  Clients will be locked out if more than
> - * this  * HARD_SERVER_LIMIT are needed.
> - *
> - * We keep this for one reason it keeps the size of the scoreboard file small
> - * enough that we can read the whole thing without worrying too much about
> - * the overhead.
> - */
> -#ifndef HARD_THREAD_LIMIT
> -#define HARD_THREAD_LIMIT 64
>  #endif
>
>  #ifndef DEFAULT_THREADS_PER_CHILD
> Index: server/mpm/worker/worker.c
> ===================================================================
> RCS file: /home/cvspublic/httpd-2.0/server/mpm/worker/worker.c,v
> retrieving revision 1.47
> diff -u -r1.47 worker.c
> --- server/mpm/worker/worker.c 2001/12/14 16:29:43 1.47
> +++ server/mpm/worker/worker.c 2001/12/17 22:28:06
> @@ -110,6 +110,32 @@
>  #include <signal.h>
>  #include <limits.h>             /* for INT_MAX */
>
> +/* Limit on the total --- clients will be locked out if more servers than
> + * this are needed.  It is intended solely to keep the server from crashing
> + * when things get out of hand.
> + *
> + * We keep a hard maximum number of servers, for two reasons --- first off,
> + * in case something goes seriously wrong, we want to stop the fork bomb
> + * short of actually crashing the machine we're running on by filling some
> + * kernel table.  Secondly, it keeps the size of the scoreboard file small
> + * enough that we can read the whole thing without worrying too much about
> + * the overhead.
> + */
> +#ifndef HARD_SERVER_LIMIT
> +#define HARD_SERVER_LIMIT 16
> +#endif
> +
> +/* Limit on the threads per process.  Clients will be locked out if more than
> + * this  * HARD_SERVER_LIMIT are needed.
> + *
> + * We keep this for one reason it keeps the size of the scoreboard file small
> + * enough that we can read the whole thing without worrying too much about
> + * the overhead.
> + */
> +#ifndef HARD_THREAD_LIMIT
> +#define HARD_THREAD_LIMIT 64
> +#endif
> +
>  /*
>   * Actual definitions of config globals
>   */
> @@ -141,6 +167,8 @@
>      apr_threadattr_t *threadattr;
>  } thread_starter;
>
> +#define ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_THREAD_LIMIT) + t)
> +
>  /*
>   * The max child slot ever assigned, preserved across restarts.  Necessary
>   * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts.  We
> @@ -495,9 +523,11 @@
>                             int my_thread_num)
>  {
>      conn_rec *current_conn;
> -    long conn_id = AP_ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
> +    long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
>      int csd;
> +    void *sbh;
>
> +    ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
>      apr_os_sock_get(&csd, sock);
>
>      if (csd >= FD_SETSIZE) {
> @@ -510,7 +540,7 @@
>          return;
>      }
>
> -    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id);
> +    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, sbh);
>      if (current_conn) {
>          ap_process_connection(current_conn);
>          ap_lingering_close(current_conn);
> @@ -694,9 +724,9 @@
>          }
>      }
>
> -    ap_update_child_status(process_slot, thread_slot,
> -                           (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
> -                           (request_rec *) NULL);
> +    ap_update_child_status_from_indexes(process_slot, thread_slot,
> +                                        (dying) ? SERVER_DEAD : SERVER_GRACEFUL,
> +                                        (request_rec *) NULL);
>      dying = 1;
>      ap_scoreboard_image->parent[process_slot].quiescing = 1;
>      kill(ap_my_pid, SIGTERM);
> @@ -718,9 +748,9 @@
>
>      free(ti);
>
> -    ap_update_child_status(process_slot, thread_slot, SERVER_STARTING, NULL);
> +    ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING,
NULL);
>      while (!workers_may_exit) {
> -        ap_update_child_status(process_slot, thread_slot, SERVER_READY, NULL);
> +        ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY,
NULL);
>          rv = ap_queue_pop(worker_queue, &csd, &ptrans);
>          /* We get FD_QUEUE_EINTR whenever ap_queue_pop() has been interrupted
>           * from an explicit call to ap_queue_interrupt_all(). This allows
> @@ -734,7 +764,7 @@
>          apr_pool_destroy(ptrans);
>      }
>
> -    ap_update_child_status(process_slot, thread_slot,
> +    ap_update_child_status_from_indexes(process_slot, thread_slot,
>          (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);
>      apr_thread_mutex_lock(worker_thread_count_mutex);
>      worker_thread_count--;
> @@ -797,7 +827,7 @@
>              my_info->sd = 0;
>
>                /* We are creating threads right now */
> -            ap_update_child_status(my_child_num, i, SERVER_STARTING, NULL);
> +            ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
NULL);
>              /* We let each thread update its own scoreboard entry.  This is
>               * done because it lets us deal with tid better.
>               */
> @@ -821,8 +851,8 @@
>
>      /* What state should this child_main process be listed as in the
>       * scoreboard...?
> -     *  ap_update_child_status(my_child_num, i, SERVER_STARTING,
> -     *                         (request_rec *) NULL);
> +     *  ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
> +     *                                      (request_rec *) NULL);
>       *
>       *  This state should be listed separately in the scoreboard, in some kind
>       *  of process_status, not mixed in with the worker threads' status.
> @@ -965,7 +995,7 @@
>          /* fork didn't succeed. Fix the scoreboard or else
>           * it will say SERVER_STARTING forever and ever
>           */
> -        ap_update_child_status(slot, 0, SERVER_DEAD, NULL);
> +        ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, NULL);
>
>          /* In case system resources are maxxed out, we don't want
>             Apache running away with the CPU trying to fork over and
> @@ -1222,8 +1252,8 @@
>              child_slot = find_child_by_pid(&pid);
>              if (child_slot >= 0) {
>                  for (i = 0; i < ap_threads_per_child; i++)
> -                    ap_update_child_status(child_slot, i, SERVER_DEAD,
> -                                           (request_rec *) NULL);
> +                    ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
> +                                                        (request_rec *) NULL);
>
>                  ap_scoreboard_image->parent[child_slot].pid = 0;
>                  ap_scoreboard_image->parent[child_slot].quiescing = 0;
>
> --
> Jeff Trawick | trawick@attglobal.net | PGP public key at web site:
>        http://www.geocities.com/SiliconValley/Park/9289/
>              Born in Roswell... married an alien...
>