You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rb...@apache.org on 2001/02/01 22:55:18 UTC

cvs commit: httpd-2.0/server/mpm/spmt_os2 scoreboard.h

rbb         01/02/01 13:55:17

  Modified:    .        CHANGES
               modules/generators mod_status.c
               modules/http http_protocol.c
               server   Makefile.in config.m4 connection.c
               server/mpm/beos Makefile.in
               server/mpm/dexter Makefile.in dexter.c mpm.h mpm_default.h
               server/mpm/mpmt_beos Makefile.in
               server/mpm/mpmt_pthread Makefile.in config.m4 mpm.h
                        mpm_default.h mpmt_pthread.c
               server/mpm/perchild Makefile.in
               server/mpm/prefork config.m4 mpm.h mpm_default.h prefork.c
  Added:       include  scoreboard.h
               server   scoreboard.c
  Removed:     include  mpm_status.h
               server/mpm/beos scoreboard.c scoreboard.h
               server/mpm/dexter scoreboard.c scoreboard.h
               server/mpm/mpmt_beos scoreboard.c scoreboard.h
               server/mpm/mpmt_pthread scoreboard.c scoreboard.h
               server/mpm/perchild scoreboard.c scoreboard.h
               server/mpm/prefork scoreboard.h
               server/mpm/spmt_os2 scoreboard.h
  Log:
  Bring mod_status for 2.0 back in line with mod_status for 1.3.  This is
  basically a straight port of the 1.3 module to 2.0.  The MPMs need to be
  modified a bit to work with mod_status, but prefork, mpmt_pthread, and
  dexter have already been changed.  I will fix perchild tonight.  There
  is a lot of common code that can be abstracted, and there seems to be a
  small bug with regard to what mpmt_pthread and dexter report as current
  connections.  ExtendedStatus does work again, although until the bug
  mentioned above is fixed, it isn't as useful on mpmt_pthread and dexter.
  
  Next week, I will look at allowing other modules to add data to the
  STATUS page and possibly to the scoreboard itself.
  
  Revision  Changes    Path
  1.71      +3 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.70
  retrieving revision 1.71
  diff -u -d -b -w -u -r1.70 -r1.71
  --- CHANGES	2001/02/01 10:24:08	1.70
  +++ CHANGES	2001/02/01 21:54:06	1.71
  @@ -1,5 +1,8 @@
   Changes with Apache 2.0b1
   
  +  *) Make mod_status work with 2.0.  This will work for prefork,
  +     mpmt_pthread, and dexter.  [Ryan Bloom]
  +
     *) Correct a typo in httpd.conf.
        [Kunihiro Tanaka <ta...@apache.or.jp>] PR#7154 
   
  
  
  
  1.1                  httpd-2.0/include/scoreboard.h
  
  Index: scoreboard.h
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  
  #ifndef APACHE_SCOREBOARD_H
  #define APACHE_SCOREBOARD_H
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  #ifdef HAVE_SYS_TIMES_H
  #include <sys/time.h>
  #include <sys/times.h>
  #elif defined(TPF)
  #include <time.h>
  #endif
  
  #include "mpm_default.h"	/* For HARD_.*_LIMIT */
  #include "apr_thread_proc.h"
  
  /*The optimized timeout code only works if we're not using a scoreboard file*/
  #if defined(AP_USE_MEM_BASED_SCOREBOARD)
  #define OPTIMIZE_TIMEOUTS
  #endif
  
  /* Scoreboard info on a process is, for now, kept very brief --- 
   * just status value and pid (the latter so that the caretaker process
   * can properly update the scoreboard when a process dies).  We may want
   * to eventually add a separate set of long_score structures which would
   * give, for each process, the number of requests serviced, and info on
   * the current, or most recent, request.
   *
   * Status values:
   */
  
  #define SERVER_DEAD 0
  #define SERVER_STARTING 1	/* Server Starting up */
  #define SERVER_READY 2		/* Waiting for connection (or accept() lock) */
  #define SERVER_BUSY_READ 3	/* Reading a client request */
  #define SERVER_BUSY_WRITE 4	/* Processing a client request */
  #define SERVER_BUSY_KEEPALIVE 5	/* Waiting for more requests via keepalive */
  #define SERVER_BUSY_LOG 6	/* Logging the request */
  #define SERVER_BUSY_DNS 7	/* Looking up a hostname */
  #define SERVER_GRACEFUL 8	/* server is gracefully finishing request */
  #define SERVER_ACCEPTING 9	/* thread is accepting connections */
  #define SERVER_QUEUEING	10      /* thread is putting connection on the queue */
  #define SERVER_NUM_STATUS 11	/* number of status settings */
  
  /* A "virtual time" is simply a counter that indicates that a child is
   * making progress.  The parent checks up on each child, and when they have
   * made progress it resets the last_rtime element.  But when the child hasn't
   * made progress in a time that's roughly timeout_len seconds long, it is
   * sent a SIGALRM.
   *
   * vtime is an optimization that is used only when the scoreboard is in
   * shared memory (it's not easy/feasible to do it in a scoreboard file).
   * The essential observation is that timeouts rarely occur, the vast majority
   * of hits finish before any timeout happens.  So it really sucks to have to
   * ask the operating system to set up and destroy alarms many times during
   * a request.
   */
  typedef unsigned vtime_t;
  
  /* Type used for generation indicies.  Startup and every restart cause a
   * new generation of children to be spawned.  Children within the same
   * generation share the same configuration information -- pointers to stuff
   * created at config time in the parent are valid across children.  For
   * example, the vhostrec pointer in the scoreboard below is valid in all
   * children of the same generation.
   *
   * The safe way to access the vhost pointer is like this:
   *
   * short_score *ss = pointer to whichver slot is interesting;
   * parent_score *ps = pointer to whichver slot is interesting;
   * server_rec *vh = ss->vhostrec;
   *
   * if (ps->generation != ap_my_generation) {
   *     vh = NULL;
   * }
   *
   * then if vh is not NULL it's valid in this child.
   *
   * This avoids various race conditions around restarts.
   */
  typedef int ap_generation_t;
  
  /* stuff which is thread/process specific */
  typedef struct {
  #ifdef OPTIMIZE_TIMEOUTS
      vtime_t cur_vtime;		/* the child's current vtime */
      unsigned short timeout_len;	/* length of the timeout */
  #endif
      int thread_num;
      unsigned char status;
      unsigned long access_count;
      unsigned long bytes_served;
      unsigned long my_access_count;
      unsigned long my_bytes_served;
      unsigned long conn_bytes;
      unsigned short conn_count;
      apr_time_t start_time;
      apr_time_t stop_time;
  #ifdef HAVE_TIMES
      struct tms times;
  #endif
  #ifndef OPTIMIZE_TIMEOUTS
      time_t last_used;
  #endif
      char client[32];		/* Keep 'em small... */
      char request[64];		/* We just want an idea... */
      server_rec *vhostrec;	/* What virtual host is being accessed? */
                                  /* SEE ABOVE FOR SAFE USAGE! */
  } short_score;
  
  typedef struct {
      ap_generation_t running_generation;	/* the generation of children which
                                           * should still be serving requests. */
  } global_score;
  
  /* stuff which the parent generally writes and the children rarely read */
  typedef struct {
      pid_t pid;
      ap_generation_t generation;	/* generation of this child */
      int worker_threads;
  #ifdef OPTIMIZE_TIMEOUTS
      time_t last_rtime;		/* time(0) of the last change */
      vtime_t last_vtime;		/* the last vtime the parent has seen */
  #endif
  } parent_score;
  
  typedef struct {
      short_score servers[HARD_SERVER_LIMIT][HARD_THREAD_LIMIT];
      parent_score parent[HARD_SERVER_LIMIT];
      global_score global;
  } scoreboard;
  
  #define KEY_LENGTH 16
  #define VALUE_LENGTH 64
  typedef struct {
      char key[KEY_LENGTH];
      char value[VALUE_LENGTH];
  } status_table_entry;
  
  #define STATUSES_PER_CONNECTION 10
  
  typedef struct {
      status_table_entry
          table[HARD_SERVER_LIMIT*HARD_THREAD_LIMIT][STATUSES_PER_CONNECTION];
  } new_scoreboard;
  
  #define SCOREBOARD_SIZE		sizeof(scoreboard)
  #define NEW_SCOREBOARD_SIZE	sizeof(new_scoreboard)
  #ifdef TPF
  #define SCOREBOARD_NAME		"SCOREBRD"
  #define SCOREBOARD_FRAMES		SCOREBOARD_SIZE/4095 + 1
  #endif
  
  AP_DECLARE(int) ap_exists_scoreboard_image(void);
  void reinit_scoreboard(apr_pool_t *p);
  apr_status_t ap_cleanup_shared_mem(void *d);
  AP_DECLARE(void) ap_sync_scoreboard_image(void);
  
  AP_DECLARE(void) reopen_scoreboard(apr_pool_t *p);
  
  apr_inline void ap_sync_scoreboard_image(void);
  void increment_counts(int child_num, int thread_num, request_rec *r);
  void update_scoreboard_global(void);
  AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid);
  int ap_update_child_status(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_DATA extern scoreboard *ap_scoreboard_image;
  AP_DECLARE_DATA extern const char *ap_scoreboard_fname;
  AP_DECLARE_DATA extern int ap_extended_status;
  AP_DECLARE_DATA apr_time_t ap_restart_time;
  
  AP_DECLARE_DATA extern ap_generation_t volatile ap_my_generation;
  
  /* for time_process_request() in http_main.c */
  #define START_PREQUEST 1
  #define STOP_PREQUEST  2
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif	/* !APACHE_SCOREBOARD_H */
  
  
  
  1.19      +669 -35   httpd-2.0/modules/generators/mod_status.c
  
  Index: mod_status.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/generators/mod_status.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -d -b -w -u -r1.18 -r1.19
  --- mod_status.c	2001/01/27 23:29:39	1.18
  +++ mod_status.c	2001/02/01 21:54:14	1.19
  @@ -56,11 +56,74 @@
    * University of Illinois, Urbana-Champaign.
    */
   
  +/* Status Module.  Display lots of internal data about how Apache is
  + * performing and the state of all children processes.
  + *
  + * To enable this, add the following lines into any config file:
  + *
  + * <Location /server-status>
  + * SetHandler server-status
  + * </Location>
  + *
  + * You may want to protect this location by password or domain so no one
  + * else can look at it.  Then you can access the statistics with a URL like:
  + *
  + * http://your_server_name/server-status
  + *
  + * /server-status - Returns page using tables
  + * /server-status?notable - Returns page for browsers without table support
  + * /server-status?refresh - Returns page with 1 second refresh
  + * /server-status?refresh=6 - Returns page with refresh every 6 seconds
  + * /server-status?auto - Returns page with data for automatic parsing
  + *
  + * Mark Cox, mark@ukweb.com, November 1995
  + *
  + * 12.11.95 Initial version for www.telescope.org
  + * 13.3.96  Updated to remove rprintf's [Mark]
  + * 18.3.96  Added CPU usage, process information, and tidied [Ben Laurie]
  + * 18.3.96  Make extra Scoreboard variables #definable
  + * 25.3.96  Make short report have full precision [Ben Laurie suggested]
  + * 25.3.96  Show uptime better [Mark/Ben Laurie]
  + * 29.3.96  Better HTML and explanation [Mark/Rob Hartill suggested]
  + * 09.4.96  Added message for non-STATUS compiled version
  + * 18.4.96  Added per child and per slot counters [Jim Jagielski]
  + * 01.5.96  Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.]
  + * 18.5.96  Adapted to use new rprintf() routine, incidentally fixing a missing
  + *          piece in short reports [Ben Laurie]
  + * 21.5.96  Additional Status codes (DNS and LOGGING only enabled if
  + *          extended STATUS is enabled) [George Burgyan/Jim J.]
  + * 10.8.98  Allow for extended status info at runtime (no more STATUS)
  + *          [Jim J.]
  + */
  +
  +#define CORE_PRIVATE
   #include "httpd.h"
   #include "http_config.h"
   #include "http_core.h"
   #include "http_protocol.h"
  -#include "mpm_status.h"
  +#include "http_main.h"
  +#include "util_script.h"
  +#include <time.h>
  +#include "scoreboard.h"
  +#include "http_log.h"
  +
  +#ifdef NEXT
  +#if (NX_CURRENT_COMPILER_RELEASE == 410)
  +#ifdef m68k
  +#define HZ 64
  +#else
  +#define HZ 100
  +#endif
  +#else
  +#include <machine/param.h>
  +#endif
  +#endif /* NEXT */
  +
  +#define STATUS_MAXLINE		64
  +
  +#define KBYTE			1024
  +#define	MBYTE			1048576L
  +#define	GBYTE			1073741824L
   
   #ifndef DEFAULT_TIME_FORMAT 
   #define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
  @@ -70,39 +133,221 @@
   
   module AP_MODULE_DECLARE_DATA status_module;
   
  -static int print_status_value(void *data, const char *key, const char *val)
  +/*
  + *command-related code. This is here to prevent use of ExtendedStatus
  + * without status_module included.
  + */
  +static const char *set_extended_status(cmd_parms *cmd, void *dummy, int arg) 
   {
  -    request_rec *r = (request_rec *) data;
  +    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
  +    if (err != NULL) {
  +        return err;
  +    }
  +    ap_extended_status = arg;
  +    return NULL;
  +}
   
  -    ap_rprintf(r, "<dt>%s\n<dd>%s\n", key, val);
  -    return 1;
  +static const command_rec status_module_cmds[] =
  +{
  +    AP_INIT_FLAG("ExtendedStatus", set_extended_status, NULL, RSRC_CONF,
  +      "\"On\" to enable extended status information, \"Off\" to disable"),
  +    {NULL}
  +};
  +
  +/* Format the number of bytes nicely */
  +static void format_byte_out(request_rec *r, unsigned long bytes)
  +{
  +    if (bytes < (5 * KBYTE))
  +	ap_rprintf(r, "%d B", (int) bytes);
  +    else if (bytes < (MBYTE / 2))
  +	ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
  +    else if (bytes < (GBYTE / 2))
  +	ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
  +    else
  +	ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
  +}
  +
  +static void format_kbyte_out(request_rec *r, unsigned long kbytes)
  +{
  +    if (kbytes < KBYTE)
  +	ap_rprintf(r, "%d kB", (int) kbytes);
  +    else if (kbytes < MBYTE)
  +	ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE);
  +    else
  +	ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE);
  +}
  +
  +static void show_time(request_rec *r, time_t tsecs)
  +{
  +    long days, hrs, mins, secs;
  +
  +    secs = tsecs % 60;
  +    tsecs /= 60;
  +    mins = tsecs % 60;
  +    tsecs /= 60;
  +    hrs = tsecs % 24;
  +    days = tsecs / 24;
  +    if (days)
  +	ap_rprintf(r, " %ld day%s", days, days == 1 ? "" : "s");
  +    if (hrs)
  +	ap_rprintf(r, " %ld hour%s", hrs, hrs == 1 ? "" : "s");
  +    if (mins)
  +	ap_rprintf(r, " %ld minute%s", mins, mins == 1 ? "" : "s");
  +    if (secs)
  +	ap_rprintf(r, " %ld second%s", secs, secs == 1 ? "" : "s");
   }
   
  +/* Main handler for x-httpd-status requests */
  +
  +/* ID values for command table */
  +
  +#define STAT_OPT_END		-1
  +#define STAT_OPT_REFRESH	0
  +#define STAT_OPT_NOTABLE	1
  +#define STAT_OPT_AUTO		2
  +
  +struct stat_opt {
  +    int id;
  +    const char *form_data_str;
  +    const char *hdr_out_str;
  +};
  +
  +static const struct stat_opt status_options[] =	/* see #defines above */
  +{
  +    {STAT_OPT_REFRESH, "refresh", "Refresh"},
  +    {STAT_OPT_NOTABLE, "notable", NULL},
  +    {STAT_OPT_AUTO, "auto", NULL},
  +    {STAT_OPT_END, NULL, NULL}
  +};
  +
  +static char status_flags[SERVER_NUM_STATUS];
  +
   static int status_handler(request_rec *r)
   {
  -    int i;
  -    apr_array_header_t *server_status;
  -    ap_status_table_row_t *status_rows;
  +    const char *loc;
  +    time_t nowtime = time(NULL);
  +    time_t up_time;
  +    int j, i, res;
  +    int ready = 0;
  +    int busy = 0;
  +    unsigned long count = 0;
  +    unsigned long lres, bytes;
  +    unsigned long my_lres, my_bytes, conn_bytes;
  +    unsigned short conn_lres;
  +    unsigned long bcount = 0;
  +    unsigned long kbcount = 0;
  +    long req_time;
  +#ifndef NO_TIMES
  +#ifdef _SC_CLK_TCK
  +    float tick = sysconf(_SC_CLK_TCK);
  +#else
  +    float tick = HZ;
  +#endif
  +#endif
  +    int short_report = 0;
  +    int no_table_report = 0;
  +    short_score score_record;
  +    parent_score ps_record;
  +    char stat_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT];
  +    int pid_buffer[HARD_SERVER_LIMIT * HARD_THREAD_LIMIT];
  +    clock_t tu, ts, tcu, tcs;
  +    server_rec *vhost;
   
       if (strcmp(r->handler, STATUS_MAGIC_TYPE) && strcmp(r->handler, "server-status")) {
           return DECLINED;
       }
   
  +    tu = ts = tcu = tcs = 0;
  +
  +    if (!ap_exists_scoreboard_image()) {
  +	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
  +		    "Server status unavailable in inetd mode");
  +	return HTTP_INTERNAL_SERVER_ERROR;
  +    }
       r->allowed = (1 << M_GET);
       if (r->method_number != M_GET)
   	return DECLINED;
   
       r->content_type = "text/html";
   
  +    /*
  +     * Simple table-driven form data set parser that lets you alter the header
  +     */
  +
  +    if (r->args) {
  +	i = 0;
  +	while (status_options[i].id != STAT_OPT_END) {
  +	    if ((loc = ap_strstr_c(r->args, status_options[i].form_data_str)) != NULL) {
  +		switch (status_options[i].id) {
  +		case STAT_OPT_REFRESH:
  +		    if (*(loc + strlen(status_options[i].form_data_str)) == '='
  +                        && atol(loc + strlen(status_options[i].form_data_str) 
  +                                    + 1) > 0)
  +			apr_table_set(r->headers_out,
  +			      status_options[i].hdr_out_str,
  +			      loc + strlen(status_options[i].hdr_out_str) + 1);
  +		    else
  +			apr_table_set(r->headers_out,
  +			      status_options[i].hdr_out_str, "1");
  +		    break;
  +		case STAT_OPT_NOTABLE:
  +		    no_table_report = 1;
  +		    break;
  +		case STAT_OPT_AUTO:
  +		    r->content_type = "text/plain";
  +		    short_report = 1;
  +		    break;
  +		}
  +	    }
  +	    i++;
  +	}
  +    }
  +
       ap_send_http_header(r);
   
       if (r->header_only)
   	return 0;
   
  -    server_status = ap_get_status_table(r->pool);
  +    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;
  +
  +	    score_record = ap_scoreboard_image->servers[i][j];
  +	    ps_record = ap_scoreboard_image->parent[i];
  +	    res = score_record.status;
  +	    stat_buffer[indx] = status_flags[res];
  +	    pid_buffer[indx] = (int) ps_record.pid;
  +	    if (res == SERVER_READY)
  +	        ready++;
  +	    else if (res != SERVER_DEAD)
  +	        busy++;
  +	    if (ap_extended_status) {
  +	        lres = score_record.access_count;
  +	        bytes = score_record.bytes_served;
  +	        if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) {
  +#ifndef NO_TIMES
  +		    tu += score_record.times.tms_utime;
  +		    ts += score_record.times.tms_stime;
  +		    tcu += score_record.times.tms_cutime;
  +		    tcs += score_record.times.tms_cstime;
  +#endif /* NO_TIMES */
  +		    count += lres;
  +		    bcount += bytes;
  +		    if (bcount >= KBYTE) {
  +		        kbcount += (bcount >> 10);
  +		        bcount = bcount & 0x3ff;
  +		    }
  +	        }
  +	    }
  +        }
  +    }
  +
  +    up_time = nowtime - ap_restart_time;
   
  +    if (!short_report) {
       ap_rputs(DOCTYPE_HTML_3_2
  -    	 "<html><head>\n<title>Apache Status</title>\n</head><body>\n",
  +		 "<HTML><HEAD>\n<TITLE>Apache Status</TITLE>\n</HEAD><BODY>\n",
       	 r);
       ap_rputs("<H1>Apache Server Status for ", r);
       ap_rvputs(r, ap_get_server_name(r), "</H1>\n\n", NULL);
  @@ -111,35 +356,424 @@
       ap_rvputs(r, "Server Built: ",
         ap_get_server_built(), "<br>\n<hr>\n", NULL);
       ap_rvputs(r, "Current Time: ",
  -      ap_ht_time(r->pool, apr_now(), DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL);
  +	  ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL);
  +	ap_rvputs(r, "Restart Time: ",
  +	  ap_ht_time(r->pool, ap_restart_time, DEFAULT_TIME_FORMAT, 0), 
  +	  "<br>\n", NULL);
  +	ap_rprintf(r, "Parent Server Generation: %d <br>\n", (int) ap_my_generation);
  +	ap_rputs("Server uptime: ", r);
  +	show_time(r, up_time);
  +	ap_rputs("<br>\n", r);
  +    }
       
  -    if (server_status) {
  -        ap_rprintf(r, "\n%d connections currently being processed\n",
  -                   server_status->nelts);
  +    if (ap_extended_status) {
  +	if (short_report) {
  +	    ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %lu\n",
  +		count, kbcount);
   
  -        status_rows = (ap_status_table_row_t *) server_status->elts;
  -        for (i = 0; i < server_status->nelts; i++) {
  -	    ap_rprintf(r, "<h2>Connection %ld</h2>\n", status_rows[i].conn_id);
  -            apr_table_do(print_status_value, (void *) r, status_rows[i].data, 
  -                         NULL);
  +#ifndef NO_TIMES
  +	    /* Allow for OS/2 not having CPU stats */
  +	    if (ts || tu || tcu || tcs)
  +		ap_rprintf(r, "CPULoad: %g\n",
  +		    (tu + ts + tcu + tcs) / tick / up_time * 100.);
  +#endif
  +
  +	    ap_rprintf(r, "Uptime: %ld\n", (long) (up_time));
  +	    if (up_time > 0)
  +		ap_rprintf(r, "ReqPerSec: %g\n",
  +		    (float) count / (float) up_time);
  +
  +	    if (up_time > 0)
  +		ap_rprintf(r, "BytesPerSec: %g\n",
  +		    KBYTE * (float) kbcount / (float) up_time);
  +
  +	    if (count > 0)
  +		ap_rprintf(r, "BytesPerReq: %g\n",
  +		    KBYTE * (float) kbcount / (float) count);
  +	}
  +	else {			/* !short_report */
  +	    ap_rprintf(r, "Total accesses: %lu - Total Traffic: ", count);
  +	    format_kbyte_out(r, kbcount);
  +
  +#ifndef NO_TIMES
  +	    /* Allow for OS/2 not having CPU stats */
  +	    ap_rputs("<br>\n", r);
  +	    ap_rprintf(r, "CPU Usage: u%g s%g cu%g cs%g",
  +		    tu / tick, ts / tick, tcu / tick, tcs / tick);
  +
  +	    if (ts || tu || tcu || tcs)
  +		ap_rprintf(r, " - %.3g%% CPU load",
  +		    (tu + ts + tcu + tcs) / tick / up_time * 100.);
  +#endif
  +
  +	    ap_rputs("<br>\n", r);
  +
  +	    if (up_time > 0)
  +		ap_rprintf(r, "%.3g requests/sec - ",
  +			(float) count / (float) up_time);
  +
  +	    if (up_time > 0) {
  +		format_byte_out(r, KBYTE * (float) kbcount / (float) up_time);
  +		ap_rputs("/second - ", r);
           }
  +
  +	    if (count > 0) {
  +		format_byte_out(r, KBYTE * (float) kbcount / (float) count);
  +		ap_rputs("/request", r);
       }
  -    ap_rputs("</body></html>\n", r);
  +
  +	    ap_rputs("<br>\n", r);
  +	}				/* short_report */
  +    }					/* ap_extended_status */
  +
  +    if (!short_report)
  +	ap_rprintf(r, "\n%d requests currently being processed, %d idle servers\n"
  +		,busy, ready);
  +    else
  +	ap_rprintf(r, "BusyServers: %d\nIdleServers: %d\n", busy, ready);
  +
  +    /* send the scoreboard 'table' out */
  +
  +    if (!short_report)
  +	ap_rputs("<PRE>", r);
  +    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;
  +	    ap_rputc(stat_buffer[indx], r);
  +	    if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1)) && !short_report)
  +	        ap_rputs("\n", r);
  +        }
  +    }
  +
  +    if (short_report)
  +	ap_rputs("\n", r);
  +    else {
  +	ap_rputs("</PRE>\n", r);
  +	ap_rputs("Scoreboard Key: <br>\n", r);
  +	ap_rputs("\"<B><code>_</code></B>\" Waiting for Connection, \n", r);
  +	ap_rputs("\"<B><code>S</code></B>\" Starting up, \n", r);
  +	ap_rputs("\"<B><code>R</code></B>\" Reading Request,<BR>\n", r);
  +	ap_rputs("\"<B><code>W</code></B>\" Sending Reply, \n", r);
  +	ap_rputs("\"<B><code>K</code></B>\" Keepalive (read), \n", r);
  +	ap_rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n", r);
  +	ap_rputs("\"<B><code>L</code></B>\" Logging, \n", r);
  +	ap_rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n", r);
  +	ap_rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n", r);
  +	ap_rputs("<P>\n", r);
  +	if (!ap_extended_status) {
  +	    int j = 0;
  +            int k;
  +	    ap_rputs("PID Key: <br>\n", r);
  +	    ap_rputs("<PRE>\n", r);
  +	    for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  +                for (k = 0; k < HARD_THREAD_LIMIT; ++k) {
  +                    int indx = (i * HARD_THREAD_LIMIT) + j;
  +
  +		    if (stat_buffer[indx] != '.') {
  +		        ap_rprintf(r, "   %d in state: %c ", pid_buffer[i],
  +		        stat_buffer[indx]);
  +		        if (++j >= 3) {
  +		    	    ap_rputs("\n", r);
  +			    j = 0;
  +		        } else
  +		    	    ap_rputs(",", r);
  +		    }
  +                }
  +	    }
  +	    ap_rputs("\n", r);
  +	    ap_rputs("</PRE>\n", r);
  +	}
  +    }
  +
  +    if (ap_extended_status) {
  +	if (!short_report) {
  +	    if (no_table_report)
  +		ap_rputs("<p><hr><h2>Server Details</h2>\n\n", r);
  +	    else
  +#ifdef NO_TIMES
  +		/* Allow for OS/2 not having CPU stats */
  +		ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r);
  +#else
  +		ap_rputs("<p>\n\n<table border=0><tr><th>Srv<th>PID<th>Acc<th>M<th>CPU\n<th>SS<th>Req<th>Conn<th>Child<th>Slot<th>Client<th>VHost<th>Request</tr>\n\n", r);
  +#endif
  +	}
  +
  +	for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  +	for (j = 0; j < HARD_THREAD_LIMIT; ++j) {
  +	    score_record = ap_scoreboard_image->servers[i][j];
  +	    ps_record = ap_scoreboard_image->parent[i];
  +	    vhost = score_record.vhostrec;
  +	    if (ps_record.generation != ap_my_generation) {
  +		vhost = NULL;
  +	    }
  +
  +#if defined(NO_GETTIMEOFDAY)
  +#ifndef NO_TIMES
  +	    if (score_record.start_time == (clock_t) 0)
  +#endif /* NO_TIMES */
  +		req_time = 0L;
  +#ifndef NO_TIMES
  +	    else {
  +		req_time = score_record.stop_time - score_record.start_time;
  +		req_time = (req_time * 1000) / (int) tick;
  +	    }
  +#endif /* NO_TIMES */
  +#else
  +	    if (score_record.start_time == 0L &&
  +		score_record.start_time == 0L)
  +		req_time = 0L;
  +	    else
  +		req_time =
  +		    ((score_record.stop_time - score_record.start_time) * 1000) +
  +		    ((score_record.stop_time - score_record.start_time) / 1000);
  +#endif
  +	    if (req_time < 0L)
  +		req_time = 0L;
  +
  +	    lres = score_record.access_count;
  +	    my_lres = score_record.my_access_count;
  +	    conn_lres = score_record.conn_count;
  +	    bytes = score_record.bytes_served;
  +	    my_bytes = score_record.my_bytes_served;
  +	    conn_bytes = score_record.conn_bytes;
  +	    if (lres != 0 || (score_record.status != SERVER_READY
  +			      && score_record.status != SERVER_DEAD)) {
  +		if (!short_report) {
  +		    if (no_table_report) {
  +			if (score_record.status == SERVER_DEAD)
  +			    ap_rprintf(r,
  +				"<b>Server %d-%d</b> (-): %d|%lu|%lu [",
  +				i, (int) ps_record.generation, (int) conn_lres,
  +				my_lres, lres);
  +			else
  +			    ap_rprintf(r,
  +				"<b>Server %d-%d</b> (%d): %d|%lu|%lu [",
  +				i, (int) ps_record.generation,
  +				(int) ps_record.pid,
  +				(int) conn_lres, my_lres, lres);
  +
  +			switch (score_record.status) {
  +			case SERVER_READY:
  +			    ap_rputs("Ready", r);
  +			    break;
  +			case SERVER_STARTING:
  +			    ap_rputs("Starting", r);
  +			    break;
  +			case SERVER_BUSY_READ:
  +			    ap_rputs("<b>Read</b>", r);
  +			    break;
  +			case SERVER_BUSY_WRITE:
  +			    ap_rputs("<b>Write</b>", r);
  +			    break;
  +			case SERVER_BUSY_KEEPALIVE:
  +			    ap_rputs("<b>Keepalive</b>", r);
  +			    break;
  +			case SERVER_BUSY_LOG:
  +			    ap_rputs("<b>Logging</b>", r);
  +			    break;
  +			case SERVER_BUSY_DNS:
  +			    ap_rputs("<b>DNS lookup</b>", r);
  +			    break;
  +			case SERVER_DEAD:
  +			    ap_rputs("Dead", r);
  +			    break;
  +			case SERVER_GRACEFUL:
  +			    ap_rputs("Graceful", r);
  +			    break;
  +			default:
  +			    ap_rputs("?STATE?", r);
  +			    break;
  +			}
  +#ifdef NO_TIMES
  +			/* Allow for OS/2 not having CPU stats */
  +			ap_rprintf(r, "]\n %.0f %ld (",
  +#else
  +
  +			ap_rprintf(r, "] u%g s%g cu%g cs%g\n %.0f %ld (",
  +			    score_record.times.tms_utime / tick,
  +			    score_record.times.tms_stime / tick,
  +			    score_record.times.tms_cutime / tick,
  +			    score_record.times.tms_cstime / tick,
  +#endif
  +#ifdef OPTIMIZE_TIMEOUTS
  +			    difftime(nowtime, ps_record.last_rtime),
  +#else
  +			    difftime(nowtime, score_record.last_used),
  +#endif
  +			    (long) req_time);
  +			format_byte_out(r, conn_bytes);
  +			ap_rputs("|", r);
  +			format_byte_out(r, my_bytes);
  +			ap_rputs("|", r);
  +			format_byte_out(r, bytes);
  +			ap_rputs(")\n", r);
  +			ap_rprintf(r, " <i>%s {%s}</i> <b>[%s]</b><br>\n\n",
  +			    ap_escape_html(r->pool, score_record.client),
  +			    ap_escape_html(r->pool, score_record.request),
  +			    vhost ? ap_escape_html(r->pool, 
  +				vhost->server_hostname) : "(unavailable)");
  +		    }
  +		    else {		/* !no_table_report */
  +			if (score_record.status == SERVER_DEAD)
  +			    ap_rprintf(r,
  +				"<tr><td><b>%d-%d</b><td>-<td>%d/%lu/%lu",
  +				i, (int) ps_record.generation,
  +				(int) conn_lres, my_lres, lres);
  +			else
  +			    ap_rprintf(r,
  +				"<tr><td><b>%d-%d</b><td>%d<td>%d/%lu/%lu",
  +				i, (int) ps_record.generation,
  +				(int) ps_record.pid, (int) conn_lres,
  +				my_lres, lres);
  +
  +			switch (score_record.status) {
  +			case SERVER_READY:
  +			    ap_rputs("<td>_", r);
  +			    break;
  +			case SERVER_STARTING:
  +			    ap_rputs("<td><b>S</b>", r);
  +			    break;
  +			case SERVER_BUSY_READ:
  +			    ap_rputs("<td><b>R</b>", r);
  +			    break;
  +			case SERVER_BUSY_WRITE:
  +			    ap_rputs("<td><b>W</b>", r);
  +			    break;
  +			case SERVER_BUSY_KEEPALIVE:
  +			    ap_rputs("<td><b>K</b>", r);
  +			    break;
  +			case SERVER_BUSY_LOG:
  +			    ap_rputs("<td><b>L</b>", r);
  +			    break;
  +			case SERVER_BUSY_DNS:
  +			    ap_rputs("<td><b>D</b>", r);
  +			    break;
  +			case SERVER_DEAD:
  +			    ap_rputs("<td>.", r);
  +			    break;
  +			case SERVER_GRACEFUL:
  +			    ap_rputs("<td>G", r);
  +			    break;
  +			default:
  +			    ap_rputs("<td>?", r);
  +			    break;
  +			}
  +#ifdef NO_TIMES
  +			/* Allow for OS/2 not having CPU stats */
  +			ap_rprintf(r, "\n<td>%.0f<td>%ld",
  +#else
  +			ap_rprintf(r, "\n<td>%.2f<td>%.0f<td>%ld",
  +			    (score_record.times.tms_utime +
  +			     score_record.times.tms_stime +
  +			     score_record.times.tms_cutime +
  +			     score_record.times.tms_cstime) / tick,
  +#endif
  +#ifdef OPTIMIZE_TIMEOUTS
  +			    difftime(nowtime, ps_record.last_rtime),
  +#else
  +			    difftime(nowtime, score_record.last_used),
  +#endif
  +			    (long) req_time);
  +			ap_rprintf(r, "<td>%-1.1f<td>%-2.2f<td>%-2.2f\n",
  +			   (float) conn_bytes / KBYTE, (float) my_bytes / MBYTE,
  +			    (float) bytes / MBYTE);
  +			if (score_record.status == SERVER_BUSY_READ)
  +			    ap_rprintf(r,
  +			     "<td>?<td nowrap>?<td nowrap>..reading.. </tr>\n\n");
  +			else
  +			    ap_rprintf(r,
  +			     "<td>%s<td nowrap>%s<td nowrap>%s</tr>\n\n",
  +			     ap_escape_html(r->pool, score_record.client),
  +			     vhost ? ap_escape_html(r->pool, 
  +				vhost->server_hostname) : "(unavailable)",
  +			     ap_escape_html(r->pool, score_record.request));
  +		    }		/* no_table_report */
  +		}			/* !short_report */
  +	    }			/* if (<active child>) */
  +	}				/* for () */
  +	}
  +
  +	if (!(short_report || no_table_report)) {
  +#ifdef NO_TIMES
  +	    ap_rputs("</table>\n \
  +<hr> \
  +<table>\n \
  +<tr><th>Srv<td>Child Server number - generation\n \
  +<tr><th>PID<td>OS process ID\n \
  +<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  +<tr><th>M<td>Mode of operation\n \
  +<tr><th>SS<td>Seconds since beginning of most recent request\n \
  +<tr><th>Req<td>Milliseconds required to process most recent request\n \
  +<tr><th>Conn<td>Kilobytes transferred this connection\n \
  +<tr><th>Child<td>Megabytes transferred this child\n \
  +<tr><th>Slot<td>Total megabytes transferred this slot\n \
  +</table>\n", r);
  +#else
  +	    ap_rputs("</table>\n \
  +<hr> \
  +<table>\n \
  +<tr><th>Srv<td>Child Server number - generation\n \
  +<tr><th>PID<td>OS process ID\n \
  +<tr><th>Acc<td>Number of accesses this connection / this child / this slot\n \
  +<tr><th>M<td>Mode of operation\n \
  +<tr><th>CPU<td>CPU usage, number of seconds\n \
  +<tr><th>SS<td>Seconds since beginning of most recent request\n \
  +<tr><th>Req<td>Milliseconds required to process most recent request\n \
  +<tr><th>Conn<td>Kilobytes transferred this connection\n \
  +<tr><th>Child<td>Megabytes transferred this child\n \
  +<tr><th>Slot<td>Total megabytes transferred this slot\n \
  +</table>\n", r);
  +#endif
  +	}
  +
  +    } else {
  +
  +	if (!short_report) {
  +	    ap_rputs("<hr>To obtain a full report with current status information ", r);
  +	    ap_rputs("you need to use the <code>ExtendedStatus On</code> directive. \n", r);
  +	}
  +
  +    }
  +
  +    if (!short_report) {
  +	ap_rputs(ap_psignature("<HR>\n",r), r);
  +	ap_rputs("</BODY></HTML>\n", r);
  +    }
  +
       return 0;
   }
   
  +
  +static void status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
  +{
  +    status_flags[SERVER_DEAD] = '.';	/* We don't want to assume these are in */
  +    status_flags[SERVER_READY] = '_';	/* any particular order in scoreboard.h */
  +    status_flags[SERVER_STARTING] = 'S';
  +    status_flags[SERVER_BUSY_READ] = 'R';
  +    status_flags[SERVER_BUSY_WRITE] = 'W';
  +    status_flags[SERVER_BUSY_KEEPALIVE] = 'K';
  +    status_flags[SERVER_BUSY_LOG] = 'L';
  +    status_flags[SERVER_BUSY_DNS] = 'D';
  +    status_flags[SERVER_GRACEFUL] = 'G';
  +}
  +
   static void register_hooks(apr_pool_t *p)
   {
       ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE);
  +    ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE);
   }
   
   module AP_MODULE_DECLARE_DATA status_module =
   {
       STANDARD20_MODULE_STUFF,
  -    NULL,			/* create per-dir config */
  -    NULL,			/* merge per-dir config */
  +    NULL,			/* dir config creater */
  +    NULL,			/* dir merger --- default is to override */
       NULL,			/* server config */
       NULL,			/* merge server config */
  -    NULL,			/* command table */
  -    register_hooks	/* register hooks */
  +    status_module_cmds,		/* command table */
  +    register_hooks              /* register_hooks */
   };
  +
  
  
  
  1.289     +13 -3     httpd-2.0/modules/http/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/http/http_protocol.c,v
  retrieving revision 1.288
  retrieving revision 1.289
  diff -u -d -b -w -u -r1.288 -r1.289
  --- http_protocol.c	2001/01/31 22:45:21	1.288
  +++ http_protocol.c	2001/02/01 21:54:18	1.289
  @@ -91,7 +91,6 @@
   #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
   #include "util_charset.h"
   #include "util_ebcdic.h"
  -#include "mpm_status.h"
   
   #include "mod_core.h"
   
  @@ -1211,7 +1210,9 @@
       char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
       const char *ll = l;
       const char *uri;
  +#if 0
       conn_rec *conn = r->connection;
  +#endif
       int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
       int len;
   
  @@ -1277,7 +1278,12 @@
       r->request_time = apr_now();
       r->the_request = apr_pstrdup(r->pool, l);
       r->method = ap_getword_white(r->pool, &ll);
  -    ap_update_connection_status(conn->id, "Method", r->method);
  +#if 0
  +/* XXX If we want to keep track of the Method, the protocol module should do
  + * it.  That support isn't in the scoreboard yet.  Hopefully next week 
  + * sometime.   rbb */
  +    ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", r->method); 
  +#endif
       uri = ap_getword_white(r->pool, &ll);
   
       /* Provide quick information about the request method as soon as known */
  @@ -1302,7 +1308,11 @@
   
       r->assbackwards = (ll[0] == '\0');
       r->protocol = apr_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
  +/* XXX If we want to keep track of the Method, the protocol module should do
  + * it.  That support isn't in the scoreboard yet.  Hopefully next week 
  + * sometime.   rbb
       ap_update_connection_status(conn->id, "Protocol", r->protocol);
  + */
   
       if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor)
         && minor < HTTP_VERSION(1,0))	/* don't allow HTTP/0.1000 */
  
  
  
  1.32      +1 -1      httpd-2.0/server/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/Makefile.in,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -d -b -w -u -r1.31 -r1.32
  --- Makefile.in	2001/01/06 21:47:48	1.31
  +++ Makefile.in	2001/02/01 21:54:22	1.32
  @@ -12,7 +12,7 @@
   	util_script.c util_uri.c util_md5.c util_cfgtree.c util_ebcdic.c \
   	rfc1413.c connection.c listen.c \
           mpm_common.c util_charset.c util_debug.c util_xml.c \
  -	util_filter.c exports.c buildmark.c
  +	util_filter.c exports.c buildmark.c scoreboard.c
   
   targets = delete-exports $(LTLIBRARY_NAME)
   
  
  
  
  1.8       +4 -0      httpd-2.0/server/config.m4
  
  Index: config.m4
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/config.m4,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -d -b -w -u -r1.7 -r1.8
  --- config.m4	2000/06/09 22:37:50	1.7
  +++ config.m4	2001/02/01 21:54:23	1.8
  @@ -49,3 +49,7 @@
   AC_CHECK_FUNCS(
   syslog \
   )
  +
  +dnl Obsolete scoreboard code uses this.
  +    AC_CHECK_HEADERS(sys/times.h)
  +    AC_CHECK_FUNCS(times)
  
  
  
  1.72      +6 -5      httpd-2.0/server/connection.c
  
  Index: connection.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/connection.c,v
  retrieving revision 1.71
  retrieving revision 1.72
  diff -u -d -b -w -u -r1.71 -r1.72
  --- connection.c	2001/02/01 17:21:46	1.71
  +++ connection.c	2001/02/01 21:54:24	1.72
  @@ -64,9 +64,10 @@
   #include "http_request.h"
   #include "http_protocol.h"
   #include "ap_mpm.h"
  -#include "mpm_status.h"
  +#include "mpm_default.h"
   #include "http_config.h"
   #include "http_vhost.h"
  +#include "scoreboard.h"
   #include "http_log.h"
   #include "util_filter.h"
   
  @@ -240,26 +241,26 @@
        * until no requests are left or we decide to close.
        */
   
  -    ap_update_connection_status(c->id, "Status", "Reading");
  +    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_READ, NULL);
       while ((r = ap_read_request(c)) != NULL) {
   
   	/* process the request if it was read without error */
   
  -        ap_update_connection_status(c->id, "Status", "Writing");
  +        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_WRITE, NULL); 
   	if (r->status == HTTP_OK)
   	    ap_process_request(r);
   
   	if (!c->keepalive || c->aborted)
   	    break;
   
  -        ap_update_connection_status(c->id, "Status", "Keepalive");
  +        ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_KEEPALIVE, NULL);
   	apr_destroy_pool(r->pool);
   
   	if (ap_graceful_stop_signalled())
               break;
       }
   
  -    ap_reset_connection_status(c->id);
  +    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_READY, NULL);
       return OK;
   }
   
  
  
  
  1.1                  httpd-2.0/server/scoreboard.c
  
  Index: scoreboard.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Portions of this software are based upon public domain software
   * originally written at the National Center for Supercomputing Applications,
   * University of Illinois, Urbana-Champaign.
   */
  
  #include "apr_strings.h"
  #include "apr_portable.h"
  #include "ap_config.h"
  #include "httpd.h"
  #include "http_log.h"
  #include "http_main.h"
  #include "http_core.h"
  #include "http_config.h"
  #include "unixd.h"
  #include "http_conf_globals.h"
  #include "mpm.h"
  #include "scoreboard.h"
  #ifdef HAVE_SYS_TYPES_H
  #include <sys/types.h>
  #endif
  
  AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL;
  AP_DECLARE_DATA const char *ap_scoreboard_fname=NULL;
  AP_DECLARE_DATA int ap_extended_status = 0;
  AP_DECLARE_DATA apr_time_t ap_restart_time = 0;
  
  #if APR_HAS_SHARED_MEMORY
  #include "apr_shmem.h"
  
  static apr_shmem_t *scoreboard_shm = NULL;
  
  apr_status_t ap_cleanup_shared_mem(void *d)
  {
      apr_shm_free(scoreboard_shm, ap_scoreboard_image);
      ap_scoreboard_image = NULL;
      apr_shm_destroy(scoreboard_shm);
  
      return APR_SUCCESS;
  }
  
  static void setup_shared_mem(apr_pool_t *p)
  {
      char buf[512];
      char errmsg[120];
      const char *fname;
      apr_status_t rv;
  
      fname = ap_server_root_relative(p, ap_scoreboard_fname);
      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: %s",
                      ap_server_argv0, apr_strerror(rv, errmsg, sizeof errmsg));
          fprintf(stderr, "%s\n", buf);
          exit(APEXIT_INIT);
      }
      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);
          perror(buf); /* o.k. since MM sets errno */
          apr_shm_destroy(scoreboard_shm);
          exit(APEXIT_INIT);
      }
      apr_register_cleanup(p, NULL, ap_cleanup_shared_mem, apr_null_cleanup);
      ap_scoreboard_image->global.running_generation = 0;
  }
  
  void reopen_scoreboard(apr_pool_t *p)
  {
  }
  #endif   /* APR_SHARED_MEM */
  
  /* Called by parent process */
  void reinit_scoreboard(apr_pool_t *p)
  {
      int running_gen = 0;
      if (ap_scoreboard_image)
  	running_gen = ap_scoreboard_image->global.running_generation;
      if (ap_scoreboard_image == NULL) {
          setup_shared_mem(p);
      }
      memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
      ap_scoreboard_image->global.running_generation = running_gen;
  }
  
  /* Routines called to deal with the scoreboard image
   * --- note that we do *not* need write locks, since update_child_status
   * only updates a *single* record in place, and only one process writes to
   * a given scoreboard slot at a time (either the child process owning that
   * slot, or the parent, noting that the child has died).
   *
   * As a final note --- setting the score entry to getpid() is always safe,
   * since when the parent is writing an entry, it's only noting SERVER_DEAD
   * anyway.
   */
  
  apr_inline void ap_sync_scoreboard_image(void)
  {
  }
  
  AP_DECLARE(int) ap_exists_scoreboard_image(void)
  {
      return (ap_scoreboard_image ? 1 : 0);
  }
  
  static apr_inline void put_scoreboard_info(int child_num, int thread_num, 
  				       short_score *new_score_rec)
  {
      /* XXX - needs to be fixed to account for threads */
  #ifdef SCOREBOARD_FILE
      lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0);
      force_write(scoreboard_fd, new_score_rec, sizeof(short_score));
  #endif
  }
  
  void update_scoreboard_global(void)
  {
  #ifdef SCOREBOARD_FILE
      lseek(scoreboard_fd,
  	  (char *) &ap_scoreboard_image->global -(char *) ap_scoreboard_image, 0);
      force_write(scoreboard_fd, &ap_scoreboard_image->global,
  		sizeof ap_scoreboard_image->global);
  #endif
  }
  
  void increment_counts(int child_num, int thread_num, request_rec *r)
  {
      short_score *ss;
  
      ss = &ap_scoreboard_image->servers[child_num][thread_num];
  
  #ifdef HAVE_TIMES
      times(&ss->times);
  #endif
      ss->access_count++;
      ss->my_access_count++;
      ss->conn_count++;
      ss->bytes_served += r->bytes_sent;
      ss->my_bytes_served += r->bytes_sent;
      ss->conn_bytes += r->bytes_sent;
  
      put_scoreboard_info(child_num, thread_num, ss);
  }
  
  AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid)
  {
      int i;
      int max_daemons_limit = ap_get_max_daemons();
  
      for (i = 0; i < max_daemons_limit; ++i)
  	if (ap_scoreboard_image->parent[i].pid == pid->pid)
  	    return i;
  
      return -1;
  }
  
  int ap_update_child_status(int child_num, int thread_num, int status, request_rec *r)
  {
      int old_status;
      short_score *ss;
      parent_score *ps;
  
      if (child_num < 0)
  	return -1;
  
      ss = &ap_scoreboard_image->servers[child_num][thread_num];
      old_status = ss->status;
      ss->status = status;
  
      ps = &ap_scoreboard_image->parent[child_num];
      
      if ((status == SERVER_READY  || status == SERVER_ACCEPTING)
  	&& old_status == SERVER_STARTING) {
          ss->thread_num = child_num * HARD_SERVER_LIMIT + thread_num;
  	ps->worker_threads = ap_threads_per_child;
      }
  
      if (ap_extended_status) {
  	if (status == SERVER_READY || status == SERVER_DEAD) {
  	    /*
  	     * Reset individual counters
  	     */
  	    if (status == SERVER_DEAD) {
  		ss->my_access_count = 0L;
  		ss->my_bytes_served = 0L;
  	    }
  	    ss->conn_count = (unsigned short) 0;
  	    ss->conn_bytes = (unsigned long) 0;
  	}
  	if (r) {
  	    conn_rec *c = r->connection;
  	    apr_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
  				  REMOTE_NOLOOKUP), sizeof(ss->client));
  	    if (r->the_request == NULL) {
  		    apr_cpystrn(ss->request, "NULL", sizeof(ss->request));
  	    } else if (r->parsed_uri.password == NULL) {
  		    apr_cpystrn(ss->request, r->the_request, sizeof(ss->request));
  	    } else {
  		/* Don't reveal the password in the server-status view */
  		    apr_cpystrn(ss->request, apr_pstrcat(r->pool, r->method, " ",
  					       ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD),
  					       r->assbackwards ? NULL : " ", r->protocol, NULL),
  				       sizeof(ss->request));
  	    }
  	    ss->vhostrec =  r->server;
  	}
      }
      
      put_scoreboard_info(child_num, thread_num, ss);
      return old_status;
  }
  
  void ap_time_process_request(int child_num, int thread_num, int status)
  {
      short_score *ss;
  
      if (child_num < 0)
  	return;
  
      ss = &ap_scoreboard_image->servers[child_num][thread_num];
  
      if (status == START_PREQUEST) {
          ss->start_time = apr_now(); 
      }
      else if (status == STOP_PREQUEST) {
          ss->stop_time = apr_now(); 
      }
      put_scoreboard_info(child_num, thread_num, ss);
  }
  
  
  
  
  1.2       +1 -1      httpd-2.0/server/mpm/beos/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/beos/Makefile.in,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -d -b -w -u -r1.1 -r1.2
  --- Makefile.in	2000/06/20 14:30:00	1.1
  +++ Makefile.in	2001/02/01 21:54:29	1.2
  @@ -1,5 +1,5 @@
   
   LTLIBRARY_NAME    = libbeos.la
  -LTLIBRARY_SOURCES = beos.c scoreboard.c
  +LTLIBRARY_SOURCES = beos.c 
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.4       +1 -1      httpd-2.0/server/mpm/dexter/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/dexter/Makefile.in,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -d -b -w -u -r1.3 -r1.4
  --- Makefile.in	2000/04/30 00:06:04	1.3
  +++ Makefile.in	2001/02/01 21:54:36	1.4
  @@ -1,5 +1,5 @@
   
   LTLIBRARY_NAME    = libdexter.la
  -LTLIBRARY_SOURCES = dexter.c scoreboard.c
  +LTLIBRARY_SOURCES = dexter.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.140     +19 -22    httpd-2.0/server/mpm/dexter/dexter.c
  
  Index: dexter.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/dexter/dexter.c,v
  retrieving revision 1.139
  retrieving revision 1.140
  diff -u -d -b -w -u -r1.139 -r1.140
  --- dexter.c	2001/01/27 21:28:27	1.139
  +++ dexter.c	2001/02/01 21:54:37	1.140
  @@ -99,7 +99,6 @@
   static int max_threads = 0;
   static int max_requests_per_child = 0;
   static const char *ap_pid_fname=NULL;
  -AP_DECLARE_DATA const char *ap_scoreboard_fname=NULL;
   static int num_daemons=0;
   static int workers_may_exit = 0;
   static int requests_this_child;
  @@ -117,6 +116,7 @@
    * many child processes in this MPM.
    */
   int ap_max_daemons_limit = -1;
  +int ap_threads_per_child = HARD_THREAD_LIMIT;
   
   char ap_coredump_dir[MAX_STRING_LEN];
   
  @@ -214,6 +214,7 @@
   static int volatile shutdown_pending;
   static int volatile restart_pending;
   static int volatile is_graceful;
  +ap_generation_t volatile ap_my_generation=0;
   
   /*
    * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
  @@ -414,6 +415,9 @@
   
       ap_sock_disable_nagle(sock);
   
  +    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(conn_id),
  +                                  SERVER_BUSY_READ, (request_rec *) NULL);
  +
       current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id);
   
       ap_process_connection(current_conn);
  @@ -510,6 +514,10 @@
       pthread_mutex_unlock(&thread_pool_parent_mutex);
       apr_create_pool(&ptrans, tpool);
   
  +    (void) ap_update_child_status(child_num, thread_num, SERVER_STARTING,
  +                                  (request_rec *) NULL);
  +
  +
       apr_setup_poll(&pollset, num_listenfds+1, tpool);
       for(n=0 ; n <= num_listenfds ; ++n)
           apr_add_poll_socket(pollset, listenfds[n], APR_POLLIN);
  @@ -531,6 +539,10 @@
           else {
               thread_just_started = 0;
           }
  +
  +        (void) ap_update_child_status(child_num, thread_num, SERVER_READY,
  +                                      (request_rec *) NULL);
  +
           if ((rv = SAFE_ACCEPT(apr_lock(accept_mutex)))
               != APR_SUCCESS) {
               ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
  @@ -630,7 +642,8 @@
       }
   
       pthread_mutex_lock(&thread_pool_parent_mutex);
  -    apr_destroy_pool(tpool);
  +    ap_update_child_status(child_num, thread_num, SERVER_DEAD,
  +        (request_rec *) NULL);
       pthread_mutex_unlock(&thread_pool_parent_mutex);
       pthread_mutex_lock(&worker_thread_count_mutex);
       worker_thread_count--;
  @@ -768,9 +781,12 @@
   	child_main(slot);
       }
   
  +    (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL);
  +
       if ((pid = fork()) == -1) {
           ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
                        "fork: Unable to fork new process");
  +        (void) ap_update_child_status(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
   	   over and over again. */
  @@ -902,17 +918,13 @@
               child_slot = -1;
               for (i = 0; i < ap_max_daemons_limit; ++i) {
           	if (ap_child_table[i].pid == pid.pid) {
  -                    int j;
  -
                       child_slot = i;
  -                    for (j = 0; j < HARD_THREAD_LIMIT; j++) {
  -                        ap_dexter_force_reset_connection_status(i * HARD_THREAD_LIMIT + j);
  -                    }
                       break;
                   }
               }
               if (child_slot >= 0) {
                   ap_child_table[child_slot].pid = 0;
  +                ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);
                   
   		if (remaining_children_to_start
   		    && child_slot < num_daemons) {
  @@ -1152,7 +1164,6 @@
       ap_scoreboard_fname = DEFAULT_SCOREBOARD;
       lock_fname = DEFAULT_LOCKFILE;
       max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
  -    ap_dexter_set_maintain_connection_status(1);
   
       apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
   }
  @@ -1325,18 +1336,6 @@
       return NULL;
   }
   
  -static const char *set_maintain_connection_status(cmd_parms *cmd,
  -                                                  void *dummy, int arg) 
  -{
  -    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
  -    if (err != NULL) {
  -        return err;
  -    }
  -
  -    ap_dexter_set_maintain_connection_status(arg != 0);
  -    return NULL;
  -}
  -
   static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, const char *arg) 
   {
       apr_finfo_t finfo;
  @@ -1377,8 +1376,6 @@
                 "Maximum number of threads per child"),
   AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF,
                 "Maximum number of requests a particular child serves before dying."),
  -AP_INIT_FLAG("ConnectionStatus", set_maintain_connection_status, NULL, RSRC_CONF,
  -             "Whether or not to maintain status information on current connections"),
   AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF,
                 "The location of the directory Apache changes to before dumping core"),
   { NULL }
  
  
  
  1.5       +1 -0      httpd-2.0/server/mpm/dexter/mpm.h
  
  Index: mpm.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/dexter/mpm.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -d -b -w -u -r1.4 -r1.5
  --- mpm.h	2000/07/30 12:03:46	1.4
  +++ mpm.h	2001/02/01 21:54:38	1.5
  @@ -80,6 +80,7 @@
       unsigned char status;
   } ap_ctable;
   
  +extern int ap_threads_per_child;
   extern int ap_max_daemons_limit;
   extern ap_ctable ap_child_table[HARD_SERVER_LIMIT];
   extern server_rec *ap_server_conf;
  
  
  
  1.7       +3 -0      httpd-2.0/server/mpm/dexter/mpm_default.h
  
  Index: mpm_default.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/dexter/mpm_default.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -d -b -w -u -r1.6 -r1.7
  --- mpm_default.h	2000/06/10 01:35:59	1.6
  +++ mpm_default.h	2001/02/01 21:54:39	1.7
  @@ -59,6 +59,9 @@
   #ifndef APACHE_MPM_DEFAULT_H
   #define APACHE_MPM_DEFAULT_H
   
  +#define AP_ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_SERVER_LIMIT) + HARD_THREAD_LIMIT)
  +#define AP_CHILD_THREAD_FROM_ID(i)    (i / HARD_SERVER_LIMIT), (i % HARD_THREAD_LIMIT)
  +
   /* Number of threads to spawn off by default --- also, if fewer than
    * this free when the caretaker checks, it will spawn more.
    */
  
  
  
  1.5       +1 -1      httpd-2.0/server/mpm/mpmt_beos/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_beos/Makefile.in,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -d -b -w -u -r1.4 -r1.5
  --- Makefile.in	2000/04/30 00:06:04	1.4
  +++ Makefile.in	2001/02/01 21:54:47	1.5
  @@ -1,5 +1,5 @@
   
   LTLIBRARY_NAME    = libmpmt_beos.la
  -LTLIBRARY_SOURCES = mpmt_beos.c scoreboard.c poll.c
  +LTLIBRARY_SOURCES = mpmt_beos.c poll.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.4       +1 -1      httpd-2.0/server/mpm/mpmt_pthread/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_pthread/Makefile.in,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -d -b -w -u -r1.3 -r1.4
  --- Makefile.in	2000/04/30 00:06:04	1.3
  +++ Makefile.in	2001/02/01 21:54:52	1.4
  @@ -1,5 +1,5 @@
   
   LTLIBRARY_NAME    = libmpmt_pthread.la
  -LTLIBRARY_SOURCES = mpmt_pthread.c scoreboard.c
  +LTLIBRARY_SOURCES = mpmt_pthread.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.10      +0 -3      httpd-2.0/server/mpm/mpmt_pthread/config.m4
  
  Index: config.m4
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_pthread/config.m4,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -d -b -w -u -r1.9 -r1.10
  --- config.m4	2000/12/04 22:33:49	1.9
  +++ config.m4	2001/02/01 21:54:53	1.10
  @@ -7,7 +7,4 @@
   
       APACHE_MPM_PTHREAD
   
  -dnl Obsolete scoreboard code uses this.
  -    AC_CHECK_HEADERS(sys/times.h)
  -    AC_CHECK_FUNCS(times)
   fi
  
  
  
  1.8       +0 -1      httpd-2.0/server/mpm/mpmt_pthread/mpm.h
  
  Index: mpm.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_pthread/mpm.h,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -d -b -w -u -r1.7 -r1.8
  --- mpm.h	2000/07/30 12:03:47	1.7
  +++ mpm.h	2001/02/01 21:54:53	1.8
  @@ -70,7 +70,6 @@
   
   extern int ap_threads_per_child;
   extern int ap_max_requests_per_child;
  -extern int ap_extended_status;
   extern int ap_max_daemons_limit;
   extern unsigned int ap_my_pid;
   extern server_rec *ap_server_conf;
  
  
  
  1.7       +3 -0      httpd-2.0/server/mpm/mpmt_pthread/mpm_default.h
  
  Index: mpm_default.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_pthread/mpm_default.h,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -d -b -w -u -r1.6 -r1.7
  --- mpm_default.h	2000/03/31 09:05:09	1.6
  +++ mpm_default.h	2001/02/01 21:54:54	1.7
  @@ -59,6 +59,9 @@
   #ifndef APACHE_MPM_DEFAULT_H
   #define APACHE_MPM_DEFAULT_H
   
  +#define AP_ID_FROM_CHILD_THREAD(c, t)    ((c * HARD_SERVER_LIMIT) + HARD_THREAD_LIMIT)
  +#define AP_CHILD_THREAD_FROM_ID(i)    (i / HARD_SERVER_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.
    */
  
  
  
  1.135     +1 -5      httpd-2.0/server/mpm/mpmt_pthread/mpmt_pthread.c
  
  Index: mpmt_pthread.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/mpmt_pthread/mpmt_pthread.c,v
  retrieving revision 1.134
  retrieving revision 1.135
  diff -u -d -b -w -u -r1.134 -r1.135
  --- mpmt_pthread.c	2001/01/27 21:28:27	1.134
  +++ mpmt_pthread.c	2001/02/01 21:54:55	1.135
  @@ -94,13 +94,10 @@
   int ap_threads_per_child=0;         /* Worker threads per child */
   int ap_max_requests_per_child=0;
   static const char *ap_pid_fname=NULL;
  -AP_DECLARE_DATA const char *ap_scoreboard_fname=NULL;
   static int ap_daemons_to_start=0;
   static int min_spare_threads=0;
   static int max_spare_threads=0;
   static int ap_daemons_limit=0;
  -static time_t ap_restart_time=0;
  -AP_DECLARE_DATA int ap_extended_status = 0;
   static int workers_may_exit = 0;
   static int requests_this_child;
   static int num_listensocks = 0;
  @@ -807,7 +804,7 @@
   {
       int i, j;
       int idle_thread_count;
  -    thread_score *ss;
  +    short_score *ss;
       time_t now = 0;
       int free_length;
       int free_slots[MAX_SPAWN_RATE];
  @@ -933,7 +930,6 @@
               /* non-fatal death... note that it's gone in the scoreboard. */
               child_slot = find_child_by_pid(&pid);
               if (child_slot >= 0) {
  -                ap_mpmt_pthread_force_reset_connection_status(child_slot);
                   for (i = 0; i < ap_threads_per_child; i++)
                       ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);
                   
  
  
  
  1.2       +1 -1      httpd-2.0/server/mpm/perchild/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/perchild/Makefile.in,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -d -b -w -u -r1.1 -r1.2
  --- Makefile.in	2000/07/27 00:16:31	1.1
  +++ Makefile.in	2001/02/01 21:55:04	1.2
  @@ -1,5 +1,5 @@
   
   LTLIBRARY_NAME    = libperchild.la
  -LTLIBRARY_SOURCES = perchild.c scoreboard.c
  +LTLIBRARY_SOURCES = perchild.c
   
   include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.8       +0 -3      httpd-2.0/server/mpm/prefork/config.m4
  
  Index: config.m4
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/config.m4,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -d -b -w -u -r1.7 -r1.8
  --- config.m4	2000/12/04 22:33:50	1.7
  +++ config.m4	2001/02/01 21:55:08	1.8
  @@ -4,7 +4,4 @@
   
       APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
   
  -dnl Obsolete scoreboard code uses this.
  -    AC_CHECK_HEADERS(sys/times.h)
  -    AC_CHECK_FUNCS(times)
   fi
  
  
  
  1.6       +1 -0      httpd-2.0/server/mpm/prefork/mpm.h
  
  Index: mpm.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/mpm.h,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -d -b -w -u -r1.5 -r1.6
  --- mpm.h	2000/07/30 12:03:48	1.5
  +++ mpm.h	2001/02/01 21:55:09	1.6
  @@ -71,6 +71,7 @@
   #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
   #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
   
  +extern int ap_threads_per_child;
   extern int ap_max_daemons_limit;
   extern scoreboard *ap_scoreboard_image;
   extern server_rec *ap_server_conf;
  
  
  
  1.5       +8 -0      httpd-2.0/server/mpm/prefork/mpm_default.h
  
  Index: mpm_default.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/mpm_default.h,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -d -b -w -u -r1.4 -r1.5
  --- mpm_default.h	2000/03/31 09:05:10	1.4
  +++ mpm_default.h	2001/02/01 21:55:10	1.5
  @@ -59,6 +59,10 @@
   #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.
    */
  @@ -93,6 +97,10 @@
    */
   #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 */
  
  
  
  1.151     +14 -394   httpd-2.0/server/mpm/prefork/prefork.c
  
  Index: prefork.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v
  retrieving revision 1.150
  retrieving revision 1.151
  diff -u -d -b -w -u -r1.150 -r1.151
  --- prefork.c	2001/02/01 17:21:49	1.150
  +++ prefork.c	2001/02/01 21:55:11	1.151
  @@ -82,7 +82,6 @@
   /* TODO: this is a cobbled together prefork MPM example... it should mostly
    * TODO: behave like apache-1.3... here's a short list of things I think
    * TODO: need cleaning up still:
  - * TODO: - clean up scoreboard stuff when we figure out how to do it in 2.0
    */
   
   #include "apr.h"
  @@ -105,7 +104,6 @@
   #include "ap_config.h"
   #include "httpd.h"
   #include "mpm_default.h"
  -#include "mpm_status.h"
   #include "http_main.h"
   #include "http_log.h"
   #include "http_config.h"
  @@ -142,18 +140,16 @@
   
   /* config globals */
   
  +int ap_threads_per_child=0;         /* Worker threads per child */
   static int ap_max_requests_per_child=0;
   static const char *ap_pid_fname=NULL;
   static apr_lock_t *accept_lock;
  -static const char *ap_scoreboard_fname=NULL;
   static const char *ap_lock_fname;
   static int ap_daemons_to_start=0;
   static int ap_daemons_min_free=0;
   static int ap_daemons_max_free=0;
   static int ap_daemons_limit=0;
  -static time_t ap_restart_time=0;
   static int ap_extended_status = 0;
  -static int maintain_connection_status = 1;
   
   /*
    * The max child slot ever assigned, preserved across restarts.  Necessary
  @@ -197,9 +193,6 @@
   char tpf_server_name[INETD_SERVNAME_LENGTH+1];
   #endif /* TPF */
   
  -AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL;
  -static new_scoreboard *ap_new_scoreboard_image = NULL;
  -
   #ifdef GPROF
   /* 
    * change directory for gprof to plop the gmon.out file
  @@ -317,241 +310,11 @@
   #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
   #endif
   
  -#if APR_HAS_SHARED_MEMORY
  -#include "apr_shmem.h"
  -
  -static apr_shmem_t *scoreboard_shm = NULL;
  -static apr_shmem_t *status_shm = NULL;
  -
  -static apr_status_t cleanup_shared_mem(void *d)
  -{
  -    apr_shm_free(scoreboard_shm, ap_scoreboard_image);
  -    apr_shm_free(status_shm, ap_new_scoreboard_image);
  -    ap_scoreboard_image = NULL;
  -    ap_new_scoreboard_image = NULL;
  -    apr_shm_destroy(scoreboard_shm);
  -    apr_shm_destroy(status_shm);
  -    return APR_SUCCESS;
  -}
  -
  -static void setup_shared_mem(apr_pool_t *p)
  -{
  -    char buf[512];
  -    char errmsg[120];
  -    const char *fname;
  -    apr_status_t rv;
  -
  -    fname = ap_server_root_relative(p, ap_scoreboard_fname);
  -    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: %s",
  -		    ap_server_argv0, apr_strerror(rv, errmsg, sizeof errmsg));
  -	fprintf(stderr, "%s\n", buf);
  -	exit(APEXIT_INIT);
  -    }
  -    ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, SCOREBOARD_SIZE); 
  -    rv = apr_shm_init(&status_shm, NEW_SCOREBOARD_SIZE, fname, p);
  -    if (rv != APR_SUCCESS) {
  -	apr_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard: %s",
  -		    ap_server_argv0, apr_strerror(rv, errmsg, sizeof errmsg));
  -	fprintf(stderr, "%s\n", buf);
  -	exit(APEXIT_INIT);
  -    }
  -    ap_new_scoreboard_image = apr_shm_malloc(status_shm, NEW_SCOREBOARD_SIZE); 
  -    if (ap_scoreboard_image == NULL || ap_new_scoreboard_image == NULL) {
  -	apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard",
  -		    ap_server_argv0);
  -	perror(buf); /* o.k. since MM sets errno */
  -        apr_shm_destroy(scoreboard_shm);
  -        apr_shm_destroy(status_shm);
  -        exit(APEXIT_INIT);
  -    }
  -    apr_register_cleanup(p, NULL, cleanup_shared_mem, apr_null_cleanup);
  -    ap_scoreboard_image->global.running_generation = 0;
  -}
  -
  -static void reopen_scoreboard(apr_pool_t *p)
  -{
  -}
  -#endif
  -
  -/* Called by parent process */
  -static void reinit_scoreboard(apr_pool_t *p)
  -{
  -    int running_gen = 0;
  -    if (ap_scoreboard_image)
  -        running_gen = ap_scoreboard_image->global.running_generation;
  -
  -    if (ap_scoreboard_image == NULL) {
  -        setup_shared_mem(p);
  -    }
  -    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
  -    ap_scoreboard_image->global.running_generation = running_gen;
  -}
  -
  -
  -/* Routines called to deal with the scoreboard image
  - * --- note that we do *not* need write locks, since update_child_status
  - * only updates a *single* record in place, and only one process writes to
  - * a given scoreboard slot at a time (either the child process owning that
  - * slot, or the parent, noting that the child has died).
  - *
  - * As a final note --- setting the score entry to getpid() is always safe,
  - * since when the parent is writing an entry, it's only noting SERVER_DEAD
  - * anyway.
  - */
  -apr_inline void ap_sync_scoreboard_image(void)
  -{
  -#ifdef SCOREBOARD_FILE
  -    lseek(scoreboard_fd, 0L, 0);
  -    force_read(scoreboard_fd, ap_scoreboard_image, sizeof(*ap_scoreboard_image))
  -;
  -#endif
  -}
  -
  -AP_DECLARE(int) ap_exists_scoreboard_image(void)
  -{
  -    return (ap_scoreboard_image ? 1 : 0);
  -}
  -
   AP_DECLARE(int) ap_get_max_daemons(void)
   {
       return ap_max_daemons_limit;
   }
   
  -static apr_inline void put_scoreboard_info(int child_num,
  -                                       short_score *new_score_rec)
  -{
  -#ifdef SCOREBOARD_FILE
  -    lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0);
  -    force_write(scoreboard_fd, new_score_rec, sizeof(short_score));
  -#endif
  -}
  -
  -int ap_update_child_status(int child_num, int status, request_rec *r)
  -{
  -    int old_status;
  -    short_score *ss;
  -
  -    if (child_num < 0)
  -	return -1;
  -
  -    ap_check_signals();
  -
  -    ss = &ap_scoreboard_image->servers[child_num];
  -    old_status = ss->status;
  -    ss->status = status;
  -
  -    if (ap_extended_status) {
  -	if (status == SERVER_READY || status == SERVER_DEAD) {
  -	    /*
  -	     * Reset individual counters
  -	     */
  -	    if (status == SERVER_DEAD) {
  -		ss->my_access_count = 0L;
  -		ss->my_bytes_served = 0L;
  -	    }
  -	    ss->conn_count = (unsigned short) 0;
  -	    ss->conn_bytes = (unsigned long) 0;
  -	}
  -	if (r) {
  -	    conn_rec *c = r->connection;
  -	    apr_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config,
  -				  REMOTE_NOLOOKUP), sizeof(ss->client));
  -	    if (r->the_request == NULL) {
  -		    apr_cpystrn(ss->request, "NULL", sizeof(ss->request));
  -	    } else if (r->parsed_uri.password == NULL) {
  -		    apr_cpystrn(ss->request, r->the_request, sizeof(ss->request));
  -	    } else {
  -		/* Don't reveal the password in the server-status view */
  -		    apr_cpystrn(ss->request, apr_pstrcat(r->pool, r->method, " ",
  -					       ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD),
  -					       r->assbackwards ? NULL : " ", r->protocol, NULL),
  -				       sizeof(ss->request));
  -	    }
  -	    ss->vhostrec =  r->server;
  -	}
  -    }
  -    if (status == SERVER_STARTING && r == NULL) {
  -	/* clean up the slot's vhostrec pointer (maybe re-used)
  -	 * and mark the slot as belonging to a new generation.
  -	 */
  -	ss->vhostrec = NULL;
  -	ap_scoreboard_image->parent[child_num].generation = ap_my_generation;
  -#ifdef SCOREBOARD_FILE
  -	lseek(scoreboard_fd, XtOffsetOf(scoreboard, parent[child_num]), 0);
  -	force_write(scoreboard_fd, &ap_scoreboard_image->parent[child_num],
  -	    sizeof(parent_score));
  -#endif
  -    }
  -    put_scoreboard_info(child_num, ss);
  -
  -    return old_status;
  -}
  -
  -static void update_scoreboard_global(void)
  -{
  -#ifdef SCOREBOARD_FILE
  -    lseek(scoreboard_fd,
  -	  (char *) &ap_scoreboard_image->global -(char *) ap_scoreboard_image, 0);
  -    force_write(scoreboard_fd, &ap_scoreboard_image->global,
  -		sizeof ap_scoreboard_image->global);
  -#endif
  -}
  -
  -void ap_time_process_request(int child_num, int status)
  -{
  -    short_score *ss;
  -
  -    if (child_num < 0)
  -	return;
  -
  -    ap_sync_scoreboard_image();
  -    ss = &ap_scoreboard_image->servers[child_num];
  -
  -    if (status == START_PREQUEST) {
  -	ss->start_time = apr_now();
  -    }
  -    else if (status == STOP_PREQUEST) {
  -	ss->stop_time = apr_now();
  -    }
  -
  -    put_scoreboard_info(child_num, ss);
  -}
  -
  -/*
  -static void increment_counts(int child_num, request_rec *r)
  -{
  -    short_score *ss;
  -
  -    ap_sync_scoreboard_image();
  -    ss = &ap_scoreboard_image->servers[child_num];
  -
  -#ifdef HAVE_TIMES
  -    times(&ss->times);
  -#endif
  -    ss->access_count++;
  -    ss->my_access_count++;
  -    ss->conn_count++;
  -    ss->bytes_served += r->bytes_sent;
  -    ss->my_bytes_served += r->bytes_sent;
  -    ss->conn_bytes += r->bytes_sent;
  -
  -    put_scoreboard_info(child_num, ss);
  -}
  -*/
  -
  -static int find_child_by_pid(apr_proc_t *pid)
  -{
  -    int i;
  -
  -    for (i = 0; i < ap_max_daemons_limit; ++i)
  -	if (ap_scoreboard_image->parent[i].pid == pid->pid)
  -	    return i;
  -
  -    return -1;
  -}
  -
   #if defined(NEED_WAITPID)
   /*
      Systems without a real waitpid sometimes lose a child's exit while waiting
  @@ -563,9 +326,9 @@
   
       for (n = 0; n < ap_max_daemons_limit; ++n) {
           ap_sync_scoreboard_image();
  -	if (ap_scoreboard_image->servers[n].status != SERVER_DEAD &&
  +	if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
   		kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
  -	    ap_update_child_status(n, SERVER_DEAD, NULL);
  +	    ap_update_child_status(AP_CHILD_THREAD_FROM_ID(n), SERVER_DEAD, NULL);
   	    /* just mark it as having a successful exit status */
   	    memset(status, 0, sizeof(apr_wait_t));
   	    return(pid);
  @@ -636,7 +399,7 @@
       }
       restart_pending = 1;
       if ((is_graceful = (sig == SIGWINCH))) {
  -        apr_kill_cleanup(pconf, NULL, cleanup_shared_mem);
  +        apr_kill_cleanup(pconf, NULL, ap_cleanup_shared_mem);
       }
   }
   
  @@ -797,7 +560,7 @@
   
       ap_child_init_hook(pchild, ap_server_conf);
   
  -    (void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
  +    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL);
   
       apr_signal(SIGHUP, just_die);
       apr_signal(SIGTERM, just_die);
  @@ -831,7 +594,7 @@
   	    clean_child_exit(0);
   	}
   
  -	(void) ap_update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
  +	(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL);
   
   	/*
   	 * Wait for an acceptable connection to arrive.
  @@ -1043,7 +806,7 @@
   
   	ap_sock_disable_nagle(csd);
   
  -	(void) ap_update_child_status(my_child_num, SERVER_BUSY_READ,
  +	(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_BUSY_READ,
   				   (request_rec *) NULL);
   
   	current_conn = ap_new_connection(ptrans, ap_server_conf, csd, 
  @@ -1075,7 +838,7 @@
   	child_main(slot);
       }
   
  -    (void) ap_update_child_status(slot, SERVER_STARTING, (request_rec *) NULL);
  +    (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_STARTING, (request_rec *) NULL);
   
   
   #ifdef _OSD_POSIX
  @@ -1091,7 +854,7 @@
   	/* fork didn't succeed. Fix the scoreboard or else
   	 * it will say SERVER_STARTING forever and ever
   	 */
  -	(void) ap_update_child_status(slot, SERVER_DEAD, (request_rec *) NULL);
  +	(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), 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
  @@ -1143,7 +906,7 @@
       time_t now = time(0);
   
       for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {
  -	if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
  +	if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
   	    continue;
   	}
   	if (make_child(ap_server_conf, i, now) < 0) {
  @@ -1192,7 +955,7 @@
   
   	if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
   	    break;
  -	ss = &ap_scoreboard_image->servers[i];
  +	ss = &ap_scoreboard_image->servers[i][0];
   	status = ss->status;
   	if (status == SERVER_DEAD) {
   	    /* try to keep children numbers as low as possible */
  @@ -1307,23 +1070,6 @@
       return 0;
   }
   
  -/* Useful to erase the status of children that might be from previous
  - * generations */
  -static void ap_prefork_force_reset_connection_status(long conn_id)
  -{
  -    int i;
  -
  -    for (i = 0; i < STATUSES_PER_CONNECTION; i++) {
  -        ap_new_scoreboard_image->table[conn_id][i].key[0] = '\0';
  -    }                                                                           }
  -
  -void ap_reset_connection_status(long conn_id)
  -{
  -    if (maintain_connection_status) {
  -        ap_prefork_force_reset_connection_status(conn_id);
  -    }
  -}
  -
   /*****************************************************************
    * Executive routines.
    */
  @@ -1406,8 +1152,7 @@
   	    ap_sync_scoreboard_image();
   	    child_slot = find_child_by_pid(&pid);
   	    if (child_slot >= 0) {
  -                ap_prefork_force_reset_connection_status(child_slot);
  -		(void) ap_update_child_status(child_slot, SERVER_DEAD,
  +		(void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(child_slot), SERVER_DEAD,
   					    (request_rec *) NULL);
   		if (remaining_children_to_start
   		    && child_slot < ap_daemons_limit) {
  @@ -1521,8 +1266,8 @@
   	    */
   	ap_sync_scoreboard_image();
   	for (i = 0; i < ap_daemons_limit; ++i) {
  -	    if (ap_scoreboard_image->servers[i].status != SERVER_DEAD) {
  -		ap_scoreboard_image->servers[i].status = SERVER_GRACEFUL;
  +	    if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
  +		ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL;
   	    }
   	}
   #endif
  @@ -1724,131 +1469,6 @@
       }
       apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
       return NULL;
  -}
  -
  -/* Stub functions until this MPM supports the connection status API */
  -/* Don't mess with the string you get back from this function */
  -const char *ap_get_connection_status(long conn_id, const char *key)
  -{
  -    int i = 0;
  -    status_table_entry *ss;
  -
  -    if (!maintain_connection_status) return "";
  -    while (i < STATUSES_PER_CONNECTION) {
  -        ss = &(ap_new_scoreboard_image->table[conn_id][i]);
  -        if (ss->key[0] == '\0') {
  -            break;
  -        }
  -        if (0 == strcmp(ss->key, key)) {
  -            return ss->value;
  -        }
  -    }
  -
  -    return NULL;
  -}
  -
  -apr_array_header_t *ap_get_connections(apr_pool_t *p)
  -{
  -    int i;
  -    apr_array_header_t *connection_list;
  -    long *array_slot;
  -
  -    connection_list = apr_make_array(p, 0, sizeof(long));
  -    /* We assume that there is a connection iff it has an entry in the status
  -     * table. Connections without any status sound problematic to me, so this
  -     * is probably for the best. - manoj */
  -    for (i = 0; i < ap_max_daemons_limit; i++) {
  -         if (ap_new_scoreboard_image->table[i][0].key[0] != '\0') {
  -            array_slot = apr_push_array(connection_list);
  -            *array_slot = i;
  -        }
  -    }
  -    return connection_list;
  -}
  -
  -apr_array_header_t *ap_get_connection_keys(apr_pool_t *p, long conn_id)
  -{
  -    int i = 0;
  -    status_table_entry *ss;
  -    apr_array_header_t *key_list;
  -    char **array_slot;
  -
  -    key_list = apr_make_array(p, 0, KEY_LENGTH * sizeof(char));
  -    while (i < STATUSES_PER_CONNECTION) {
  -        ss = &(ap_new_scoreboard_image->table[conn_id][i]);
  -        if (ss->key[0] == '\0') {
  -            break;
  -        }
  -        array_slot = apr_push_array(key_list);
  -        *array_slot = apr_pstrdup(p, ss->key);
  -        i++;
  -    }
  -    return key_list;
  -}
  -
  -/* Note: no effort is made here to prevent multiple threads from messing with
  - * a single connection at the same time. ap_update_connection_status should
  - * only be called by the thread that owns the connection */
  -
  -void ap_update_connection_status(long conn_id, const char *key,
  -                                 const char *value)
  -{
  -    int i = 0;
  -    status_table_entry *ss;
  -
  -    if (!maintain_connection_status) return;
  -    while (i < STATUSES_PER_CONNECTION) {
  -        ss = &(ap_new_scoreboard_image->table[conn_id][i]);
  -        if (ss->key[0] == '\0') {
  -            break;
  -        }
  -        if (0 == strcmp(ss->key, key)) {
  -            apr_cpystrn(ss->value, value, VALUE_LENGTH);
  -            return;
  -        }
  -        i++;
  -    }
  -    /* Not found. Add an entry for this value */
  -    if (i >= STATUSES_PER_CONNECTION) {
  -        /* No room. Oh well, not much anyone can do about it. */
  -        return;
  -    }
  -    apr_cpystrn(ss->key, key, KEY_LENGTH);
  -    apr_cpystrn(ss->value, value, VALUE_LENGTH);
  -    return;
  -}
  -
  -apr_array_header_t *ap_get_status_table(apr_pool_t *p)
  -{
  -    int i, j;
  -    apr_array_header_t *server_status;
  -    ap_status_table_row_t *array_slot;
  -    status_table_entry *ss;
  -
  -    server_status = apr_make_array(p, 0, sizeof(ap_status_table_row_t));
  -
  -    /* Go ahead and return what's in the connection status table even if we
  -     * aren't maintaining it. We can at least look at what children from
  -     * previous generations are up to. */
  -
  -    for (i = 0; i < ap_max_daemons_limit; i++) {
  -        if (ap_new_scoreboard_image->table[i][0].key[0] == '\0')
  -            continue;
  -        array_slot = apr_push_array(server_status);
  -        array_slot->data = apr_make_table(p, 0);
  -        array_slot->conn_id = i;
  -
  -        for (j = 0; j < STATUSES_PER_CONNECTION; j++) {
  -            ss = &(ap_new_scoreboard_image->table[i][j]);
  -            if (ss->key[0] != '\0') {
  -                apr_table_add(array_slot->data, ss->key, ss->value);
  -            }
  -            else {
  -                break;
  -            }
  -        }
  -    }
  -    return server_status;
   }
   
   static const command_rec prefork_cmds[] = {