You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by Dean Gaudet <dg...@hyperreal.com> on 1997/06/30 23:10:06 UTC
cvs commit: apache/src CHANGES http_main.c http_main.h httpd.h
dgaudet 97/06/30 14:10:05
Modified: src CHANGES http_main.c http_main.h httpd.h
Log:
Unix scoreboard management revamp/cleanup. Including a tweaked
put_scoreboard_info from Harrie Hazewinkel's SNMP patch. Fix starvation
problem with multiple Listens and a busy socket. Early versions of this
patch were reviewed by Marc, Ben, Randy and Jim.
Revision Changes Path
1.313 +11 -1 apache/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /export/home/cvs/apache/src/CHANGES,v
retrieving revision 1.312
retrieving revision 1.313
diff -C3 -r1.312 -r1.313
*** CHANGES 1997/06/30 20:30:51 1.312
--- CHANGES 1997/06/30 21:09:56 1.313
***************
*** 1,5 ****
Changes with Apache 1.3
!
*) API: It's possible to replace standalone_main (define STANDALONE_MAIN)
and it's possible to use SFIO for the underlying i/o layer.
[Doug MacEachern]
--- 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]
!
*) API: It's possible to replace standalone_main (define STANDALONE_MAIN)
and it's possible to use SFIO for the underlying i/o layer.
[Doug MacEachern]
1.172 +248 -197 apache/src/http_main.c
Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.171
retrieving revision 1.172
diff -C3 -r1.171 -r1.172
*** http_main.c 1997/06/30 20:28:51 1.171
--- http_main.c 1997/06/30 21:09:58 1.172
***************
*** 156,162 ****
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;
--- 156,161 ----
***************
*** 165,170 ****
--- 164,196 ----
int suexec_enabled = 0;
int listenbacklog;
+ /*
+ * The max child slot ever assigned, preserved across restarts. Necessary
+ * to deal with MaxClients changes across SIGUSR1 restarts. We use this
+ * value to optimize routines that have to scan the entire scoreboard.
+ */
+ static int max_daemons_limit = -1;
+
+ /*
+ * 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 *head_listener;
+
char server_root[MAX_STRING_LEN];
char server_confname[MAX_STRING_LEN];
***************
*** 919,932 ****
/* XXX: things are seriously screwed if we ever have to do a partial
* read or write ... we could get a corrupted scoreboard
*/
! static int force_write (int fd, char *buffer, int bufsz)
{
int rv, orig_sz = bufsz;
do {
rv = write (fd, buffer, bufsz);
if (rv > 0) {
! buffer += rv;
bufsz -= rv;
}
} while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
--- 945,958 ----
/* XXX: things are seriously screwed if we ever have to do a partial
* read or write ... we could get a corrupted scoreboard
*/
! static int force_write (int fd, void *buffer, int bufsz)
{
int rv, orig_sz = bufsz;
do {
rv = write (fd, buffer, bufsz);
if (rv > 0) {
! buffer = (char *)buffer + rv;
bufsz -= rv;
}
} while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
***************
*** 934,947 ****
return rv < 0? rv : orig_sz - bufsz;
}
! static int force_read (int fd, char *buffer, int bufsz)
{
int rv, orig_sz = bufsz;
do {
rv = read (fd, buffer, bufsz);
if (rv > 0) {
! buffer += rv;
bufsz -= rv;
}
} while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
--- 960,973 ----
return rv < 0? rv : orig_sz - bufsz;
}
! static int force_read (int fd, void *buffer, int bufsz)
{
int rv, orig_sz = bufsz;
do {
rv = read (fd, buffer, bufsz);
if (rv > 0) {
! buffer = (char *)buffer + rv;
bufsz -= rv;
}
} while ((rv > 0 && bufsz > 0) || (rv == -1 && errno == EINTR));
***************
*** 977,984 ****
memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image));
scoreboard_image->global.exit_generation=exit_gen;
! force_write (scoreboard_fd, (char*)scoreboard_image,
! sizeof(*scoreboard_image));
#endif
}
--- 1003,1009 ----
memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image));
scoreboard_image->global.exit_generation=exit_gen;
! force_write (scoreboard_fd, scoreboard_image, sizeof(*scoreboard_image));
#endif
}
***************
*** 1036,1043 ****
{
#ifdef SCOREBOARD_FILE
lseek (scoreboard_fd, 0L, 0);
! force_read (scoreboard_fd, (char*)scoreboard_image,
! sizeof(*scoreboard_image));
#endif
}
--- 1061,1067 ----
{
#ifdef SCOREBOARD_FILE
lseek (scoreboard_fd, 0L, 0);
! force_read (scoreboard_fd, scoreboard_image, sizeof(*scoreboard_image));
#endif
}
***************
*** 1048,1053 ****
--- 1072,1089 ----
return (scoreboard_image ? 1 : 0);
}
+ static inline void put_scoreboard_info(int child_num,
+ short_score *new_score_rec)
+ {
+ #ifndef SCOREBOARD_FILE
+ memcpy(&scoreboard_image->servers[child_num], new_score_rec,
+ sizeof(short_score));
+ #else
+ lseek(scoreboard_fd, (long)child_num * sizeof(short_score), 0);
+ force_write(scoreboard_fd, new_score_rec, sizeof(short_score));
+ #endif
+ }
+
int update_child_status (int child_num, int status, request_rec *r)
{
int old_status;
***************
*** 1092,1151 ****
}
#endif
! #ifndef SCOREBOARD_FILE
! memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof new_score_rec);
! #else
! lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
! force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
! #endif
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]);
--- 1128,1148 ----
}
#endif
! put_scoreboard_info(child_num, &new_score_rec);
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,&scoreboard_image->global,
sizeof scoreboard_image->global);
#endif
}
short_score get_scoreboard_info(int i)
{
return (scoreboard_image->servers[i]);
***************
*** 1171,1228 ****
times(&new_score_rec.times);
!
! #ifndef SCOREBOARD_FILE
! memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof(short_score));
! #else
! lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
! force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
! #endif
}
#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) {
--- 1168,1197 ----
times(&new_score_rec.times);
! put_scoreboard_info(child_num, &new_score_rec);
}
#endif
! 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
--- 1261,1267 ----
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
***************
*** 1346,1351 ****
--- 1315,1321 ----
return(-1);
#else /* WIN32 */
+ struct timeval tv;
#ifndef NEED_WAITPID
int ret;
***************
*** 1353,1369 ****
if (ret == -1 && errno == EINTR) {
return -1;
}
! if (ret <= 0) {
! sleep (1);
! return -1;
}
- return ret;
#else
! if (!reap_children ()) {
! sleep(1);
}
- return -1;
#endif
#endif /* WIN32 */
}
--- 1323,1340 ----
if (ret == -1 && errno == EINTR) {
return -1;
}
! if (ret > 0) {
! return ret;
}
#else
! if (reap_children ()) {
! return -1;
}
#endif
+ tv.tv_sec = SCOREBOARD_MAINTENANCE_INTERVAL / 1000000;
+ tv.tv_usec = SCOREBOARD_MAINTENANCE_INTERVAL % 1000000;
+ ap_select(0, NULL, NULL, NULL, &tv);
+ return -1;
#endif /* WIN32 */
}
***************
*** 1458,1471 ****
if (sigaction (SIGTERM, &sa, NULL) < 0)
log_unixerr ("sigaction(SIGTERM)", NULL, NULL, server_conf);
! /* wait_or_timeout uses sleep() which could deliver a SIGALRM just as we're
! * trying to process the restart requests. That's not good. So we avoid
! * the race condition between when the restart request is made and when the
! * handler is invoked.
! *
! * We also want to ignore HUPs and USR1 while we're busy processing one.
! */
! sigaddset (&sa.sa_mask, SIGALRM);
sigaddset (&sa.sa_mask, SIGHUP);
sigaddset (&sa.sa_mask, SIGUSR1);
sa.sa_handler = (void (*)())restart;
--- 1429,1435 ----
if (sigaction (SIGTERM, &sa, NULL) < 0)
log_unixerr ("sigaction(SIGTERM)", NULL, NULL, server_conf);
! /* we want to ignore HUPs and USR1 while we're busy processing one */
sigaddset (&sa.sa_mask, SIGHUP);
sigaddset (&sa.sa_mask, SIGUSR1);
sa.sa_handler = (void (*)())restart;
***************
*** 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");
--- 1845,1874 ----
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;
! }
}
--- 1879,1886 ----
nr->next = old_listeners;
ap_assert(!nr->used);
old_listeners = nr;
! lr = lr->next;
! } while (lr && lr != listeners);
}
***************
*** 1931,1936 ****
--- 1912,1964 ----
}
+ /* 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 inline 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);
--- 2100,2106 ----
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;
--- 2130,2136 ----
if (srv <= 0)
continue;
! lr = find_ready_listener(&main_fds);
if (lr == NULL) continue;
sd = lr->fd;
***************
*** 2269,2284 ****
}
}
! int make_child(server_rec *server_conf, int child_num)
{
int pid;
if (one_process) {
signal (SIGHUP, (void (*)())just_die);
signal (SIGTERM, (void (*)())just_die);
child_main (child_num);
}
Explain1 ("Starting new child in slot %d", child_num);
(void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL);
--- 2294,2316 ----
}
}
! static int make_child(server_rec *server_conf, int child_num)
{
int pid;
+ if (child_num + 1 > max_daemons_limit) {
+ max_daemons_limit = child_num + 1;
+ }
+
if (one_process) {
signal (SIGHUP, (void (*)())just_die);
signal (SIGTERM, (void (*)())just_die);
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);
***************
*** 2322,2327 ****
--- 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.
*/
***************
*** 2332,2341 ****
void standalone_main(int argc, char **argv)
{
int remaining_children_to_start;
- listen_rec *lr;
standalone = 1;
- listenmaxfd = -1;
is_graceful = 0;
++generation;
--- 2437,2444 ----
***************
*** 2356,2377 ****
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 ();
--- 2459,2465 ----
ptrans = make_sub_pool (pconf);
server_conf = read_config (pconf, ptrans, server_confname);
! setup_listeners (pconf);
init_modules (pconf, server_conf);
open_logs (server_conf, pconf);
set_group_privs ();
***************
*** 2385,2391 ****
note_cleanups_for_fd (pconf, scoreboard_fd);
}
#endif
-
default_server_hostnames (server_conf);
set_signals ();
--- 2473,2478 ----
***************
*** 2407,2416 ****
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",
--- 2494,2501 ----
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",
***************
*** 2433,2438 ****
--- 2518,2533 ----
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
***************
*** 2446,2463 ****
* 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.
--- 2541,2548 ----
* 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.
***************
*** 2465,2480 ****
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 */
--- 2550,2556 ----
continue;
}
! perform_idle_server_maintenance();
}
/* we've been told to restart */
***************
*** 3018,3024 ****
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;
--- 3094,3100 ----
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;
***************
*** 3040,3067 ****
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();
/*
--- 3116,3123 ----
default_server_hostnames (server_conf);
acquire_mutex(start_mutex);
+ setup_listeners(pconf);
set_signals();
/*
***************
*** 3090,3095 ****
--- 3146,3154 ----
{
child_handles[i] = create_thread((void (*)(void *))child_main, (void *)i);
}
+ if (nthreads > max_daemons_limit) {
+ max_daemons_limit = nthreads;
+ }
}
/* main loop */
***************
*** 3104,3120 ****
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)
--- 3163,3179 ----
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)
***************
*** 3160,3180 ****
{
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);
--- 3219,3230 ----
{
listen_rec *lr;
!
! lr = find_ready_listener (&listenfds);
! if (lr != NULL) {
! sd = lr->fd;
}
! }
do {
clen = sizeof(sa_client);
***************
*** 3216,3223 ****
{
listen_rec *lr;
! for (lr=listeners; lr != NULL; lr=lr->next)
! {
/* prove the point again */
ap_assert(!lr->used);
if(lr->used)
--- 3266,3273 ----
{
listen_rec *lr;
! lr = listeners;
! do {
/* prove the point again */
ap_assert(!lr->used);
if(lr->used)
***************
*** 3225,3231 ****
closesocket(lr->fd);
lr->fd = -1;
}
! }
}
for(i=0; i<nthreads; i++)
--- 3275,3282 ----
closesocket(lr->fd);
lr->fd = -1;
}
! lr = lr->next;
! } while (lr != listeners);
}
for(i=0; i<nthreads; i++)
1.12 +0 -4 apache/src/http_main.h
Index: http_main.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -C3 -r1.11 -r1.12
*** http_main.h 1997/06/15 19:22:26 1.11
--- http_main.h 1997/06/30 21:10:01 1.12
***************
*** 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 ----
1.120 +15 -0 apache/src/httpd.h
Index: httpd.h
===================================================================
RCS file: /export/home/cvs/apache/src/httpd.h,v
retrieving revision 1.119
retrieving revision 1.120
diff -C3 -r1.119 -r1.120
*** httpd.h 1997/06/29 19:19:36 1.119
--- httpd.h 1997/06/30 21:10:02 1.120
***************
*** 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.