You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@hyperreal.org on 1999/10/13 07:24:17 UTC

cvs commit: apache-2.0/src/modules/standard mod_status.c

manoj       99/10/12 22:24:17

  Modified:    .        STATUS
               src/main http_connection.c http_protocol.c
               src/modules/mpm/dexter Makefile.tmpl dexter.c
               src/modules/standard mod_status.c
  Added:       src/include mpm_status.h
               src/modules/mpm/dexter scoreboard.c scoreboard.h
  Log:
  Add a connection status table to replace the old function of the
  scoreboard. It allows MPMs to implement their own mechanism for the
  status table and allows any module to add its own per-connection status
  entries.
  
  Revision  Changes    Path
  1.6       +5 -7      apache-2.0/STATUS
  
  Index: STATUS
  ===================================================================
  RCS file: /home/cvs/apache-2.0/STATUS,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -d -u -r1.5 -r1.6
  --- STATUS	1999/08/31 21:46:35	1.5
  +++ STATUS	1999/10/13 05:24:11	1.6
  @@ -1,5 +1,5 @@
   Apache 2.0 STATUS:
  -Last modified at [$Date: 1999/08/31 21:46:35 $]
  +Last modified at [$Date: 1999/10/13 05:24:11 $]
   
   Release:
   
  @@ -15,12 +15,6 @@
       * CGI doesn't work
           Status: Ben Laurie is working on this.
   
  -    * mod_status doesn't work
  -        Status: Manoj Kasichainula <ma...@io.com> is working on this. A
  -        patch has been posted that starts to fix this:
  -        (<19...@samosa.mindspring.com> and
  -        <19...@io.com>)
  -
       * suEXEC doesn't work
           Ben Laurie's work to fix CGIs will also fix this.
   
  @@ -43,6 +37,10 @@
   
       * Use APR to get rid of more platform dependancies.
           Status: Ryan Bloom <rb...@raleigh.ibm.com> is working on this.
  +
  +    * The connection status table is not very efficient. Also, very few stats
  +      are exported to the connection status table (easy to fix), and mod_status
  +      is ugly.
   
   Other bugs that need fixing:
   
  
  
  
  1.1                  apache-2.0/src/include/mpm_status.h
  
  Index: mpm_status.h
  ===================================================================
  /* ====================================================================
   * Copyright (c) 1995-1999 The Apache Group.  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. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * 4. The names "Apache Server" and "Apache Group" 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 names without prior written
   *    permission of the Apache Group.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Apache Group
   *    for use in the Apache HTTP server project (http://www.apache.org/)."
   *
   * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based
   * on public domain software written at the National Center for
   * Supercomputing Applications, University of Illinois, Urbana-Champaign.
   * For more information on the Apache Group and the Apache HTTP server
   * project, please see <http://www.apache.org/>.
   *
   */
  
  /*
   * TODO: Possible additions to this API include getting a list of connection
   * IDs and a list of keys in a particular row.
   */
  
  #ifndef APACHE_MPM_STATUS_H
  #define APACHE_MPM_STATUS_H
  
  #include "apr_lib.h"
  
  typedef struct {
      long conn_id;
      ap_table_t *data;
  } ap_status_table_row_t;
  
  /**
   *
   * Get a cell from the status table. Don't mess with the string you get.
   *
   * conn_id = Connection ID
   * key = key
   *
   */
  API_EXPORT(const char *) ap_get_connection_status(long conn_id, const char *key);
  
  /**
   *
   * Set a cell in the status table. No guarantees are made that long strings
   * won't be truncated.
   *
   * conn_id = Connection ID
   * key = key
   * value = value
   *
   */
  API_EXPORT(void) ap_update_connection_status(long conn_id, const char *key, const char *value);
  
  /**
   *
   * Clear out this connection's status values. Normally called when a
   * connection is closed
   *
   * conn_id = Connection ID
   *
   */
  API_EXPORT(void) ap_reset_connection_status(long conn_id);
  
  /**
   *
   * Returns the most up-to-date status table available, in the form of an array
   * of ap_status_row_t's.
   *
   * p = context, generally of the request
   *
   */
  API_EXPORT(ap_array_header_t *) ap_get_status_table(ap_context_t *p);
  
  #endif /* APACHE_SERVER_STATS_H */
  
  
  
  
  1.21      +5 -0      apache-2.0/src/main/http_connection.c
  
  Index: http_connection.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_connection.c,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -d -u -r1.20 -r1.21
  --- http_connection.c	1999/10/11 22:07:21	1.20
  +++ http_connection.c	1999/10/13 05:24:13	1.21
  @@ -61,6 +61,7 @@
   #include "http_request.h"
   #include "http_protocol.h"
   #include "ap_mpm.h"
  +#include "mpm_status.h"
   #include "http_config.h"
   #include "http_vhost.h"
   
  @@ -230,16 +231,19 @@
        * until no requests are left or we decide to close.
        */
   
  +    ap_update_connection_status(c->id, "Status", "Reading");
       while ((r = ap_read_request(c)) != NULL) {
   
   	/* process the request if it was read without error */
   
  +        ap_update_connection_status(c->id, "Status", "Writing");
   	if (r->status == HTTP_OK)
   	    ap_process_request(r);
   
   	if (!c->keepalive || c->aborted)
   	    break;
   
  +        ap_update_connection_status(c->id, "Status", "Keepalive");
   	ap_destroy_pool(r->pool);
   
   	if (ap_graceful_stop_signalled()) {
  @@ -249,6 +253,7 @@
   	}
       }
   
  +    ap_reset_connection_status(c->id);
       return OK;
   }
   
  
  
  
  1.22      +3 -0      apache-2.0/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -d -u -r1.21 -r1.22
  --- http_protocol.c	1999/10/12 20:38:58	1.21
  +++ http_protocol.c	1999/10/13 05:24:13	1.22
  @@ -73,6 +73,7 @@
   #include "http_log.h"           /* For errors detected in basic auth common
                                    * support code... */
   #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
  +#include "mpm_status.h"
   #include <stdarg.h>
   
   HOOK_STRUCT(
  @@ -826,6 +827,7 @@
       r->request_time = time(NULL);
       r->the_request = ap_pstrdup(r->pool, l);
       r->method = ap_getword_white(r->pool, &ll);
  +    ap_update_connection_status(conn->id, "Method", r->method);
       uri = ap_getword_white(r->pool, &ll);
   
       /* Provide quick information about the request method as soon as known */
  @@ -850,6 +852,7 @@
   
       r->assbackwards = (ll[0] == '\0');
       r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
  +    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.5       +2 -2      apache-2.0/src/modules/mpm/dexter/Makefile.tmpl
  
  Index: Makefile.tmpl
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/dexter/Makefile.tmpl,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -d -u -r1.4 -r1.5
  --- Makefile.tmpl	1999/09/23 19:08:01	1.4
  +++ Makefile.tmpl	1999/10/13 05:24:14	1.5
  @@ -2,9 +2,9 @@
   LIB=libdexter.$(LIBEXT)
   
   OBJS=\
  -     dexter.o acceptlock.o
  +     dexter.o acceptlock.o scoreboard.o
   OBJS_PIC=\
  -     dexter.lo acceptlock.lo
  +     dexter.lo acceptlock.lo scoreboard.lo
   
   all: lib
   
  
  
  
  1.43      +11 -1     apache-2.0/src/modules/mpm/dexter/dexter.c
  
  Index: dexter.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/mpm/dexter/dexter.c,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -d -u -r1.42 -r1.43
  --- dexter.c	1999/10/10 20:35:02	1.42
  +++ dexter.c	1999/10/13 05:24:14	1.43
  @@ -71,6 +71,7 @@
   #include "acceptlock.h"
   #include "mpm_default.h"
   #include "dexter.h"
  +#include "scoreboard.h"
   
   #include <poll.h>
   #include <netinet/tcp.h> 
  @@ -1204,11 +1205,17 @@
           
           if (pid >= 0) {
               process_child_status(pid, status);
  -            /* non-fatal death... note that it's gone in the child table. */
  +            /* non-fatal death... note that it's gone in the child table and
  +             * clean out the status table. */
               child_slot = -1;
               for (i = 0; i < max_daemons_limit; ++i) {
           	if (child_table[i].pid == pid) {
  +                    int j;
  +
                       child_slot = i;
  +                    for (j = 0; j < HARD_THREAD_LIMIT; j++) {
  +                        ap_reset_connection_status(i * HARD_THREAD_LIMIT + j);
  +                    }
                       break;
                   }
               }
  @@ -1301,6 +1308,9 @@
       }
       ap_log_pid(pconf, ap_pid_fname);
       SAFE_ACCEPT(accept_mutex_init(pconf, 1));
  +    if (!is_graceful) {
  +        reinit_scoreboard(pconf);
  +    }
       /* Initialize the child table */
       if (!is_graceful) {
           for (i = 0; i < HARD_SERVER_LIMIT; i++) {
  
  
  
  1.3       +501 -19   apache-2.0/src/modules/mpm/dexter/scoreboard.c
  
  Index: scoreboard.c
  ===================================================================
  RCS file: scoreboard.c
  diff -N scoreboard.c
  --- /dev/null	Tue Oct 12 22:24:04 1999
  +++ /tmp/cvsuc4372	Tue Oct 12 22:24:16 1999
  @@ -0,0 +1,527 @@
  +/* ====================================================================
  + * Copyright (c) 1995-1999 The Apache Group.  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. All advertising materials mentioning features or use of this 
  + *    software must display the following acknowledgment: 
  + *    "This product includes software developed by the Apache Group 
  + *    for use in the Apache HTTP server project (http://www.apache.org/)." 
  + * 
  + * 4. The names "Apache Server" and "Apache Group" 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 names without prior written 
  + *    permission of the Apache Group. 
  + * 
  + * 6. Redistributions of any form whatsoever must retain the following 
  + *    acknowledgment: 
  + *    "This product includes software developed by the Apache Group 
  + *    for use in the Apache HTTP server project (http://www.apache.org/)." 
  + * 
  + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based 
  + * on public domain software written at the National Center for 
  + * Supercomputing Applications, University of Illinois, Urbana-Champaign. 
  + * For more information on the Apache Group and the Apache HTTP server 
  + * project, please see <http://www.apache.org/>. 
  + * 
  + */ 
  +
  +#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_status.h"
  +#include "scoreboard.h"
  +#include "dexter.h" /* for max_daemons_limit */
  +#ifdef USE_SHMGET_SCOREBOARD
  +#include <sys/types.h>
  +#include <sys/ipc.h>
  +#include <sys/shm.h>
  +#endif
  +
  +#ifdef USE_OS2_SCOREBOARD
  +    /* Add MMAP style functionality to OS/2 */
  +#define INCL_DOSMEMMGR
  +#define INCL_DOSEXCEPTIONS
  +#define INCL_DOSSEMAPHORES
  +#include <os2.h>
  +#include <umalloc.h>
  +#include <stdio.h>
  +#endif
  +
  +static scoreboard *ap_scoreboard_image = NULL;
  +static char *ap_server_argv0=NULL;
  +
  +/*****************************************************************
  + *
  + * Dealing with the scoreboard... a lot of these variables are global
  + * only to avoid getting clobbered by the longjmp() that happens when
  + * a hard timeout expires...
  + *
  + * We begin with routines which deal with the file itself... 
  + */
  +
  +#if defined(USE_OS2_SCOREBOARD)
  +
  +/* The next two routines are used to access shared memory under OS/2.  */
  +/* This requires EMX v09c to be installed.                           */
  +
  +caddr_t create_shared_heap(const char *name, size_t size)
  +{
  +    ULONG rc;
  +    void *mem;
  +    Heap_t h;
  +
  +    rc = DosAllocSharedMem(&mem, name, size,
  +			   PAG_COMMIT | PAG_READ | PAG_WRITE);
  +    if (rc != 0)
  +	return NULL;
  +    h = _ucreate(mem, size, !_BLOCK_CLEAN, _HEAP_REGULAR | _HEAP_SHARED,
  +		 NULL, NULL);
  +    if (h == NULL)
  +	DosFreeMem(mem);
  +    return (caddr_t) h;
  +}
  +
  +caddr_t get_shared_heap(const char *Name)
  +{
  +
  +    PVOID BaseAddress;		/* Pointer to the base address of
  +				   the shared memory object */
  +    ULONG AttributeFlags;	/* Flags describing characteristics
  +				   of the shared memory object */
  +    APIRET rc;			/* Return code */
  +
  +    /* Request read and write access to */
  +    /*   the shared memory object       */
  +    AttributeFlags = PAG_WRITE | PAG_READ;
  +
  +    rc = DosGetNamedSharedMem(&BaseAddress, Name, AttributeFlags);
  +
  +    if (rc != 0) {
  +	printf("DosGetNamedSharedMem error: return code = %ld", rc);
  +	return 0;
  +    }
  +
  +    return BaseAddress;
  +}
  +
  +static void setup_shared_mem(ap_context_t *p)
  +{
  +    caddr_t m;
  +
  +    int rc;
  +
  +    m = (caddr_t) create_shared_heap("\\SHAREMEM\\SCOREBOARD", SCOREBOARD_SIZE);
  +    if (m == 0) {
  +	fprintf(stderr, "%s: Could not create OS/2 Shared memory pool.\n",
  +		ap_server_argv0);
  +	exit(APEXIT_INIT);
  +    }
  +
  +    rc = _uopen((Heap_t) m);
  +    if (rc != 0) {
  +	fprintf(stderr,
  +		"%s: Could not uopen() newly created OS/2 Shared memory pool.\n",
  +		ap_server_argv0);
  +    }
  +    ap_scoreboard_image = (scoreboard *) m;
  +    ap_scoreboard_image->global.running_generation = 0;
  +}
  +
  +API_EXPORT(void) reopen_scoreboard(ap_context_t *p)
  +{
  +    caddr_t m;
  +    int rc;
  +
  +    m = (caddr_t) get_shared_heap("\\SHAREMEM\\SCOREBOARD");
  +    if (m == 0) {
  +	fprintf(stderr, "%s: Could not find existing OS/2 Shared memory pool.\n",
  +		ap_server_argv0);
  +	exit(APEXIT_INIT);
  +    }
  +
  +    rc = _uopen((Heap_t) m);
  +    ap_scoreboard_image = (scoreboard *) m;
  +}
  +
  +#elif defined(USE_POSIX_SCOREBOARD)
  +#include <sys/mman.h>
  +/* 
  + * POSIX 1003.4 style
  + *
  + * Note 1: 
  + * As of version 4.23A, shared memory in QNX must reside under /dev/shmem,
  + * where no subdirectories allowed.
  + *
  + * POSIX shm_open() and shm_unlink() will take care about this issue,
  + * but to avoid confusion, I suggest to redefine scoreboard file name
  + * in httpd.conf to cut "logs/" from it. With default setup actual name
  + * will be "/dev/shmem/logs.apache_status". 
  + * 
  + * If something went wrong and Apache did not unlinked this object upon
  + * exit, you can remove it manually, using "rm -f" command.
  + * 
  + * Note 2:
  + * <sys/mman.h> in QNX defines MAP_ANON, but current implementation 
  + * does NOT support BSD style anonymous mapping. So, the order of 
  + * conditional compilation is important: 
  + * this #ifdef section must be ABOVE the next one (BSD style).
  + *
  + * I tested this stuff and it works fine for me, but if it provides 
  + * trouble for you, just comment out USE_MMAP_SCOREBOARD in QNX section
  + * of ap_config.h
  + *
  + * June 5, 1997, 
  + * Igor N. Kovalenko -- infoh@mail.wplus.net
  + */
  +
  +static void cleanup_shared_mem(void *d)
  +{
  +    shm_unlink(ap_scoreboard_fname);
  +}
  +
  +static void setup_shared_mem(ap_context_t *p)
  +{
  +    char buf[512];
  +    caddr_t m;
  +    int fd;
  +
  +    fd = shm_open(ap_scoreboard_fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  +    if (fd == -1) {
  +	ap_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard",
  +		    ap_server_argv0);
  +	perror(buf);
  +	exit(APEXIT_INIT);
  +    }
  +    if (ltrunc(fd, (off_t) SCOREBOARD_SIZE, SEEK_SET) == -1) {
  +	ap_snprintf(buf, sizeof(buf), "%s: could not ltrunc scoreboard",
  +		    ap_server_argv0);
  +	perror(buf);
  +	shm_unlink(ap_scoreboard_fname);
  +	exit(APEXIT_INIT);
  +    }
  +    if ((m = (caddr_t) mmap((caddr_t) 0,
  +			    (size_t) SCOREBOARD_SIZE, PROT_READ | PROT_WRITE,
  +			    MAP_SHARED, fd, (off_t) 0)) == (caddr_t) - 1) {
  +	ap_snprintf(buf, sizeof(buf), "%s: cannot mmap scoreboard",
  +		    ap_server_argv0);
  +	perror(buf);
  +	shm_unlink(ap_scoreboard_fname);
  +	exit(APEXIT_INIT);
  +    }
  +    close(fd);
  +    ap_register_cleanup(p, NULL, cleanup_shared_mem, ap_null_cleanup);
  +    ap_scoreboard_image = (scoreboard *) m;
  +    ap_scoreboard_image->global.running_generation = 0;
  +}
  +
  +API_EXPORT(void) reopen_scoreboard(ap_context_t *p)
  +{
  +}
  +
  +#elif defined(USE_MMAP_SCOREBOARD)
  +
  +static void setup_shared_mem(ap_context_t *p)
  +{
  +    caddr_t m;
  +
  +#if defined(MAP_ANON)
  +/* BSD style */
  +#ifdef CONVEXOS11
  +    /*
  +     * 9-Aug-97 - Jeff Venters (venters@convex.hp.com)
  +     * ConvexOS maps address space as follows:
  +     *   0x00000000 - 0x7fffffff : Kernel
  +     *   0x80000000 - 0xffffffff : User
  +     * Start mmapped area 1GB above start of text.
  +     *
  +     * Also, the length requires a pointer as the actual length is
  +     * returned (rounded up to a page boundary).
  +     */
  +    {
  +	unsigned len = SCOREBOARD_SIZE;
  +
  +	m = mmap((caddr_t) 0xC0000000, &len,
  +		 PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, NOFD, 0);
  +    }
  +#elif defined(MAP_TMPFILE)
  +    {
  +	char mfile[] = "/tmp/apache_shmem_XXXX";
  +	int fd = mkstemp(mfile);
  +	if (fd == -1) {
  +	    perror("open");
  +	    fprintf(stderr, "%s: Could not open %s\n", ap_server_argv0, mfile);
  +	    exit(APEXIT_INIT);
  +	}
  +	m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
  +		PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  +	if (m == (caddr_t) - 1) {
  +	    perror("mmap");
  +	    fprintf(stderr, "%s: Could not mmap %s\n", ap_server_argv0, mfile);
  +	    exit(APEXIT_INIT);
  +	}
  +	close(fd);
  +	unlink(mfile);
  +    }
  +#else
  +    m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
  +	     PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
  +#endif
  +    if (m == (caddr_t) - 1) {
  +	perror("mmap");
  +	fprintf(stderr, "%s: Could not mmap memory\n", ap_server_argv0);
  +	exit(APEXIT_INIT);
  +    }
  +#else
  +/* Sun style */
  +    int fd;
  +
  +    fd = open("/dev/zero", O_RDWR);
  +    if (fd == -1) {
  +	perror("open");
  +	fprintf(stderr, "%s: Could not open /dev/zero\n", ap_server_argv0);
  +	exit(APEXIT_INIT);
  +    }
  +    m = mmap((caddr_t) 0, SCOREBOARD_SIZE,
  +	     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  +    if (m == (caddr_t) - 1) {
  +	perror("mmap");
  +	fprintf(stderr, "%s: Could not mmap /dev/zero\n", ap_server_argv0);
  +	exit(APEXIT_INIT);
  +    }
  +    close(fd);
  +#endif
  +    ap_scoreboard_image = (scoreboard *) m;
  +    ap_scoreboard_image->global.running_generation = 0;
  +}
  +
  +API_EXPORT(void) reopen_scoreboard(ap_context_t *p)
  +{
  +}
  +
  +#elif defined(USE_SHMGET_SCOREBOARD)
  +static key_t shmkey = IPC_PRIVATE;
  +static int shmid = -1;
  +
  +static void setup_shared_mem(ap_context_t *p)
  +{
  +    struct shmid_ds shmbuf;
  +    const server_rec * server_conf = ap_get_server_conf();
  +#ifdef MOVEBREAK
  +    char *obrk;
  +#endif
  +
  +    if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT | SHM_R | SHM_W)) == -1) {
  +#ifdef LINUX
  +	if (errno == ENOSYS) {
  +	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, server_conf,
  +			 "Your kernel was built without CONFIG_SYSVIPC\n"
  +			 "%s: Please consult the Apache FAQ for details",
  +			 ap_server_argv0);
  +	}
  +#endif
  +	ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf,
  +		    "could not call shmget");
  +	exit(APEXIT_INIT);
  +    }
  +
  +    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, server_conf,
  +		"created shared memory segment #%d", shmid);
  +
  +#ifdef MOVEBREAK
  +    /*
  +     * Some SysV systems place the shared segment WAY too close
  +     * to the dynamic memory break point (sbrk(0)). This severely
  +     * limits the use of malloc/sbrk in the program since sbrk will
  +     * refuse to move past that point.
  +     *
  +     * To get around this, we move the break point "way up there",
  +     * attach the segment and then move break back down. Ugly
  +     */
  +    if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
  +	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
  +	    "sbrk() could not move break");
  +    }
  +#endif
  +
  +#define BADSHMAT	((scoreboard *)(-1))
  +    if ((ap_scoreboard_image = (scoreboard *) shmat(shmid, 0, 0)) == BADSHMAT) {
  +	ap_log_error(APLOG_MARK, APLOG_EMERG, server_conf, "shmat error");
  +	/*
  +	 * We exit below, after we try to remove the segment
  +	 */
  +    }
  +    else {			/* only worry about permissions if we attached the segment */
  +	if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) {
  +	    ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
  +		"shmctl() could not stat segment #%d", shmid);
  +	}
  +	else {
  +	    shmbuf.shm_perm.uid = unixd_config.user_id;
  +	    shmbuf.shm_perm.gid = unixd_config.group_id;
  +	    if (shmctl(shmid, IPC_SET, &shmbuf) != 0) {
  +		ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
  +		    "shmctl() could not set segment #%d", shmid);
  +	    }
  +	}
  +    }
  +    /*
  +     * We must avoid leaving segments in the kernel's
  +     * (small) tables.
  +     */
  +    if (shmctl(shmid, IPC_RMID, NULL) != 0) {
  +	ap_log_error(APLOG_MARK, APLOG_WARNING, server_conf,
  +		"shmctl: IPC_RMID: could not remove shared memory segment #%d",
  +		shmid);
  +    }
  +    if (ap_scoreboard_image == BADSHMAT)	/* now bailout */
  +	exit(APEXIT_INIT);
  +
  +#ifdef MOVEBREAK
  +    if (obrk == (char *) -1)
  +	return;			/* nothing else to do */
  +    if (sbrk(-(MOVEBREAK)) == (char *) -1) {
  +	ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
  +	    "sbrk() could not move break back");
  +    }
  +#endif
  +}
  +
  +API_EXPORT(void) reopen_scoreboard(ap_context_t *p)
  +{
  +}
  +
  +#endif
  +
  +/* Called by parent process */
  +void reinit_scoreboard(ap_context_t *p)
  +{
  +    if (ap_scoreboard_image == NULL) {
  +	setup_shared_mem(p);
  +    }
  +    memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE);
  +}
  +
  +/****
  + * Above code is shmem code. Below code is interacting with the shmem
  + ****/
  +
  +void ap_reset_connection_status(long conn_id)
  +{
  +    int i;
  +
  +    for (i = 0; i < STATUSES_PER_CONNECTION; i++) {
  +        ap_scoreboard_image->table[conn_id][i].key[0] = '\0';
  +    }
  +}
  +
  +/* 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;
  +
  +    while (i < STATUSES_PER_CONNECTION) {
  +        ss = &(ap_scoreboard_image->table[conn_id][i]);
  +        if (ss->key[0] == '\0') {
  +            break;
  +        }
  +        if (0 == strcmp(ss->key, key)) {
  +            return ss->value;
  +        }
  +    }
  +
  +    return NULL;
  +}
  +
  +/* 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;
  +
  +    while (i < STATUSES_PER_CONNECTION) {
  +        ss = &(ap_scoreboard_image->table[conn_id][i]);
  +        if (ss->key[0] == '\0') {
  +            break;
  +        }
  +        if (0 == strcmp(ss->key, key)) {
  +            ap_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;
  +    }
  +    ap_cpystrn(ss->key, key, KEY_LENGTH);
  +    ap_cpystrn(ss->value, value, VALUE_LENGTH);
  +    return;
  +}
  +
  +ap_array_header_t *ap_get_status_table(ap_context_t *p)
  +{
  +    int i, j;
  +    ap_array_header_t *server_status;
  +    ap_status_table_row_t *array_slot;
  +    status_table_entry *ss;
  +
  +    server_status = ap_make_array(p, 0, sizeof(ap_status_table_row_t));
  +    for (i = 0; i < max_daemons_limit*HARD_THREAD_LIMIT; i++) {
  +	if (ap_scoreboard_image->table[i][0].key[0] == '\0')
  +	    continue;
  +        array_slot = ap_push_array(server_status);
  +        array_slot->data = ap_make_table(p, 0);
  +        array_slot->conn_id = i;
  +        
  +        for (j = 0; j < STATUSES_PER_CONNECTION; j++) {
  +	    ss = &(ap_scoreboard_image->table[i][j]);
  +            if (ss->key[0] != '\0') {
  +                ap_table_add(array_slot->data, ss->key, ss->value);
  +            }
  +            else {
  +                break;
  +            }
  +        }
  +    }
  +    return server_status;
  +}
  
  
  
  1.3       +83 -72    apache-2.0/src/modules/mpm/dexter/scoreboard.h
  
  Index: scoreboard.h
  ===================================================================
  RCS file: scoreboard.h
  diff -N scoreboard.h
  --- /dev/null	Tue Oct 12 22:24:04 1999
  +++ /tmp/cvsVJ4375	Tue Oct 12 22:24:16 1999
  @@ -0,0 +1,105 @@
  +/* ====================================================================
  + * Copyright (c) 1995-1999 The Apache Group.  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. All advertising materials mentioning features or use of this 
  + *    software must display the following acknowledgment: 
  + *    "This product includes software developed by the Apache Group 
  + *    for use in the Apache HTTP server project (http://www.apache.org/)." 
  + * 
  + * 4. The names "Apache Server" and "Apache Group" 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 names without prior written 
  + *    permission of the Apache Group. 
  + * 
  + * 6. Redistributions of any form whatsoever must retain the following 
  + *    acknowledgment: 
  + *    "This product includes software developed by the Apache Group 
  + *    for use in the Apache HTTP server project (http://www.apache.org/)." 
  + * 
  + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 GROUP 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 Group and was originally based 
  + * on public domain software written at the National Center for 
  + * Supercomputing Applications, University of Illinois, Urbana-Champaign. 
  + * For more information on the Apache Group and the Apache HTTP server 
  + * project, please see <http://www.apache.org/>. 
  + * 
  + */ 
  +
  +#ifndef APACHE_SCOREBOARD_H
  +#define APACHE_SCOREBOARD_H
  +#include <pthread.h>
  +#ifdef __cplusplus
  +extern "C" {
  +#endif
  +
  +#ifdef TPF
  +#include <time.h>
  +#else
  +#include <sys/times.h>
  +#endif /* TPF */
  +
  +#include "mpm_default.h"	/* For HARD_.*_LIMIT */
  +
  +/* The generic shared memory chunk code */
  +void reinit_scoreboard(ap_context_t *p);
  +#if defined(USE_OS2_SCOREBOARD)
  +caddr_t create_shared_heap(const char *name, size_t size);
  +caddr_t get_shared_heap(const char *Name);
  +#endif
  +
  +API_EXPORT(void) reopen_scoreboard(ap_context_t *p);
  +
  +/* The stuff for Dexter's status table */
  +
  +#include "mpm_status.h"
  +#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];
  +} scoreboard;
  +
  +#define SCOREBOARD_SIZE		sizeof(scoreboard)
  +
  +#ifdef __cplusplus
  +}
  +#endif
  +
  +#endif	/* !APACHE_SCOREBOARD_H */
  
  
  
  1.4       +34 -694   apache-2.0/src/modules/standard/mod_status.c
  
  Index: mod_status.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/standard/mod_status.c,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -d -u -r1.3 -r1.4
  --- mod_status.c	1999/08/31 05:34:03	1.3
  +++ mod_status.c	1999/10/13 05:24:16	1.4
  @@ -55,720 +55,71 @@
    *
    */
   
  -/* 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 ap_table_t 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 "http_conf_globals.h"	/* for ap_extended_status */
  -#include "http_main.h"
  -#include "util_script.h"
  +#include "mpm_status.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"
   #endif
   
   module MODULE_VAR_EXPORT status_module;
   
  -/*
  - *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, char *arg) 
  -{
  -    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
  -    if (err != NULL) {
  -        return err;
  -    }
  -    if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
  -	ap_extended_status = 0;
  -    }
  -    else {
  -	ap_extended_status = 1;
  -    }
  -    return NULL;
  -}
  -
  -static const command_rec status_module_cmds[] =
  -{
  -    { "ExtendedStatus", set_extended_status, NULL, RSRC_CONF, TAKE1,
  -      "\"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)
  +static int print_status_value(void *data, const char *key, const char *val)
   {
  -    long days, hrs, mins, secs;
  +    request_rec *r = (request_rec *) data;
   
  -    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");
  +    ap_rprintf(r, "<dt>%s\n<dd>%s\n", key, val);
  +    return 1;
   }
   
  -/* Main handler for x-httpd-status requests */
  -
  -/* ID values for command ap_table_t */
  -
  -#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)
   {
  -    char *loc;
  +    int i;
  +    ap_array_header_t *server_status;
  +    ap_status_table_row_t *status_rows;
       time_t nowtime = time(NULL);
  -    time_t up_time;
  -    int i, j, 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;
  -    thread_score score_record;
  -    parent_score ps_record;
  -    char stat_buffer[HARD_SERVER_LIMIT][HARD_THREAD_LIMIT];
  -    int pid_buffer[HARD_SERVER_LIMIT];
  -    clock_t tu, ts, tcu, tcs;
  -    server_rec *vhost;
  -
  -    tu = ts = tcu = tcs = 0;
   
  -    if (!ap_exists_scoreboard_image()) {
  -	ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 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 = strstr(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)) == '=')
  -			ap_table_set(r->headers_out,
  -			      status_options[i].hdr_out_str,
  -			      loc + strlen(status_options[i].hdr_out_str) + 1);
  -		    else
  -			ap_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;
  -
  -    ap_sync_scoreboard_image();
  -    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];
  -	res = score_record.status;
  -	stat_buffer[i][j] = status_flags[res];
  -	pid_buffer[i] = (int) ps_record.pid;
  -	if (res == SERVER_READY)
  -	    ready++;
  -	else if (res != SERVER_DEAD && res != SERVER_ACCEPTING
  -	         && res != SERVER_QUEUEING && res != SERVER_STARTING)
  -	    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;
  -
  -    /* ap_hard_timeout("send status info", r); */
  -
  -    if (!short_report) {
  -	ap_rputs(DOCTYPE_HTML_3_2
  -		 "<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);
  -	ap_rvputs(r, "Server Version: ",
  -	  ap_get_server_version(), "<br>\n", NULL);
  -	ap_rvputs(r, "Server Built: ",
  -	  ap_get_server_built(), "<br>\n<hr>\n", NULL);
  -	ap_rvputs(r, "Current Time: ",
  -	  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 (ap_extended_status) {
  -	if (short_report) {
  -	    ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %lu\n",
  -		count, kbcount);
  -
  -#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("<br>\n", r);
  -	}				/* short_report */
  -    }					/* ap_extended_status */
  -
  -    if (!short_report)
  -	ap_rprintf(r, "\n%d connections 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) {
  -	ap_rputc(stat_buffer[i][j], r);
  -	if ((((i * HARD_THREAD_LIMIT) + j) % 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>A</code></B>\" Accepting on port,<BR>\n", r);
  -	ap_rputs("\"<B><code>Q</code></B>\" Queueing connection, \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 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) {
  -		if (stat_buffer[i][j] != '.') {
  -		    ap_rprintf(r, "   %d,%d in state: %c ", pid_buffer[i], j,
  -                        stat_buffer[i][j]);
  -		    if (++k >= 3) {
  -		    	ap_rputs("\n", r);
  -			k = 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>TID<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>TID<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.tv_sec == 0L &&
  -		score_record.start_time.tv_usec == 0L)
  -		req_time = 0L;
  -	    else
  -		req_time =
  -		    ((score_record.stop_time.tv_sec - score_record.start_time.tv_sec) * 1000) +
  -		    ((score_record.stop_time.tv_usec - score_record.start_time.tv_usec) / 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> (pid: %d, tid: %d): %d|%lu|%lu [",
  -				i, (int) ps_record.generation,
  -				(int) ps_record.pid,
  -				(int) j,
  -				(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",
  -			    score_record.client,
  -			    ap_escape_html(r->pool, score_record.request),
  -			    vhost ? 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>-<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<td>%d/%lu/%lu",
  -				i, (int) ps_record.generation,
  -				(int) ps_record.pid, (int) j, (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;
  -			case SERVER_ACCEPTING:
  -			    ap_rputs("<td>A", r);
  -			    break;
  -			case SERVER_QUEUEING:
  -			    ap_rputs("<td>Q", 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",
  -			     score_record.client,
  -			     vhost ? 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>TID<td>OS thread 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>TID<td>OS thread 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 {
  -
  -    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);
  +    server_status = ap_get_status_table(r->pool);
   
  -    }
  +    ap_rputs(DOCTYPE_HTML_3_2
  +    	 "<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);
  +    ap_rvputs(r, "Server Version: ",
  +      ap_get_server_version(), "<br>\n", NULL);
  +    ap_rvputs(r, "Server Built: ",
  +      ap_get_server_built(), "<br>\n<hr>\n", NULL);
  +    ap_rvputs(r, "Current Time: ",
  +      ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), "<br>\n", NULL);
  +    ap_rprintf(r, "\n%d connections currently being processed\n",
  +               server_status->nelts);
   
  -    if (!short_report) {
  -	ap_rputs(ap_psignature("<HR>\n",r), r);
  -	ap_rputs("</BODY></HTML>\n", r);
  +    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);
  +        ap_table_do(print_status_value, (void *) r, status_rows[i].data, NULL);
       }
  -
  -    /* ap_kill_timeout(r); */
  +    ap_rputs("</body></html>\n", r);
       return 0;
   }
   
  -
  -static void status_init(server_rec *s, ap_context_t *p)
  -{
  -    int i;
  -    for (i = 0; i < SERVER_NUM_STATUS; i++)
  -      status_flags[i] = '?';
  -
  -    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';
  -    status_flags[SERVER_ACCEPTING] = 'A';
  -    status_flags[SERVER_QUEUEING] = 'Q';
  -}
  -
   static const handler_rec status_handlers[] =
   {
       {STATUS_MAGIC_TYPE, status_handler},
  @@ -778,23 +129,12 @@
   
   module MODULE_VAR_EXPORT status_module =
   {
  -    STANDARD_MODULE_STUFF,
  -    status_init,		/* initializer */
  -    NULL,			/* dir config creater */
  -    NULL,			/* dir merger --- default is to override */
  +    STANDARD20_MODULE_STUFF,
  +    NULL,			/* create per-dir config */
  +    NULL,			/* merge per-dir config */
       NULL,			/* server config */
       NULL,			/* merge server config */
  -    status_module_cmds,		/* command ap_table_t */
  +    NULL,			/* command table */
       status_handlers,		/* handlers */
  -    NULL,			/* filename translation */
  -    NULL,			/* check_user_id */
  -    NULL,			/* check auth */
  -    NULL,			/* check access */
  -    NULL,			/* type_checker */
  -    NULL,			/* fixups */
  -    NULL,			/* logger */
  -    NULL,			/* header parser */
  -    NULL,			/* child_init */
  -    NULL,			/* child_exit */
  -    NULL			/* post read-request */
  +    NULL                        /* register hooks */
   };