httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@hyperreal.com>
Subject cvs commit: apache/src CHANGES alloc.c alloc.h http_main.c http_protocol.c mod_browser.c mod_include.c mod_rewrite.c mod_status.c scoreboard.h
Date Thu, 24 Apr 1997 23:35:30 GMT
dgaudet     97/04/24 16:35:29

  Modified:    src       CHANGES alloc.c alloc.h http_main.c
                        http_protocol.c  mod_browser.c mod_include.c
                        mod_rewrite.c mod_status.c  scoreboard.h
  Log:
  Graceful restarts, reliable signals, and memory fixes.
  
  Reviewed by:	Paul S., Roy, (and others reviewed earlier incarnations)
  
  Revision  Changes    Path
  1.248     +12 -0     apache/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache/src/CHANGES,v
  retrieving revision 1.247
  retrieving revision 1.248
  diff -C3 -r1.247 -r1.248
  *** CHANGES	1997/04/24 23:28:44	1.247
  --- CHANGES	1997/04/24 23:35:18	1.248
  ***************
  *** 1,4 ****
  --- 1,16 ----
    Changes with Apache 1.2
  +   
  +   *) Fix graceful restart on architectures not using scoreboard files
  +      (it is still broken on scoreboard-file architectures).
  +      Eliminate many signal-related race conditions in both forms of
  +      restart, and in SIGTERM.  See htdocs/manual/stopping.html for
  +      details on stopping and restarting the parent.
  +      [Dean Gaudet]
  + 
  +   *) Fix memory leaks in mod_rewrite, mod_browser, mod_include.  Tune
  +      memory allocator to avoid a behaviour that required extra blocks to
  +      be allocated.
  +      [Dean Gaudet]
    
      *) Allow suexec to access files relative to current directory but not
         above.  (Excluding leading / or any .. directory.)  [Ken Coar]
  
  
  
  1.27      +12 -4     apache/src/alloc.c
  
  Index: alloc.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/alloc.c,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -C3 -r1.26 -r1.27
  *** alloc.c	1997/04/07 10:58:38	1.26
  --- alloc.c	1997/04/24 23:35:18	1.27
  ***************
  *** 185,194 ****
       * on the free list...
       */
    
  -   min_size += BLOCK_MINFREE;
  - 
      while (blok != NULL) {
  !     if (min_size <= blok->h.endp - blok->h.first_avail) {
          *lastptr = blok->h.next;
          blok->h.next = NULL;
          return blok;
  --- 185,192 ----
       * on the free list...
       */
    
      while (blok != NULL) {
  !     if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) {
          *lastptr = blok->h.next;
          blok->h.next = NULL;
          return blok;
  ***************
  *** 201,207 ****
    
      /* Nope. */
    
  !   return malloc_block (min_size);
    }
    
    
  --- 199,206 ----
    
      /* Nope. */
    
  !   min_size += BLOCK_MINFREE;
  !   return malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
    }
    
    
  ***************
  *** 896,901 ****
  --- 895,909 ----
        register_cleanup (p, (void *)preg, regex_cleanup, regex_cleanup);
    
        return preg;
  + }
  + 
  + 
  + void pregfree(pool *p, regex_t *reg)
  + {
  +     block_alarms();
  +     regfree (reg);
  +     kill_cleanup (p, (void *)reg, regex_cleanup);
  +     unblock_alarms();
    }
    
    /*****************************************************************
  
  
  
  1.19      +6 -3      apache/src/alloc.h
  
  Index: alloc.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/alloc.h,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -C3 -r1.18 -r1.19
  *** alloc.h	1997/04/07 10:58:38	1.18
  --- alloc.h	1997/04/24 23:35:19	1.19
  ***************
  *** 210,216 ****
    void note_cleanups_for_fd (pool *, int);
    void kill_cleanups_for_fd (pool *p, int fd);
    
  ! regex_t *pregcomp(pool *p, const char *pattern, int cflags);
    
    /* routines to note closes... file descriptors are constrained enough
     * on some systems that we want to support this.
  --- 210,217 ----
    void note_cleanups_for_fd (pool *, int);
    void kill_cleanups_for_fd (pool *p, int fd);
    
  ! regex_t *pregcomp (pool *p, const char *pattern, int cflags);
  ! void pregfree (pool *p, regex_t *reg);
    
    /* routines to note closes... file descriptors are constrained enough
     * on some systems that we want to support this.
  ***************
  *** 236,244 ****
                     FILE **pipe_err);
    #define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL)
    
  ! /* magic numbers --- only one so far, min free bytes in a new pool block */
    
  ! #define BLOCK_MINFREE 8192     
    
    /* Finally, some accounting */
    
  --- 237,247 ----
                     FILE **pipe_err);
    #define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL)
    
  ! /* magic numbers --- min free bytes to consider a free pool block useable,
  !  * and the min amount to allocate if we have to go to malloc() */
    
  ! #define BLOCK_MINFREE 4096
  ! #define BLOCK_MINALLOC 8192
    
    /* Finally, some accounting */
    
  
  
  
  1.139     +409 -318  apache/src/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_main.c,v
  retrieving revision 1.138
  retrieving revision 1.139
  diff -C3 -r1.138 -r1.139
  *** http_main.c	1997/04/21 20:29:07	1.138
  --- http_main.c	1997/04/24 23:35:20	1.139
  ***************
  *** 73,78 ****
  --- 73,82 ----
     *      Extensive rework for Apache.
     */
    
  + /* XXX: systems without HAVE_SHMGET or HAVE_MMAP do not reliably update
  +  * the scoreboard because a received signal might interrupt the scoreboard
  +  * calls.
  +  */
    
    #define CORE_PRIVATE
    
  ***************
  *** 157,163 ****
    
    server_rec *server_conf;
    JMP_BUF jmpbuffer;
  - JMP_BUF restart_buffer;
    int sd;
    static fd_set listenfds;
    static int listenmaxfd;
  --- 161,166 ----
  ***************
  *** 176,181 ****
  --- 179,200 ----
    
    int one_process = 0;
    
  + /* small utility macros to make things easier to read */
  + 
  + #ifdef NO_KILLPG
  + #define ap_killpg(x, y)		(kill (-(x), (y)))
  + #else
  + #define ap_killpg(x, y)		(killpg ((x), (y)))
  + #endif
  + 
  + #if defined(USE_LONGJMP)
  + #define ap_longjmp(x, y)	(longjmp ((x), (y)))
  + #define ap_setjmp(x)		(setjmp (x))
  + #else
  + #define ap_longjmp(x, y)	(siglongjmp ((x), (y)))
  + #define ap_setjmp(x)		(sigsetjmp ((x), 1))
  + #endif
  + 
    #if defined(USE_FCNTL_SERIALIZED_ACCEPT)
    static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
    static struct flock unlock_it = { F_UNLCK, 0, 0, 0 };
  ***************
  *** 359,369 ****
        }
        
        if (!current_conn) {
  ! #if defined(USE_LONGJMP)
  ! 	longjmp(jmpbuffer,1);
  ! #else
  ! 	siglongjmp(jmpbuffer,1);
  ! #endif
        }
        
        if (timeout_req != NULL) dirconf = timeout_req->per_dir_config;
  --- 378,384 ----
        }
        
        if (!current_conn) {
  ! 	ap_longjmp (jmpbuffer, 1);
        }
        
        if (timeout_req != NULL) dirconf = timeout_req->per_dir_config;
  ***************
  *** 401,411 ****
    	bclose(timeout_req->connection->client);
        
    	if (!standalone) exit(0);
  ! #if defined(USE_LONGJMP)
  ! 	longjmp(jmpbuffer,1);
  ! #else
  ! 	siglongjmp(jmpbuffer,1);
  ! #endif
        }
        else {   /* abort the connection */
            bsetflag(current_conn->client, B_EOUT, 1);
  --- 416,423 ----
    	bclose(timeout_req->connection->client);
        
    	if (!standalone) exit(0);
  ! 
  ! 	ap_longjmp (jmpbuffer, 1);
        }
        else {   /* abort the connection */
            bsetflag(current_conn->client, B_EOUT, 1);
  ***************
  *** 538,548 ****
        }
        
        if (!current_conn) {
  ! #if defined(USE_LONGJMP)
  ! 	longjmp(jmpbuffer,1);
  ! #else
  ! 	siglongjmp(jmpbuffer,1);
  ! #endif
        }
        bsetflag(current_conn->client, B_EOUT, 1);
        current_conn->aborted = 1;
  --- 550,556 ----
        }
        
        if (!current_conn) {
  ! 	ap_longjmp (jmpbuffer, 1);
        }
        bsetflag(current_conn->client, B_EOUT, 1);
        current_conn->aborted = 1;
  ***************
  *** 1172,1266 ****
    in wait_or_timeout(). But this routine is still useful for systems with no
    waitpid().
    */
  ! int reap_children()
  !     {
  !     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
  ! 	   && errno == ECHILD)
  ! 	    {
  ! 	    sync_scoreboard_image();
  ! 	    update_child_status(n,SERVER_DEAD,NULL);
  ! 	    ret=1;
  ! 	    }
  !     return ret;
        }
    #endif
    
    /* Finally, this routine is used by the caretaker process to wait for
     * a while...
     */
    
  ! #if 1
  ! 
  ! static int wait_or_timeout(int *status)
  !     {
    #ifndef NEED_WAITPID
        int ret;
    
  !     ret=waitpid(-1,status,WNOHANG);
  !     if(ret <= 0)
  ! 	{
  ! 	sleep(1);
    	return -1;
  ! 	}
        return ret;
    #else
  !     if(!reap_children())
    	sleep(1);
        return -1;
    #endif
  !     }
    
  - #else
    
  ! static JMP_BUF wait_timeout_buf;
    
  ! static void longjmp_out_of_alarm (int sig) {
  ! #if defined(USE_LONGJMP)
  !     longjmp (wait_timeout_buf, 1);
  ! #else
  !     siglongjmp (wait_timeout_buf, 1);
  ! #endif
    }
    
  ! int wait_or_timeout (int *status)
    {
  !     int wait_or_timeout_retval = -1;
  ! #ifdef BROKEN_WAIT
  !     static int ntimes;
  ! #endif
    
  ! #if defined(USE_LONGJMP)
  !     if (setjmp(wait_timeout_buf) != 0) {
  ! #else 
  !     if (sigsetjmp(wait_timeout_buf, 1) != 0) {
  ! #endif
  ! 	errno = ETIMEDOUT;
  ! 	return wait_or_timeout_retval;
        }
  ! #ifdef BROKEN_WAIT
  !     if(++ntimes == 60)
  ! 	{
  ! 	reap_children();
  ! 	ntimes=0;
  ! 	}
  ! #endif
  !     signal (SIGALRM, longjmp_out_of_alarm);
  !     alarm(1);
  ! #if defined(NEXT)
  !     wait_or_timeout_retval = wait((union wait *)status);
    #else
  !     wait_or_timeout_retval = wait(status);
    #endif
  -     alarm(0);
  -     return wait_or_timeout_retval;
    }
    
  - #endif
    
    /*****************************************************************
     * Here follows a long bunch of generic server bookkeeping stuff...
  --- 1180,1344 ----
    in wait_or_timeout(). But this routine is still useful for systems with no
    waitpid().
    */
  ! int reap_children ()
  ! {
  !     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
  ! 		&& errno == ECHILD) {
  ! 	    sync_scoreboard_image ();
  ! 	    update_child_status (n, SERVER_DEAD, NULL);
  ! 	    ret = 1;
  ! 	}
        }
  +     return ret;
  + }
    #endif
    
    /* Finally, this routine is used by the caretaker process to wait for
     * a while...
     */
    
  ! static int wait_or_timeout ()
  ! {
    #ifndef NEED_WAITPID
        int ret;
    
  !     ret = waitpid (-1, NULL, WNOHANG);
  !     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
  ! }
    
    
  ! void sig_term() {
  !     log_error("httpd: caught SIGTERM, shutting down", server_conf);
  !     cleanup_scoreboard();
  !     ap_killpg (pgrp, SIGKILL);
  !     close(sd);
  !     exit(1);
  ! }
    
  ! void bus_error(void) {
  !     char emsg[256];
  ! 
  !     ap_snprintf
  ! 	(
  ! 	    emsg,
  ! 	    sizeof(emsg) - 1,
  ! 	    "httpd: caught SIGBUS, attempting to dump core in %s",
  ! 	    server_root
  ! 	);
  !     log_error(emsg, server_conf);
  !     chdir(server_root);
  !     abort();         
  !     exit(1);
  ! }
  ! 
  ! void seg_fault() {
  !     char emsg[256];
  ! 
  !     ap_snprintf
  ! 	(
  ! 	    emsg,
  ! 	    sizeof(emsg) - 1,
  ! 	    "httpd: caught SIGSEGV, attempting to dump core in %s",
  ! 	    server_root
  ! 	);
  !     log_error(emsg, server_conf);
  !     chdir(server_root);
  !     abort();
  !     exit(1);
    }
    
  ! void just_die()			/* SIGHUP to child process??? */
    {
  !     exit (0);
  ! }
    
  ! static int deferred_die;
  ! 
  ! static void deferred_die_handler ()
  ! {
  !     deferred_die = 1;
  ! }
  ! 
  ! /* volatile just in case */
  ! static volatile int restart_pending;
  ! static volatile int is_graceful;
  ! static volatile int generation;
  ! 
  ! static void restart (int sig)
  ! {
  !     is_graceful = (sig == SIGUSR1);
  !     restart_pending = 1;
  ! }
  ! 
  ! 
  ! void set_signals()
  ! {
  ! #ifndef NO_USE_SIGACTION
  !     struct sigaction sa;
  ! 
  !     sigemptyset(&sa.sa_mask);
  !     sa.sa_flags = 0;
  ! 
  !     if (!one_process) {
  ! 	sa.sa_handler = (void (*)())seg_fault;
  ! 	if (sigaction (SIGSEGV, &sa, NULL) < 0)
  ! 	    log_unixerr ("sigaction(SIGSEGV)", NULL, NULL, server_conf);
  ! 	sa.sa_handler = (void (*)())bus_error;
  ! 	if (sigaction (SIGBUS, &sa, NULL) < 0)
  ! 	    log_unixerr ("sigaction(SIGBUS)", NULL, NULL, server_conf);
        }
  !     sa.sa_handler = (void (*)())sig_term;
  !     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.  restart
  !      * cleans out the SIGALRM handler, but this totally avoids the race
  !      * condition between when the restart request is made and when the handler
  !      * is invoked.
  !      *
  !      * We also don't 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;
  !     if (sigaction (SIGHUP, &sa, NULL) < 0)
  ! 	log_unixerr ("sigaction(SIGHUP)", NULL, NULL, server_conf);
  !     if (sigaction (SIGUSR1, &sa, NULL) < 0)
  ! 	log_unixerr ("sigaction(SIGUSR1)", NULL, NULL, server_conf);
    #else
  !     if(!one_process) {
  ! 	signal (SIGSEGV, (void (*)())seg_fault);
  !     	signal (SIGBUS, (void (*)())bus_error);
  !     }
  ! 
  !     signal (SIGTERM, (void (*)())sig_term);
  !     signal (SIGHUP, (void (*)())restart);
  !     signal (SIGUSR1, (void (*)())restart);
    #endif
    }
    
    
    /*****************************************************************
     * Here follows a long bunch of generic server bookkeeping stuff...
  ***************
  *** 1310,1364 ****
    #endif
    }
    
  - void sig_term() {
  -     log_error("httpd: caught SIGTERM, shutting down", server_conf);
  -     cleanup_scoreboard();
  - #ifndef NO_KILLPG
  -     killpg(pgrp,SIGKILL);
  - #else
  -     kill(-pgrp,SIGKILL);
  - #endif
  -     close(sd);
  -     exit(1);
  - }
  - 
  - void bus_error(void) {
  -     char emsg[256];
  - 
  -     ap_snprintf
  - 	(
  - 	    emsg,
  - 	    sizeof(emsg) - 1,
  - 	    "httpd: caught SIGBUS, attempting to dump core in %s",
  - 	    server_root
  - 	);
  -     log_error(emsg, server_conf);
  -     chdir(server_root);
  -     abort();         
  -     exit(1);
  - }
  - 
  - void seg_fault() {
  -     char emsg[256];
  - 
  -     ap_snprintf
  - 	(
  - 	    emsg,
  - 	    sizeof(emsg) - 1,
  - 	    "httpd: caught SIGSEGV, attempting to dump core in %s",
  - 	    server_root
  - 	);
  -     log_error(emsg, server_conf);
  -     chdir(server_root);
  -     abort();
  -     exit(1);
  - }
  - 
  - void just_die()			/* SIGHUP to child process??? */
  - {
  -     exit (0);
  - }
  - 
    /* Reset group privileges, after rereading the config files
     * (our uid may have changed, and if so, we want the new perms).
     *
  --- 1388,1393 ----
  ***************
  *** 1429,1499 ****
        return (suexec_enabled);
    }
    
  - static int is_graceful;
  - static int generation;
  - 
  - void restart() {
  -     signal (SIGALRM, SIG_IGN);
  -     alarm (0);
  -     is_graceful=0;
  - #if defined(USE_LONGJMP)
  -     longjmp(restart_buffer,1);
  - #else
  -     siglongjmp(restart_buffer,1);
  - #endif
  - }
  - 
  - void graceful_restart()
  -     {
  -     scoreboard_image->global.exit_generation=generation;
  -     is_graceful=1;
  -     update_scoreboard_global();
  - #if defined(USE_LONGJMP)
  -     longjmp(restart_buffer,1);
  - #else
  -     siglongjmp(restart_buffer,1);
  - #endif
  -     }
  - 
  - void set_signals()
  - {
  - #ifndef NO_USE_SIGACTION
  -     struct sigaction sa;
  - 
  -     sigemptyset(&sa.sa_mask);
  -     sa.sa_flags = 0;
  - 
  -     if (!one_process) {
  - 	sa.sa_handler = (void (*)())seg_fault;
  - 	if (sigaction(SIGSEGV, &sa, NULL) < 0)
  - 	    log_unixerr("sigaction(SIGSEGV)", NULL, NULL, server_conf);
  - 	sa.sa_handler = (void (*)())bus_error;
  - 	if (sigaction(SIGBUS, &sa, NULL) < 0)
  - 	    log_unixerr("sigaction(SIGBUS)", NULL, NULL, server_conf);
  -     }
  -     /* USE WITH EXTREME CAUTION. Graceful restarts are known to break */
  -     /*  problems will be dealt with in a future release */
  -     sa.sa_handler=(void (*)())sig_term;
  -     if(sigaction(SIGTERM,&sa,NULL) < 0)
  - 	log_unixerr("sigaction(SIGTERM)", NULL, NULL, server_conf);
  -     sa.sa_handler=(void (*)())restart;
  -     if(sigaction(SIGHUP,&sa,NULL) < 0)
  - 	log_unixerr("sigaction(SIGHUP)", NULL, NULL, server_conf);
  -     sa.sa_handler=(void (*)())graceful_restart;
  -     if(sigaction(SIGUSR1,&sa,NULL) < 0)
  - 	log_unixerr("sigaction(SIGUSR1)", NULL, NULL, server_conf);
  - #else
  -     if(!one_process) {
  - 	signal(SIGSEGV,(void (*)())seg_fault);
  -     	signal(SIGBUS,(void (*)())bus_error);
  -     }
  - 
  -     signal(SIGTERM,(void (*)())sig_term);
  -     signal(SIGHUP,(void (*)())restart);
  -     signal(SIGUSR1,(void (*)())graceful_restart);
  - #endif
  - }
  - 
    /*****************************************************************
     * Connection structures and accounting...
     * Should these be global?  Only to this file, at least...
  --- 1458,1463 ----
  ***************
  *** 1727,1737 ****
         * Setup the jump buffers so that we can return here after
         * a signal or a timeout (yeah, I know, same thing).
         */
  ! #if defined(USE_LONGJMP)
  !     setjmp(jmpbuffer);
  ! #else
  !     sigsetjmp(jmpbuffer,1);
  ! #endif
    #ifndef __EMX__
        signal(SIGURG, timeout);
    #endif    
  --- 1691,1697 ----
         * Setup the jump buffers so that we can return here after
         * a signal or a timeout (yeah, I know, same thing).
         */
  !     ap_setjmp (jmpbuffer);
    #ifndef __EMX__
        signal(SIGURG, timeout);
    #endif    
  ***************
  *** 1741,1746 ****
  --- 1701,1712 ----
    	BUFF *conn_io;
    	request_rec *r;
          
  + 	/* Prepare to receive a SIGUSR1 due to graceful restart so that
  + 	 * we can exit cleanly.  Since we're between connections right
  + 	 * now it's the right time to exit, but we might be blocked in a
  + 	 * system call when the graceful restart request is made. */
  + 	signal (SIGUSR1, (void (*)())just_die);
  + 
            /*
             * (Re)initialize this child to a pre-connection state.
             */
  ***************
  *** 1804,1813 ****
                        continue;
                }
    
  !             do {
                    clen = sizeof(sa_client);
                    csd  = accept(sd, &sa_client, &clen);
  !             } while (csd < 0 && errno == EINTR);
    
                if (csd >= 0)
                    break;      /* We have a socket ready for reading */
  --- 1770,1789 ----
                        continue;
                }
    
  ! 	    /* if we accept() something we don't want to die, so we have to
  ! 	     * defer the exit
  ! 	     */
  ! 	    deferred_die = 0;
  ! 	    signal (SIGUSR1, (void (*)())deferred_die_handler);
  !             for (;;) {
                    clen = sizeof(sa_client);
                    csd  = accept(sd, &sa_client, &clen);
  ! 		if (csd >= 0 || errno != EINTR) break;
  ! 		if (deferred_die) {
  ! 		    /* we didn't get a socket, and we were told to die */
  ! 		    exit (0);
  ! 		}
  ! 	    }
    
                if (csd >= 0)
                    break;      /* We have a socket ready for reading */
  ***************
  *** 1822,1831 ****
  --- 1798,1819 ----
    #endif
                    log_unixerr("accept", "(client socket)", NULL, server_conf);
                }
  + 
  + 	    /* go around again, safe to die */
  + 	    signal (SIGUSR1, (void (*)())just_die);
  + 	    if (deferred_die) {
  + 		/* ok maybe not, see ya later */
  + 		exit (0);
  + 	    }
            }
    
            accept_mutex_off(); /* unlock after "accept" */
    
  + 	/* We've got a socket, let's at least process one request off the
  + 	 * socket before we accept a graceful restart request.
  + 	 */
  + 	signal (SIGUSR1, SIG_IGN);
  + 
    	note_cleanups_for_fd(ptrans,csd);
    
            /*
  ***************
  *** 1867,1872 ****
  --- 1855,1866 ----
    
            for (;;) {
                r = read_request(current_conn);
  + 
  + 	    /* ok we've read the request... it's a little too late
  + 	     * to do a graceful restart, so ignore them for now.
  + 	     */
  + 	    signal (SIGUSR1, SIG_IGN);
  + 
                (void)update_child_status(child_num, SERVER_BUSY_WRITE, r);
    
                if (r) process_request(r); /* else premature EOF --- ignore */
  ***************
  *** 1885,1890 ****
  --- 1879,1899 ----
                    bclose(conn_io);
                    exit(0);
                }
  + 
  + 	    /* In case we get a graceful restart while we're blocked
  + 	     * waiting for the request.
  + 	     *
  + 	     * XXX: This isn't perfect, we might actually read the
  + 	     * request and then just die without saying anything to
  + 	     * the client.  This can be fixed by using deferred_die
  + 	     * but you have to teach buff.c about it so that it can handle
  + 	     * the EINTR properly.
  + 	     *
  + 	     * In practice though browsers (have to) expect keepalive
  + 	     * connections to close before receiving a response because
  + 	     * of network latencies and server timeouts.
  + 	     */
  + 	    signal (SIGUSR1, (void (*)())just_die);
            }
    
            /*
  ***************
  *** 1921,1929 ****
  --- 1930,1946 ----
    	child_main (child_num);
        }
    
  +     Explain1 ("Starting new child in slot %d", child_num);
  +     (void)update_child_status (child_num, SERVER_STARTING, (request_rec *)NULL);
  + 
        if ((pid = fork()) == -1) {
    	log_unixerr("fork", NULL, "Unable to fork new process", server_conf);
    
  + 	/* fork didn't succeed. Fix the scoreboard or else
  + 	 * it will say SERVER_STARTING forever and ever
  + 	 */
  + 	(void)update_child_status (child_num, 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. */
  ***************
  *** 1933,1942 ****
  --- 1950,1974 ----
        } 
        
        if (!pid) {
  + 	/* Disable the restart signal handlers and enable the just_die stuff.
  + 	 * Note that since restart() just notes that a restart has been
  + 	 * requested there's no race condition here.
  + 	 */
    	signal (SIGHUP, (void (*)())just_die);
  + 	signal (SIGUSR1, (void (*)())just_die);
    	signal (SIGTERM, (void (*)())just_die);
    	child_main (child_num);
        }
  + 
  +     /* If the parent proceeds with a restart before the child has written
  +      * their pid into the scoreboard we'll end up "forgetting" about the
  +      * child.  So we write the child pid into the scoreboard now.  (This
  +      * is safe, because the child is going to be writing the same value
  +      * to the same word.)
  +      * XXX: this needs to be sync'd to disk in the non shared memory stuff
  +      */
  +     scoreboard_image->servers[child_num].pid = pid;
  + 
        return 0;
    }
    
  ***************
  *** 2076,2225 ****
     * Executive routines.
     */
    
  - static int num_children = 0;
  - 
    void standalone_main(int argc, char **argv)
    {
        struct sockaddr_in sa_server;
        int saved_sd;
    
        standalone = 1;
        sd = listenmaxfd = -1;
  -     
  -     if (!one_process) detach(); 
  -     
  - #if defined(USE_LONGJMP)
  -     setjmp(restart_buffer);
  - #else
  -     sigsetjmp(restart_buffer,1);
  - #endif
    
        ++generation;
    
  !     signal (SIGHUP, SIG_IGN);	/* Until we're done (re)reading config */
  !     
  !     if(!one_process && !is_graceful)
  !     {
  ! #ifndef NO_KILLPG
  !       if (killpg(pgrp,SIGHUP) < 0)    /* Kill 'em off */
  ! #else
  !       if (kill(-pgrp,SIGHUP) < 0)
  ! #endif
  !         log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
  !     }
  !     
  !     if(is_graceful)
  ! 	{
  ! 	/* USE WITH EXTREME CAUTION. Graceful restarts are known to break */
  ! 	/*  problems will be dealt with in a future release */
  ! 	log_error("SIGUSR1 received.  Doing graceful restart",server_conf);
  ! 	kill_cleanups_for_fd(pconf,sd);
  ! 	}
  !     else if (sd != -1 || listenmaxfd != -1) {
  ! 	reclaim_child_processes(); /* Not when just starting up */
  ! 	log_error ("SIGHUP received.  Attempting to restart", server_conf);
  !     }
  !     
  !     copy_listeners(pconf);
  !     saved_sd=sd;
  !     restart_time = time(NULL);
  !     clear_pool (pconf);
  !     ptrans = make_sub_pool (pconf);
  !     
  !     server_conf = read_config(pconf, ptrans, server_confname); 
  !     open_logs(server_conf, pconf);
  !     set_group_privs();
  !     accept_mutex_init(pconf);
  !     reinit_scoreboard(pconf);
  !     
  !     default_server_hostnames (server_conf);
  ! 
  !     if (listeners == NULL) {
  !         if(!is_graceful) {
  ! 	    memset((char *) &sa_server, 0, sizeof(sa_server));
  ! 	    sa_server.sin_family=AF_INET;
  ! 	    sa_server.sin_addr=bind_address;
  ! 	    sa_server.sin_port=htons(server_conf->port);
    
  ! 	    sd = make_sock(pconf, &sa_server);
    	}
    	else {
  ! 	    sd = saved_sd;
  ! 	    note_cleanups_for_fd(pconf, sd);
    	}
  -     }
  -     else {
  - 	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();
  !     log_pid(pconf, pid_fname);
    
  !     num_children = 0;
  !     
  !     if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
  ! 	daemons_max_free = daemons_min_free + 1;
    
  !     while (num_children < daemons_to_start && num_children < daemons_limit)
{
  ! 	make_child(server_conf, num_children++);
  !     }
    
  !     log_error ("Server configured -- resuming normal operations", server_conf);
  !     
  !     while (1) {
  ! 	int status, child_slot;
  ! 	int pid = wait_or_timeout(&status);
  ! 	
  ! 	if (pid >= 0) {
  ! 	    /* Child died... note that it's gone in the scoreboard. */
    	    sync_scoreboard_image();
  ! 	    child_slot = find_child_by_pid (pid);
  ! 	    Explain2("Reaping child %d slot %d",pid,child_slot);
  ! 	    if (child_slot >= 0)
  ! 		(void)update_child_status (child_slot, SERVER_DEAD,
  ! 		 (request_rec*)NULL);
  !         }
  ! 
  ! 	sync_scoreboard_image();
  ! 	if ((count_idle_servers() < daemons_min_free)
  ! 	 && (child_slot = find_free_child_num()) >= 0
  ! 	 && child_slot < daemons_limit) {
  ! 	    Explain1("Starting new child in slot %d",child_slot);
  ! 	    (void)update_child_status(child_slot,SERVER_STARTING,
  ! 	     (request_rec*)NULL);
  ! 	    if (make_child(server_conf, child_slot) < 0) {
  ! 		/* fork didn't succeed. Fix the scoreboard or else
  ! 		   it will say SERVER_STARTING forever and ever */
  ! 	        (void)update_child_status(child_slot,SERVER_DEAD,
  ! 	             (request_rec*)NULL);
    	    }
  ! 
    	}
    
  ! 	/*
  ! 	if(scoreboard_image->global.please_exit && !count_live_servers())
  ! #if defined(USE_LONGJMP)
  ! 	    longjmp(restart_buffer,1);
  ! #else
  ! 	    siglongjmp(restart_buffer,1);
  ! #endif
  ! 	*/
  !     }
    
    } /* standalone_main */
    
  --- 2108,2316 ----
     * Executive routines.
     */
    
    void standalone_main(int argc, char **argv)
    {
        struct sockaddr_in sa_server;
        int saved_sd;
  +     int remaining_children_to_start;
    
        standalone = 1;
        sd = listenmaxfd = -1;
    
  +     is_graceful = 0;
        ++generation;
    
  !     if (!one_process) detach (); 
    
  !     do {
  ! 	copy_listeners(pconf);
  ! 	saved_sd = sd;
  ! 	if (!is_graceful) {
  ! 	    restart_time = time(NULL);
  ! 	}
  ! 	clear_pool (pconf);
  ! 	ptrans = make_sub_pool (pconf);
  ! 
  ! 	server_conf = read_config (pconf, ptrans, server_confname); 
  ! 	open_logs (server_conf, pconf);
  ! 	set_group_privs ();
  ! 	accept_mutex_init (pconf);
  ! 	if (!is_graceful) {
  ! 	    reinit_scoreboard(pconf);
  ! 	}
  ! 
  ! 	default_server_hostnames (server_conf);
  ! 
  ! 	if (listeners == NULL) {
  ! 	    if (!is_graceful) {
  ! 		memset ((char *)&sa_server, 0, sizeof (sa_server));
  ! 		sa_server.sin_family = AF_INET;
  ! 		sa_server.sin_addr = bind_address;
  ! 		sa_server.sin_port = htons (server_conf->port);
  ! 		sd = make_sock (pconf, &sa_server);
  ! 	    }
  ! 	    else {
  ! 		sd = saved_sd;
  ! 		note_cleanups_for_fd(pconf, sd);
  ! 	    }
    	}
    	else {
  ! 	    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 ();
  ! 	log_pid (pconf, pid_fname);
  ! 
  ! 	if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
  ! 	    daemons_max_free = daemons_min_free + 1;
  ! 
  ! 	/* If we're doing a graceful_restart then we're going to see a lot
  ! 	 * of children exiting immediately when we get into the main loop
  ! 	 * below (because we just sent them SIGUSR1).  This happens pretty
  ! 	 * rapidly... and for each one that exits we'll start a new one until
  ! 	 * we reach at least daemons_min_free.  But we may be permitted to
  ! 	 * start more than that, so we'll just keep track of how many we're
  ! 	 * supposed to start up without the 1 second penalty between each fork.
  ! 	 */
  ! 	remaining_children_to_start = daemons_to_start;
  ! 	if( remaining_children_to_start > daemons_limit ) {
  ! 	    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",
  ! 	    server_conf);
  ! 	restart_pending = 0;
  ! 
  ! 	while (!restart_pending) {
  ! 	    int child_slot;
  ! 	    int pid = wait_or_timeout ();
  ! 
  ! 	    /* XXX: if it takes longer than 1 second for all our children
  ! 	     * to start up and get into IDLE state then we may spawn an
  ! 	     * extra child
  ! 	     */
  ! 	    if (pid >= 0) {
  ! 		/* Child died... note that it's gone in the scoreboard. */
  ! 		sync_scoreboard_image ();
  ! 		child_slot = find_child_by_pid (pid);
  ! 		Explain2 ("Reaping child %d slot %d", pid, child_slot);
  ! 		if (child_slot >= 0) {
  ! 		    (void)update_child_status (child_slot, SERVER_DEAD,
  ! 			(request_rec *)NULL);
  ! 		} else if (is_graceful) {
  ! 		    /* Great, we've probably just lost a slot in the
  ! 		     * scoreboard.  Somehow we don't know about this
  ! 		     * child.
  ! 		     */
  ! 		    log_printf (server_conf,
  ! 			"long lost child came home! (pid %d)", pid );
  ! 		}
  ! 	    } else if (remaining_children_to_start) {
  ! 		/* we hit a 1 second timeout in which none of the previous
  ! 	 	 * 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.
  ! 		 */
  ! 		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 */
    
  ! 	if (one_process) {
  ! 	    /* not worth thinking about */
  ! 	    exit (0);
  ! 	}
  ! 
  ! 	if (is_graceful) {
  ! 	    int i;
  ! 
  ! 	    /* USE WITH CAUTION:  Graceful restarts are not known to work
  ! 	    * in various configurations on the architectures we support. */
  ! 	    scoreboard_image->global.exit_generation = generation;
  ! 	    update_scoreboard_global ();
  ! 
  ! 	    log_error ("SIGUSR1 received.  Doing graceful restart",server_conf);
  ! 	    kill_cleanups_for_fd (pconf, sd);
  ! 	    /* kill off the idle ones */
  ! 	    if (ap_killpg(pgrp, SIGUSR1) < 0) {
  ! 		log_unixerr ("killpg SIGUSR1", NULL, NULL, server_conf);
  ! 	    }
  ! 	    /* This is mostly for debugging... so that we know what is still
  ! 	     * gracefully dealing with existing request.
  ! 	     * XXX: clean this up a bit?
  ! 	     */
    	    sync_scoreboard_image();
  ! 	    for (i = 0; i < daemons_limit; ++i ) {
  ! 		if (scoreboard_image->servers[i].status != SERVER_DEAD) {
  ! 		    scoreboard_image->servers[i].status = SERVER_GRACEFUL;
  ! 		}
    	    }
  ! #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
  ! 	    lseek (scoreboard_fd, 0L, 0);
  ! 	    force_write (scoreboard_fd, (char*)scoreboard_image,
  ! 			sizeof(*scoreboard_image));
  ! #endif
    	}
  + 	else {
  + 	    /* Kill 'em off */
  + 	    if (ap_killpg (pgrp, SIGHUP) < 0) {
  + 		log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
  + 	    }
  + 	    reclaim_child_processes(); /* Not when just starting up */
  + 	    log_error ("SIGHUP received.  Attempting to restart", server_conf);
  + 	}
  + 	++generation;
    
  !     } while (restart_pending);
    
    } /* standalone_main */
    
  ***************
  *** 2288,2294 ****
    #endif
    
        setup_prelinked_modules();
  !     
        suexec_enabled = init_suexec();
        server_conf = read_config (pconf, ptrans, server_confname);
        
  --- 2379,2385 ----
    #endif
    
        setup_prelinked_modules();
  ! 
        suexec_enabled = init_suexec();
        server_conf = read_config (pconf, ptrans, server_confname);
        
  
  
  
  1.116     +2 -0      apache/src/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/http_protocol.c,v
  retrieving revision 1.115
  retrieving revision 1.116
  diff -C3 -r1.115 -r1.116
  *** http_protocol.c	1997/04/21 20:29:08	1.115
  --- http_protocol.c	1997/04/24 23:35:20	1.116
  ***************
  *** 626,631 ****
  --- 626,633 ----
                return 0;
    	}
        }
  +     /* we've probably got something to do, ignore graceful restart requests */
  +     signal (SIGUSR1, SIG_IGN);
        bsetflag( conn->client, B_SAFEREAD, 0 );
        if (len == (HUGE_STRING_LEN - 1)) {
            log_printf(r->server, "request failed for %s, reason: header too long",
  
  
  
  1.9       +3 -2      apache/src/mod_browser.c
  
  Index: mod_browser.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_browser.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -C3 -r1.8 -r1.9
  *** mod_browser.c	1997/03/07 14:15:38	1.8
  --- mod_browser.c	1997/04/24 23:35:21	1.9
  ***************
  *** 117,125 ****
    
        new = push_array(sconf->browsers);
        new->name = name;
  !     new->preg = pcalloc(cmd->pool, sizeof(regex_t));
  !     if (regcomp(new->preg, name, REG_EXTENDED|REG_NOSUB|cflags))
    	return "Browser regex could not be compiled.";
        new->features = make_table(cmd->pool, 5);
    
        var = getword(cmd->pool, &feature, '=');
  --- 117,126 ----
    
        new = push_array(sconf->browsers);
        new->name = name;
  !     new->preg = pregcomp (cmd->pool, name, REG_EXTENDED|REG_NOSUB|cflags);
  !     if (new->preg == NULL) {
    	return "Browser regex could not be compiled.";
  +     }
        new->features = make_table(cmd->pool, 5);
    
        var = getword(cmd->pool, &feature, '=');
  
  
  
  1.30      +6 -9      apache/src/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_include.c,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -C3 -r1.29 -r1.30
  *** mod_include.c	1997/04/22 02:35:10	1.29
  --- mod_include.c	1997/04/24 23:35:21	1.30
  ***************
  *** 861,879 ****
    
    int re_check(request_rec *r, char *string, char *rexp) 
    {
  !     regex_t compiled;
  !     char err_string[MAX_STRING_LEN];
        int regex_error;
    
  !     regex_error = regcomp(&compiled, rexp, REG_EXTENDED|REG_NOSUB);
  !     if (regex_error) {
  !         regerror(regex_error, &compiled, err_string, (size_t)MAX_STRING_LEN);
  !         log_printf(r->server,
  !             "unable to compile pattern %s [%s]", rexp, err_string);
            return -1;
        }
  !     regex_error = regexec(&compiled, string, 0, (regmatch_t *)NULL, 0);
  !     regfree(&compiled);
        return(!regex_error);
    }
    
  --- 861,876 ----
    
    int re_check(request_rec *r, char *string, char *rexp) 
    {
  !     regex_t *compiled;
        int regex_error;
    
  !     compiled = pregcomp (r->pool, rexp, REG_EXTENDED|REG_NOSUB);
  !     if (compiled == NULL) {
  !         log_printf(r->server, "unable to compile pattern %s", rexp);
            return -1;
        }
  !     regex_error = regexec(compiled, string, 0, (regmatch_t *)NULL, 0);
  !     pregfree (r->pool, compiled);
        return(!regex_error);
    }
    
  
  
  
  1.28      +1 -1      apache/src/mod_rewrite.c
  
  Index: mod_rewrite.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_rewrite.c,v
  retrieving revision 1.27
  retrieving revision 1.28
  diff -C3 -r1.27 -r1.28
  *** mod_rewrite.c	1997/04/17 02:52:51	1.27
  --- mod_rewrite.c	1997/04/24 23:35:22	1.28
  ***************
  *** 2759,2765 ****
        cache *c;
    
        c = (cache *)palloc(p, sizeof(cache));
  !     c->pool = make_sub_pool(NULL);
        c->lists = make_array(c->pool, 2, sizeof(cachelist));
        return c;
    }
  --- 2759,2765 ----
        cache *c;
    
        c = (cache *)palloc(p, sizeof(cache));
  !     c->pool = make_sub_pool(p);
        c->lists = make_array(c->pool, 2, sizeof(cachelist));
        return c;
    }
  
  
  
  1.46      +16 -1     apache/src/mod_status.c
  
  Index: mod_status.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_status.c,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -C3 -r1.45 -r1.46
  *** mod_status.c	1997/04/06 07:43:42	1.45
  --- mod_status.c	1997/04/24 23:35:23	1.46
  ***************
  *** 227,232 ****
  --- 227,233 ----
        status[SERVER_BUSY_KEEPALIVE]='K';
        status[SERVER_BUSY_LOG]='L';
        status[SERVER_BUSY_DNS]='D';
  +     status[SERVER_GRACEFUL]='G';
    
        if (r->method_number != M_GET) return NOT_IMPLEMENTED;
        r->content_type = "text/html";
  ***************
  *** 279,285 ****
    	    ready++;
            else if (res == SERVER_BUSY_READ || res==SERVER_BUSY_WRITE || 
    		 res == SERVER_STARTING || res==SERVER_BUSY_KEEPALIVE ||
  ! 		 res == SERVER_BUSY_LOG || res==SERVER_BUSY_DNS)
    	    busy++;
    #if defined(STATUS)
            lres = score_record.access_count;
  --- 280,287 ----
    	    ready++;
            else if (res == SERVER_BUSY_READ || res==SERVER_BUSY_WRITE || 
    		 res == SERVER_STARTING || res==SERVER_BUSY_KEEPALIVE ||
  ! 		 res == SERVER_BUSY_LOG || res==SERVER_BUSY_DNS ||
  ! 		 res == SERVER_GRACEFUL)
    	    busy++;
    #if defined(STATUS)
            lres = score_record.access_count;
  ***************
  *** 407,412 ****
  --- 409,415 ----
    	rputs("\"<B><code>K</code></B>\" Keepalive (read), \n",r);
    	rputs("\"<B><code>D</code></B>\" DNS Lookup,<BR>\n",r);
    	rputs("\"<B><code>L</code></B>\" Logging, \n",r);
  + 	rputs("\"<B><code>G</code></B>\" Gracefully finishing, \n",r);
    	rputs("\"<B><code>.</code></B>\" Open slot with no current process<P>\n",r);
        }
    
  ***************
  *** 468,473 ****
  --- 471,482 ----
    		        case SERVER_DEAD:
    		            rputs("Dead",r);
    		            break;
  + 			case SERVER_GRACEFUL:
  + 			    rputs("Graceful",r);
  + 			    break;
  + 			default:
  + 			    rputs("?STATE?",r);
  + 			    break;
    		    }
    #ifdef __EMX__
                        /* Allow for OS/2 not having CPU stats */
  ***************
  *** 521,526 ****
  --- 530,541 ----
    		        case SERVER_DEAD:
    		            rputs("<td>.",r);
    		            break;
  + 			case SERVER_GRACEFUL:
  + 			    rputs("<td>G",r);
  + 			    break;
  + 			default:
  + 			    rputs("<td>?",r);
  + 			    break;
    		    }
    #ifdef __EMX__
    	            /* Allow for OS/2 not having CPU stats */
  
  
  
  1.21      +1 -0      apache/src/scoreboard.h
  
  Index: scoreboard.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/scoreboard.h,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -C3 -r1.20 -r1.21
  *** scoreboard.h	1997/01/01 18:10:44	1.20
  --- scoreboard.h	1997/04/24 23:35:23	1.21
  ***************
  *** 71,76 ****
  --- 71,77 ----
    #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 */
    
    typedef struct {
        pid_t pid;
  
  
  

Mime
View raw message