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.
  
  
  

Reply via email to