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[] = {