You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/06/29 23:35:51 UTC
[PATCH] http_main big patch
Here's a heads up... The patch below does the following:
- eliminate a starvation that can occur if some sockets on the listener list
are really busy. The sockets further down the list are not considered
on an equal basis.
- clean up duplicate listener code between WIN32 and Unix/OS2
- eliminate the sleep(1) in wait_or_timeout under unix, replace it with a
select, and a tuneable SCOREBOARD_MAINTENANCE_INTERVAL, see httpd.h.
- reduce O(n^2) loops to O(n) loops during scoreboard maintenance.
- eliminate the per-hit idle server check, instead the server kills off
or starts up one child per SCOREBOARD_MAINTENANCE_INTERVAL according
to min/maxspare settings.
- ditch unused old scoreboard code/functions
I've almost got standalone_main() down to a readable size.
I want to commit this tomorrow ... 'cause it needs guinea pigs. I expect
I screwed up the WIN32 part, but I had to touch it in order to deal with
the starvation above.
Dean
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache/src/CHANGES,v
retrieving revision 1.308
diff -c -3 -r1.308 CHANGES
*** CHANGES 1997/06/29 18:26:56 1.308
--- CHANGES 1997/06/29 21:23:50
***************
*** 1,5 ****
--- 1,15 ----
Changes with Apache 1.3
+
+ *) Revamp of (unix) scoreboard management code such that it avoids
+ unnecessary traversals of the scoreboard on each hit. This is
+ particularly important for high volume sites with a large
+ HARD_SERVER_LIMIT. Some of the previous operations were O(n^2),
+ and are now O(n). See also SCOREBOARD_MAINTENANCE_INTERVAL in
+ httpd.h. [Dean Gaudet]
+ *) In configurations using multiple Listen statements it was possible for
+ busy sockets to starve other sockets of service. [Dean Gaudet]
+
*) Add a ListenBacklog directive to control the backlog parameter
passed to listen(). Also change the default to 511 from 512.
[Marc Slemko]
Index: http_conf_globals.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_conf_globals.h,v
retrieving revision 1.12
diff -c -3 -r1.12 http_conf_globals.h
*** http_conf_globals.h 1997/06/28 23:57:55 1.12
--- http_conf_globals.h 1997/06/29 21:23:51
***************
*** 70,75 ****
--- 70,76 ----
extern int daemons_min_free;
extern int daemons_max_free;
extern int daemons_limit;
+ extern int max_daemons_limit;
extern int suexec_enabled;
extern int listenbacklog;
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.170
diff -c -3 -r1.170 http_main.c
*** http_main.c 1997/06/29 19:27:21 1.170
--- http_main.c 1997/06/29 21:24:02
***************
*** 156,170 ****
char *lock_fname;
char *server_argv0;
struct in_addr bind_address;
- listen_rec *listeners;
int daemons_to_start;
int daemons_min_free;
int daemons_max_free;
int daemons_limit;
time_t restart_time;
int suexec_enabled = 0;
int listenbacklog;
char server_root[MAX_STRING_LEN];
char server_confname[MAX_STRING_LEN];
--- 156,190 ----
char *lock_fname;
char *server_argv0;
struct in_addr bind_address;
int daemons_to_start;
int daemons_min_free;
int daemons_max_free;
int daemons_limit;
+ int max_daemons_limit = -1; /* the max of daemons_limit over all restarts */
time_t restart_time;
int suexec_enabled = 0;
int listenbacklog;
+ /*
+ * During config time, listeners is treated as a NULL-terminated list.
+ * child_main previously would start at the beginning of the list each time
+ * through the loop, so a socket early on in the list could easily starve out
+ * sockets later on in the list. The solution is to start at the listener
+ * after the last one processed. But to do that fast/easily in child_main it's
+ * way more convenient for listeners to be a ring that loops back on itself.
+ * The routine setup_listeners() is called after config time to both open up
+ * the sockets and to turn the NULL-terminated list into a ring that loops back
+ * on itself.
+ *
+ * head_listener is used by each child to keep track of what they consider
+ * to be the "start" of the ring. It is also set by make_child to ensure
+ * that new children also don't starve any sockets.
+ *
+ * Note that listeners != NULL is ensured by read_config().
+ */
+ listen_rec *listeners;
+ static listen_rec * APACHE_TLS head_listener;
+
char server_root[MAX_STRING_LEN];
char server_confname[MAX_STRING_LEN];
***************
*** 1102,1151 ****
return old_status;
}
! void update_scoreboard_global()
! {
#ifdef SCOREBOARD_FILE
lseek(scoreboard_fd,
(char *)&scoreboard_image->global-(char *)scoreboard_image,0);
force_write(scoreboard_fd,(char *)&scoreboard_image->global,
sizeof scoreboard_image->global);
#endif
- }
-
- int get_child_status (int child_num)
- {
- if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
- return -1;
- else
- return scoreboard_image->servers[child_num].status;
}
- int count_busy_servers ()
- {
- int i;
- int res = 0;
-
- for (i = 0; i < HARD_SERVER_LIMIT; ++i)
- if (scoreboard_image->servers[i].status == SERVER_BUSY_READ ||
- scoreboard_image->servers[i].status == SERVER_BUSY_WRITE ||
- scoreboard_image->servers[i].status == SERVER_BUSY_KEEPALIVE ||
- scoreboard_image->servers[i].status == SERVER_BUSY_LOG ||
- scoreboard_image->servers[i].status == SERVER_BUSY_DNS)
- ++res;
- return res;
- }
-
- int count_live_servers()
- {
- int i;
- int res = 0;
-
- for (i = 0; i < HARD_SERVER_LIMIT; ++i)
- if (scoreboard_image->servers[i].status != SERVER_DEAD)
- ++res;
- return res;
- }
-
short_score get_scoreboard_info(int i)
{
return (scoreboard_image->servers[i]);
--- 1122,1137 ----
return old_status;
}
! static void update_scoreboard_global()
! {
#ifdef SCOREBOARD_FILE
lseek(scoreboard_fd,
(char *)&scoreboard_image->global-(char *)scoreboard_image,0);
force_write(scoreboard_fd,(char *)&scoreboard_image->global,
sizeof scoreboard_image->global);
#endif
}
short_score get_scoreboard_info(int i)
{
return (scoreboard_image->servers[i]);
***************
*** 1181,1228 ****
}
#endif
- int count_idle_servers ()
- {
- int i;
- int res = 0;
-
- for (i = 0; i < HARD_SERVER_LIMIT; ++i)
- if (scoreboard_image->servers[i].status == SERVER_READY)
- ++res;
-
- return res;
- }
! int find_free_child_num ()
{
! int i;
!
! for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! if (scoreboard_image->servers[i].status == SERVER_DEAD)
! return i;
!
! return -1;
}
! int find_child_by_pid (int pid)
{
int i;
! for (i = 0; i < HARD_SERVER_LIMIT; ++i)
if (scoreboard_image->servers[i].pid == pid)
return i;
return -1;
}
! void reclaim_child_processes ()
{
#ifndef MULTITHREAD
int i, status;
int my_pid = getpid();
sync_scoreboard_image();
! for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
int pid = scoreboard_image->servers[i].pid;
if (pid != my_pid && pid != 0) {
--- 1167,1203 ----
}
#endif
! /* This is used to optimize the scoreboard manipulation routines. We know
! * that over the lifetime of the server, including graceful restarts, that
! * we've never issued a child a slot >= max_daemons_limit.
! */
! static void set_max_daemons_limit (void)
{
! if (daemons_limit > max_daemons_limit) {
! max_daemons_limit = daemons_limit;
! }
}
! static int find_child_by_pid (int pid)
{
int i;
! for (i = 0; i < max_daemons_limit; ++i)
if (scoreboard_image->servers[i].pid == pid)
return i;
return -1;
}
! static void reclaim_child_processes ()
{
#ifndef MULTITHREAD
int i, status;
int my_pid = getpid();
sync_scoreboard_image();
! for (i = 0; i < max_daemons_limit; ++i) {
int pid = scoreboard_image->servers[i].pid;
if (pid != my_pid && pid != 0) {
***************
*** 1292,1298 ****
int status, n;
int ret = 0;
! for (n = 0; n < HARD_SERVER_LIMIT; ++n) {
if (scoreboard_image->servers[n].status != SERVER_DEAD
&& waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG)
== -1
--- 1267,1273 ----
int status, n;
int ret = 0;
! for (n = 0; n < max_daemons_limit; ++n) {
if (scoreboard_image->servers[n].status != SERVER_DEAD
&& waitpid (scoreboard_image->servers[n].pid, &status, WNOHANG)
== -1
***************
*** 1354,1360 ****
return -1;
}
if (ret <= 0) {
! sleep (1);
return -1;
}
return ret;
--- 1329,1339 ----
return -1;
}
if (ret <= 0) {
! struct timeval tv;
!
! tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
! tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
! ap_select(0, NULL, NULL, NULL, &tv);
return -1;
}
return ret;
***************
*** 1881,1894 ****
return s;
}
static listen_rec *old_listeners;
static void copy_listeners(pool *p)
{
listen_rec *lr;
ap_assert(old_listeners == NULL);
! for (lr = listeners; lr; lr = lr->next) {
listen_rec *nr = malloc(sizeof *nr);
if (nr == NULL) {
fprintf (stderr, "Ouch! malloc failed in copy_listeners()\n");
--- 1860,1889 ----
return s;
}
+
+ /*
+ * During a restart we keep track of the old listeners here, so that we
+ * can re-use the sockets. We have to do this because we won't be able
+ * to re-open the sockets ("Address already in use").
+ *
+ * Unlike the listeners ring, old_listeners is a NULL terminated list.
+ *
+ * copy_listeners() makes the copy, find_listener() finds an old listener
+ * and close_unused_listener() cleans up whatever wasn't used.
+ */
static listen_rec *old_listeners;
+ /* unfortunately copy_listeners may be called before listeners is a ring */
static void copy_listeners(pool *p)
{
listen_rec *lr;
ap_assert(old_listeners == NULL);
! if (listeners == NULL) {
! return;
! }
! lr = listeners;
! do {
listen_rec *nr = malloc(sizeof *nr);
if (nr == NULL) {
fprintf (stderr, "Ouch! malloc failed in copy_listeners()\n");
***************
*** 1899,1905 ****
nr->next = old_listeners;
ap_assert(!nr->used);
old_listeners = nr;
! }
}
--- 1894,1901 ----
nr->next = old_listeners;
ap_assert(!nr->used);
old_listeners = nr;
! lr = lr->next;
! } while (lr && lr != listeners);
}
***************
*** 1931,1936 ****
--- 1927,1979 ----
}
+ /* open sockets, and turn the listeners list into a singly linked ring */
+ static void setup_listeners(pool *pconf)
+ {
+ listen_rec *lr;
+ int fd;
+
+ listenmaxfd = -1;
+ FD_ZERO (&listenfds);
+ lr = listeners;
+ for(;;) {
+ fd = find_listener (lr);
+ if (fd < 0) {
+ fd = make_sock (pconf, &lr->local_addr);
+ }
+ FD_SET (fd, &listenfds);
+ if (fd > listenmaxfd) listenmaxfd = fd;
+ lr->fd = fd;
+ if (lr->next == NULL) break;
+ lr = lr->next;
+ }
+ /* turn the list into a ring */
+ lr->next = listeners;
+ head_listener = listeners;
+ close_unused_listeners ();
+ }
+
+
+ /*
+ * Find a listener which is ready for accept(). This advances the
+ * head_listener global.
+ */
+ static listen_rec *find_ready_listener(fd_set *main_fds)
+ {
+ listen_rec *lr;
+
+ lr = head_listener;
+ do {
+ if (FD_ISSET(lr->fd, main_fds)) {
+ head_listener = lr->next;
+ return (lr);
+ }
+ lr = lr->next;
+ } while (lr != head_listener);
+ return NULL;
+ }
+
+
static int s_iInitCount = 0;
int
***************
*** 2072,2079 ****
if (scoreboard_image->global.exit_generation >= generation)
exit(0);
! if ((count_idle_servers() >= daemons_max_free)
! || (max_requests_per_child > 0
&& ++requests_this_child >= max_requests_per_child))
{
exit(0);
--- 2115,2121 ----
if (scoreboard_image->global.exit_generation >= generation)
exit(0);
! if ((max_requests_per_child > 0
&& ++requests_this_child >= max_requests_per_child))
{
exit(0);
***************
*** 2103,2111 ****
if (srv <= 0)
continue;
! for (lr = listeners; lr; lr = lr->next) {
! if (FD_ISSET(lr->fd, &main_fds)) break;
! }
if (lr == NULL) continue;
sd = lr->fd;
--- 2145,2151 ----
if (srv <= 0)
continue;
! lr = find_ready_listener(&main_fds);
if (lr == NULL) continue;
sd = lr->fd;
***************
*** 2258,2264 ****
}
}
! int make_child(server_rec *server_conf, int child_num)
{
int pid;
--- 2298,2304 ----
}
}
! static int make_child(server_rec *server_conf, int child_num)
{
int pid;
***************
*** 2268,2273 ****
--- 2308,2316 ----
child_main (child_num);
}
+ /* avoid starvation */
+ head_listener = head_listener->next;
+
Explain1 ("Starting new child in slot %d", child_num);
(void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL);
***************
*** 2311,2316 ****
--- 2354,2432 ----
}
+ /* start up a bunch of children */
+ static void startup_children (int number_to_start)
+ {
+ int i;
+
+ for (i = 0; number_to_start && i < daemons_limit; ++i ) {
+ if (scoreboard_image->servers[i].status != SERVER_DEAD) {
+ continue;
+ }
+ if (make_child (server_conf, i) < 0) {
+ break;
+ }
+ --number_to_start;
+ }
+ }
+
+
+ static void perform_idle_server_maintenance ()
+ {
+ int i;
+ int to_kill;
+ int free_slot;
+ int idle_count;
+
+ free_slot = -1;
+ to_kill = -1;
+ idle_count = 0;
+ sync_scoreboard_image ();
+ for (i = 0; i < daemons_limit; ++i) {
+ switch (scoreboard_image->servers[i].status) {
+ case SERVER_READY:
+ ++idle_count;
+ /* always kill the highest numbered child if we have to...
+ * no really well thought out reason ... other than observing
+ * the server behaviour under linux where lower numbered children
+ * tend to service more hits (and hence are more likely to have
+ * their data in cpu caches).
+ */
+ to_kill = i;
+ break;
+ case SERVER_DEAD:
+ /* try to keep children numbers as low as possible */
+ if (free_slot == -1) {
+ free_slot = i;
+ }
+ break;
+ }
+ }
+ if (idle_count > daemons_max_free) {
+ /* kill off one child... we use SIGUSR1 because that'll cause it to
+ * shut down gracefully, in case it happened to pick up a request
+ * while we were counting
+ */
+ kill (SIGUSR1, scoreboard_image->servers[to_kill].pid);
+ } else if (idle_count < daemons_min_free) {
+ if (free_slot == -1) {
+ /* only report this condition once */
+ static int reported = 0;
+
+ if (!reported) {
+ log_printf (server_conf,
+ "server reached MaxClients setting, consider"
+ " raising the MaxClients setting");
+ reported = 1;
+ }
+ } else {
+ make_child (server_conf, free_slot);
+ }
+ }
+ }
+
+
+
/*****************************************************************
* Executive routines.
*/
***************
*** 2318,2327 ****
void standalone_main(int argc, char **argv)
{
int remaining_children_to_start;
- listen_rec *lr;
standalone = 1;
- listenmaxfd = -1;
is_graceful = 0;
++generation;
--- 2434,2441 ----
***************
*** 2342,2363 ****
ptrans = make_sub_pool (pconf);
server_conf = read_config (pconf, ptrans, server_confname);
!
! listenmaxfd = -1;
! FD_ZERO (&listenfds);
! for (lr = listeners; lr != NULL; lr = lr->next) {
! int fd;
!
! fd = find_listener (lr);
! if (fd < 0) {
! fd = make_sock (pconf, &lr->local_addr);
! }
! FD_SET (fd, &listenfds);
! if (fd > listenmaxfd) listenmaxfd = fd;
! lr->fd = fd;
! }
! close_unused_listeners ();
!
init_modules (pconf, server_conf);
open_logs (server_conf, pconf);
set_group_privs ();
--- 2456,2463 ----
ptrans = make_sub_pool (pconf);
server_conf = read_config (pconf, ptrans, server_confname);
! set_max_daemons_limit();
! setup_listeners (pconf);
init_modules (pconf, server_conf);
open_logs (server_conf, pconf);
set_group_privs ();
***************
*** 2371,2377 ****
note_cleanups_for_fd (pconf, scoreboard_fd);
}
#endif
-
default_server_hostnames (server_conf);
set_signals ();
--- 2471,2476 ----
***************
*** 2393,2402 ****
remaining_children_to_start = daemons_limit;
}
if (!is_graceful) {
! while (remaining_children_to_start) {
! --remaining_children_to_start;
! make_child (server_conf, remaining_children_to_start);
! }
}
log_error ("Server configured -- resuming normal operations",
--- 2492,2499 ----
remaining_children_to_start = daemons_limit;
}
if (!is_graceful) {
! startup_children (remaining_children_to_start);
! remaining_children_to_start = 0;
}
log_error ("Server configured -- resuming normal operations",
***************
*** 2419,2424 ****
--- 2516,2531 ----
if (child_slot >= 0) {
(void)update_child_status (child_slot, SERVER_DEAD,
(request_rec *)NULL);
+ if (remaining_children_to_start
+ && child_slot < daemons_limit) {
+ /* we're still doing a 1-for-1 replacement of dead
+ * children with new children
+ */
+ make_child (server_conf, child_slot);
+ --remaining_children_to_start;
+ /* don't perform idle maintenance yet */
+ continue;
+ }
} else if (is_graceful) {
/* Great, we've probably just lost a slot in the
* scoreboard. Somehow we don't know about this
***************
*** 2432,2449 ****
* generation of children needed to be reaped... so assume
* they're all done, and pick up the slack if any is left.
*/
! while (remaining_children_to_start > 0) {
! child_slot = find_free_child_num ();
! if (child_slot < 0 || child_slot >= daemons_limit) {
! remaining_children_to_start = 0;
! break;
! }
! if (make_child (server_conf, child_slot) < 0) {
! remaining_children_to_start = 0;
! break;
! }
! --remaining_children_to_start;
! }
/* In any event we really shouldn't do the code below because
* few of the servers we just started are in the IDLE state
* yet, so we'd mistakenly create an extra server.
--- 2539,2546 ----
* generation of children needed to be reaped... so assume
* they're all done, and pick up the slack if any is left.
*/
! startup_children (remaining_children_to_start);
! remaining_children_to_start = 0;
/* In any event we really shouldn't do the code below because
* few of the servers we just started are in the IDLE state
* yet, so we'd mistakenly create an extra server.
***************
*** 2451,2466 ****
continue;
}
! sync_scoreboard_image ();
! if ((remaining_children_to_start
! || (count_idle_servers () < daemons_min_free))
! && (child_slot = find_free_child_num ()) >= 0
! && child_slot < daemons_limit) {
! make_child (server_conf, child_slot);
! }
! if (remaining_children_to_start) {
! --remaining_children_to_start;
! }
}
/* we've been told to restart */
--- 2548,2554 ----
continue;
}
! perform_idle_server_maintenance();
}
/* we've been told to restart */
***************
*** 2581,2586 ****
--- 2669,2675 ----
suexec_enabled = init_suexec();
server_conf = read_config (pconf, ptrans, server_confname);
+ set_max_daemons_limit();
init_modules (pconf, server_conf);
if(standalone) {
***************
*** 2797,2802 ****
--- 2886,2898 ----
requests_this_child = 0;
(void)update_child_status(child_num, SERVER_READY, (request_rec*)NULL);
+ /* XXX: Unlike the make_child code under Unix, there's still a starvation
+ * condition here under WIN32. All new threads start off at the first
+ * socket, which gives it higher than average preference. Note that
+ * head_listener is necessarily thread specific data.
+ */
+ head_listener = listeners;
+
/*
* Setup the jump buffers so that we can return here after
* a signal or a timeout (yeah, I know, same thing).
***************
*** 3000,3006 ****
int max_jobs_after_exit_request;
standalone = 1;
! sd = listenmaxfd = -1;
nthreads = threads_per_child;
max_jobs_after_exit_request = excess_requests_per_child;
max_jobs_per_exe = max_requests_per_child;
--- 3096,3102 ----
int max_jobs_after_exit_request;
standalone = 1;
! sd = -1;
nthreads = threads_per_child;
max_jobs_after_exit_request = excess_requests_per_child;
max_jobs_per_exe = max_requests_per_child;
***************
*** 3022,3049 ****
default_server_hostnames (server_conf);
acquire_mutex(start_mutex);
- {
- listen_rec *lr;
- int fd;
-
- listenmaxfd = -1;
- FD_ZERO(&listenfds);
-
- for (lr=listeners; lr != NULL; lr=lr->next)
- {
- fd=find_listener(lr);
- if(fd < 0)
- {
- fd = make_sock(pconf, &lr->local_addr);
- }
- FD_SET(fd, &listenfds);
- if (fd > listenmaxfd) listenmaxfd = fd;
- lr->fd=fd;
- }
- close_unused_listeners();
- sd = -1;
- }
set_signals();
/*
--- 3118,3125 ----
default_server_hostnames (server_conf);
acquire_mutex(start_mutex);
+ setup_listeners(pconf);
set_signals();
/*
***************
*** 3086,3102 ****
start_mutex_released = 1;
/* set the listen queue to 1 */
{
! listen_rec *lr;
! for (lr=listeners; lr != NULL; lr=lr->next)
! {
/* to prove a point - Ben */
ap_assert(!lr->used);
if(lr->used)
{
listen(lr->fd, 1);
}
! }
}
}
if(!start_exit)
--- 3162,3178 ----
start_mutex_released = 1;
/* set the listen queue to 1 */
{
! listen_rec *lr = listeners;
! do {
/* to prove a point - Ben */
ap_assert(!lr->used);
if(lr->used)
{
listen(lr->fd, 1);
}
! lr = lr->next;
! } while (lr != listeners);
}
}
if(!start_exit)
***************
*** 3142,3162 ****
{
listen_rec *lr;
! int fd;
!
! for (lr=listeners; lr != NULL; lr=lr->next)
! {
! /* if(!lr->used)
! continue;*/
! fd=lr->fd;
!
! if(FD_ISSET(fd, &listenfds))
! {
! sd = fd;
! break;
! }
}
! }
do {
clen = sizeof(sa_client);
--- 3218,3229 ----
{
listen_rec *lr;
!
! lr = find_ready_listener (&listenfds);
! if (lr != NULL) {
! sd = lr->fd;
}
! }
do {
clen = sizeof(sa_client);
***************
*** 3198,3205 ****
{
listen_rec *lr;
! for (lr=listeners; lr != NULL; lr=lr->next)
! {
/* prove the point again */
ap_assert(!lr->used);
if(lr->used)
--- 3265,3272 ----
{
listen_rec *lr;
! lr = listeners;
! do {
/* prove the point again */
ap_assert(!lr->used);
if(lr->used)
***************
*** 3207,3213 ****
closesocket(lr->fd);
lr->fd = -1;
}
! }
}
for(i=0; i<nthreads; i++)
--- 3274,3281 ----
closesocket(lr->fd);
lr->fd = -1;
}
! lr = lr->next;
! } while (lr != listeners);
}
for(i=0; i<nthreads; i++)
***************
*** 3468,3473 ****
--- 3536,3542 ----
setup_prelinked_modules();
server_conf = read_config (pconf, ptrans, server_confname);
+ set_max_daemons_limit();
init_modules (pconf, server_conf);
suexec_enabled = init_suexec();
open_logs(server_conf, pconf);
Index: http_main.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.h,v
retrieving revision 1.11
diff -c -3 -r1.11 http_main.h
*** http_main.h 1997/06/15 19:22:26 1.11
--- http_main.h 1997/06/29 21:24:02
***************
*** 93,101 ****
void sync_scoreboard_image ();
int update_child_status (int child_num, int status, request_rec *r);
- int get_child_status (int child_num);
- int count_busy_servers ();
- int count_idle_servers ();
-
unsigned int set_callback_and_alarm(void (*fn)(int), int x);
int check_alarm();
--- 93,97 ----
Index: httpd.h
===================================================================
RCS file: /export/home/cvs/apache/src/httpd.h,v
retrieving revision 1.119
diff -c -3 -r1.119 httpd.h
*** httpd.h 1997/06/29 19:19:36 1.119
--- httpd.h 1997/06/29 21:24:04
***************
*** 231,236 ****
--- 231,251 ----
#define HARD_SERVER_LIMIT 256
#endif
+ /*
+ * (Unix, OS/2 only)
+ * Interval, in microseconds, between scoreboard maintenance. During
+ * each scoreboard maintenance cycle the parent decides if it needs to
+ * spawn a new child (to meet MinSpareServers requirements), or kill off
+ * a child (to meet MaxSpareServers requirements). It will only spawn or
+ * kill one child per cycle. Setting this too low will chew cpu. The
+ * default is probably sufficient for everyone. But some people may want
+ * to raise this on servers which aren't dedicated to httpd and where they
+ * don't like the httpd waking up each second to see what's going on.
+ */
+ #ifndef SCOREBOARD_MAINTENANCE_INTERVAL
+ #define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
+ #endif
+
/* Number of requests to try to handle in a single process. If <= 0,
* the children don't die off. That's the default here, since I'm still
* interested in finding and stanching leaks.
Index: mod_status.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_status.c,v
retrieving revision 1.48
diff -c -3 -r1.48 mod_status.c
*** mod_status.c 1997/06/24 00:32:31 1.48
--- mod_status.c 1997/06/29 21:24:06
***************
*** 96,101 ****
--- 96,102 ----
#include <time.h>
#include "scoreboard.h"
#include "http_log.h"
+ #include "http_conf_globals.h"
#ifdef NEXT
#include <machine/param.h>
***************
*** 279,285 ****
return 0;
sync_scoreboard_image();
! for (i = 0; i<HARD_SERVER_LIMIT; ++i)
{
score_record = get_scoreboard_info(i);
res = score_record.status;
--- 280,286 ----
return 0;
sync_scoreboard_image();
! for (i = 0; i<max_daemons_limit; ++i)
{
score_record = get_scoreboard_info(i);
res = score_record.status;
***************
*** 398,404 ****
else
rputs("Scoreboard: ",r);
! for (i = 0; i<HARD_SERVER_LIMIT; ++i)
{
rputc(stat_buffer[i], r);
if((i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))&&!short_report)
--- 399,405 ----
else
rputs("Scoreboard: ",r);
! for (i = 0; i<max_daemons_limit; ++i)
{
rputc(stat_buffer[i], r);
if((i%STATUS_MAXLINE == (STATUS_MAXLINE - 1))&&!short_report)
***************
*** 434,440 ****
#endif
! for (i = 0; i<HARD_SERVER_LIMIT; ++i)
{
score_record=get_scoreboard_info(i);
lres = score_record.access_count;
--- 435,441 ----
#endif
! for (i = 0; i<max_daemons_limit; ++i)
{
score_record=get_scoreboard_info(i);
lres = score_record.access_count;