You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Rodent of Unusual Size <co...@decus.org> on 1997/08/19 19:26:51 UTC

SIG{TERM,KILL} and child_exit

>From the fingers of Dean Gaudet flowed the following:
>
>                                   The main one I have is buffered (but
>still atomic) logging.  It would be an option of course.  It actually uses
>child_exit, whee! 

    Erm, how is it doing that?  Alexei already identified that
    child_exit shouldn't be working cleanly on normal server shutdown:

void sig_term(int sig) {
    log_error("httpd: caught SIGTERM, shutting down", server_conf);
    cleanup_scoreboard();
    accept_mutex_cleanup();
#ifdef SIGKILL
    ap_killpg (pgrp, SIGKILL);
#endif /* SIGKILL */
    close(sd);
    exit(1);
}

    It looks like child_exit will actually only get called on
    child_oldage.  I've been meaning to look at a solution for this, but
    I'm pretty far behind.  I agree with Alexei that this needs to be
    addressed before 1.3b1.

    #ken    :-)}

Re: [PATCH] Re: SIG{TERM,KILL} and child_exit

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 19 Aug 1997, Dean Gaudet wrote:

> I'd move destroy_pool into child_exit_modules, just for consistency.

Ok how about creating a child_exit() routine.  I really don't want all
that duplicated code all over the place ...

Dean


Re: [PATCH] Re: SIG{TERM,KILL} and child_exit

Posted by Alexei Kosut <ak...@organic.com>.
On Tue, 19 Aug 1997, Dean Gaudet wrote:

> This looks like a good start.
> 
> I'd move destroy_pool into child_exit_modules, just for consistency.

No; child_exit_modules() shouldn't, IMHO, do anything more than call the
child_exit API handlers. None of the other http_config functions do
anything but that. Adding other functionality, like destroying pools or
exiting, is asking for trouble, because you might want to use
call_exit_modules() for some other purpose (I have no idea what). That's
why I moved (in my patch) exit() out of child_exit_modules.

> accept_mutex_cleanup() and cleanup_scoreboard() absolutely must be called.
> You seem to have lost them below.

Erg. You're right. I forgot about that.

-- Alexei Kosut <ak...@organic.com>


Re: [PATCH] Re: SIG{TERM,KILL} and child_exit

Posted by Dean Gaudet <dg...@arctic.org>.
This looks like a good start.

I'd move destroy_pool into child_exit_modules, just for consistency.

accept_mutex_cleanup() and cleanup_scoreboard() absolutely must be called.
You seem to have lost them below.

If you receive a SIGTERM during a reclaim_child_processes it will abort
the select() ... probably not a big problem though.  Just messes up timing
a wee bit. 

Dean

On Tue, 19 Aug 1997, Alexei Kosut wrote:

> On Tue, 19 Aug 1997, Rodent of Unusual Size wrote:
> 
> >     It looks like child_exit will actually only get called on
> >     child_oldage.  I've been meaning to look at a solution for this, but
> 
> And SIGHUP.
> 
> >     I'm pretty far behind.  I agree with Alexei that this needs to be
> >     addressed before 1.3b1.
> 
> Yes. Here's a patch (not fully tested) that I think fixes the SIGTERM
> issues, as well as fixing a part of the child_exit() stuff (it wasn't
> calling destroy_pool, which it should). There's still some win32 stuff
> that needs to be done (I don't think it calls child_exit at all the
> correct times, and I'm relatively sure it doesn't call child_init), but
> this should work for Unix:
> 
> Index: core/http_config.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/core/http_config.c,v
> retrieving revision 1.73
> diff -u -r1.73 http_config.c
> --- http_config.c	1997/08/18 07:17:24	1.73
> +++ http_config.c	1997/08/19 19:19:28
> @@ -1270,7 +1270,6 @@
>          if (m->child_exit)
>  	    (*m->child_exit) (s, p);
>  
> -    exit(0);
>  }
>  
>  /********************************************************************
> Index: core/http_main.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/core/http_main.c,v
> retrieving revision 1.204
> diff -u -r1.204 http_main.c
> --- http_main.c	1997/08/18 07:17:25	1.204
> +++ http_main.c	1997/08/19 19:19:33
> @@ -746,6 +746,8 @@
>      if (alarms_blocked == 0) {
>  	if (exit_after_unblock) {
>  	    child_exit_modules(pconf, server_conf);
> +	    destroy_pool(pconf);
> +	    exit(0);
>  	}
>  	if (alarm_pending) {
>  	    alarm_pending = 0;
> @@ -1591,7 +1593,7 @@
>      return -1;
>  }
>  
> -static void reclaim_child_processes (void)
> +static void reclaim_child_processes (int start_tries)
>  {
>  #ifndef MULTITHREAD
>      int i, status;
> @@ -1602,7 +1604,7 @@
>  
>  	if (pid != my_pid && pid != 0) { 
>  	    int waitret = 0,
> -		tries = 1;
> +		tries = start_tries;
>  
>  	    while (waitret == 0 && tries <= 4) {
>  		long int waittime = 4096; /* in usecs */
> @@ -1745,17 +1747,6 @@
>  }
>  
>  
> -void sig_term(int sig) {
> -    log_error("httpd: caught SIGTERM, shutting down", server_conf);
> -    cleanup_scoreboard();
> -    accept_mutex_cleanup();
> -#ifdef SIGKILL
> -    ap_killpg (pgrp, SIGKILL);
> -#endif /* SIGKILL */
> -    close(sd);
> -    exit(1);
> -}
> -
>  void bus_error(int sig) {
>      char emsg[256];
>  
> @@ -1790,6 +1781,8 @@
>  	exit_after_unblock = 1;
>      } else {
>  	child_exit_modules(pconf, server_conf);
> +	destroy_pool(pconf);
> +	exit(0);
>      }
>  }
>  
> @@ -1805,10 +1798,15 @@
>  }
>  
>  /* volatile just in case */
> +static int volatile shutdown_pending;
>  static int volatile restart_pending;
>  static int volatile is_graceful;
>  static int volatile generation;
>  
> +static void sig_term(int sig) {
> +    shutdown_pending = 1;
> +}
> +
>  static void restart (int sig)
>  {
>  #ifdef WIN32
> @@ -2642,13 +2640,18 @@
>  	clear_pool (ptrans);
>  	
>  	sync_scoreboard_image();
> -	if (scoreboard_image->global.exit_generation >= generation)
> +	if (scoreboard_image->global.exit_generation >= generation) {
>  	    child_exit_modules(pconf, server_conf);
> +	    destroy_pool(pconf);
> +	    exit(0);
> +	}
>  	
>  	if ((max_requests_per_child > 0
>  	        && ++requests_this_child >= max_requests_per_child))
>  	{
>  	    child_exit_modules(pconf, server_conf);
> +	    destroy_pool(pconf);
> +	    exit(0);
>  	}
>  
>  	(void)update_child_status(my_child_num, SERVER_READY, (request_rec*)NULL);
> @@ -2692,6 +2695,8 @@
>  		if (deferred_die) {
>  		    /* we didn't get a socket, and we were told to die */
>  		    child_exit_modules(pconf, server_conf);
> +		    destroy_pool(pconf);
> +		    exit(0);
>  		}
>  	    }
>  
> @@ -2714,13 +2719,18 @@
>  	    if (deferred_die) {
>  		/* ok maybe not, see ya later */
>  		child_exit_modules(pconf, server_conf);
> +		destroy_pool(pconf);
> +		exit(0);
>  	    }
>  	    /* or maybe we missed a signal, you never know on systems
>  	     * without reliable signals
>  	     */
>  	    sync_scoreboard_image();
> -	    if (scoreboard_image->global.exit_generation >= generation)
> +	    if (scoreboard_image->global.exit_generation >= generation) {
>  		child_exit_modules(pconf, server_conf);
> +		destroy_pool(pconf);
> +		exit(0);
> +	    }
>          }
>  
>          SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
> @@ -2805,6 +2815,8 @@
>              if (scoreboard_image->global.exit_generation >= generation) {
>                  bclose(conn_io);
>  		child_exit_modules(pconf, server_conf);
> +		destroy_pool(pconf);
> +		exit(0);
>              }
>  
>  	    /* In case we get a graceful restart while we're blocked
> @@ -3126,9 +3138,9 @@
>  
>  	log_error ("Server configured -- resuming normal operations",
>  	    server_conf);
> -	restart_pending = 0;
> +	restart_pending = shutdown_pending = 0;
>  
> -	while (!restart_pending) {
> +	while (!restart_pending && !shutdown_pending) {
>  	    int child_slot;
>  	    int pid = wait_or_timeout ();
>  
> @@ -3179,6 +3191,21 @@
>  	    perform_idle_server_maintenance();
>  	}
>  
> +	if (shutdown_pending) {
> +	    /* Time to gracefully shut down:
> +	     * Kill child processes, tell them to call child_exit, etc...
> +	     */
> +	    if (ap_killpg (pgrp, SIGTERM) < 0) {
> +		log_unixerr ("killpg SIGTERM", NULL, NULL, server_conf);
> +	    }
> +	    reclaim_child_processes(2); /* Start with SIGTERM */
> +	    log_error("httpd: caught SIGTERM, shutting down", server_conf);
> +
> +	    /* Clear the pool - including any registered cleanups */
> +	    destroy_pool(pconf);
> +	    exit(0);
> +	}
> +
>  	/* we've been told to restart */
>  	signal (SIGHUP, SIG_IGN);
>  	signal (SIGUSR1, SIG_IGN);
> @@ -3222,7 +3249,7 @@
>  	    if (ap_killpg (pgrp, SIGHUP) < 0) {
>  		log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
>  	    }
> -	    reclaim_child_processes(); /* Not when just starting up */
> +	    reclaim_child_processes(1); /* Not when just starting up */
>  	    log_error ("SIGHUP received.  Attempting to restart", server_conf);
>  	}
>  	++generation;
> 
> 
> -- Alexei Kosut <ak...@organic.com>
> 
> 


[PATCH] Re: SIG{TERM,KILL} and child_exit

Posted by Alexei Kosut <ak...@organic.com>.
On Tue, 19 Aug 1997, Rodent of Unusual Size wrote:

>     It looks like child_exit will actually only get called on
>     child_oldage.  I've been meaning to look at a solution for this, but

And SIGHUP.

>     I'm pretty far behind.  I agree with Alexei that this needs to be
>     addressed before 1.3b1.

Yes. Here's a patch (not fully tested) that I think fixes the SIGTERM
issues, as well as fixing a part of the child_exit() stuff (it wasn't
calling destroy_pool, which it should). There's still some win32 stuff
that needs to be done (I don't think it calls child_exit at all the
correct times, and I'm relatively sure it doesn't call child_init), but
this should work for Unix:

Index: core/http_config.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_config.c,v
retrieving revision 1.73
diff -u -r1.73 http_config.c
--- http_config.c	1997/08/18 07:17:24	1.73
+++ http_config.c	1997/08/19 19:19:28
@@ -1270,7 +1270,6 @@
         if (m->child_exit)
 	    (*m->child_exit) (s, p);
 
-    exit(0);
 }
 
 /********************************************************************
Index: core/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/core/http_main.c,v
retrieving revision 1.204
diff -u -r1.204 http_main.c
--- http_main.c	1997/08/18 07:17:25	1.204
+++ http_main.c	1997/08/19 19:19:33
@@ -746,6 +746,8 @@
     if (alarms_blocked == 0) {
 	if (exit_after_unblock) {
 	    child_exit_modules(pconf, server_conf);
+	    destroy_pool(pconf);
+	    exit(0);
 	}
 	if (alarm_pending) {
 	    alarm_pending = 0;
@@ -1591,7 +1593,7 @@
     return -1;
 }
 
-static void reclaim_child_processes (void)
+static void reclaim_child_processes (int start_tries)
 {
 #ifndef MULTITHREAD
     int i, status;
@@ -1602,7 +1604,7 @@
 
 	if (pid != my_pid && pid != 0) { 
 	    int waitret = 0,
-		tries = 1;
+		tries = start_tries;
 
 	    while (waitret == 0 && tries <= 4) {
 		long int waittime = 4096; /* in usecs */
@@ -1745,17 +1747,6 @@
 }
 
 
-void sig_term(int sig) {
-    log_error("httpd: caught SIGTERM, shutting down", server_conf);
-    cleanup_scoreboard();
-    accept_mutex_cleanup();
-#ifdef SIGKILL
-    ap_killpg (pgrp, SIGKILL);
-#endif /* SIGKILL */
-    close(sd);
-    exit(1);
-}
-
 void bus_error(int sig) {
     char emsg[256];
 
@@ -1790,6 +1781,8 @@
 	exit_after_unblock = 1;
     } else {
 	child_exit_modules(pconf, server_conf);
+	destroy_pool(pconf);
+	exit(0);
     }
 }
 
@@ -1805,10 +1798,15 @@
 }
 
 /* volatile just in case */
+static int volatile shutdown_pending;
 static int volatile restart_pending;
 static int volatile is_graceful;
 static int volatile generation;
 
+static void sig_term(int sig) {
+    shutdown_pending = 1;
+}
+
 static void restart (int sig)
 {
 #ifdef WIN32
@@ -2642,13 +2640,18 @@
 	clear_pool (ptrans);
 	
 	sync_scoreboard_image();
-	if (scoreboard_image->global.exit_generation >= generation)
+	if (scoreboard_image->global.exit_generation >= generation) {
 	    child_exit_modules(pconf, server_conf);
+	    destroy_pool(pconf);
+	    exit(0);
+	}
 	
 	if ((max_requests_per_child > 0
 	        && ++requests_this_child >= max_requests_per_child))
 	{
 	    child_exit_modules(pconf, server_conf);
+	    destroy_pool(pconf);
+	    exit(0);
 	}
 
 	(void)update_child_status(my_child_num, SERVER_READY, (request_rec*)NULL);
@@ -2692,6 +2695,8 @@
 		if (deferred_die) {
 		    /* we didn't get a socket, and we were told to die */
 		    child_exit_modules(pconf, server_conf);
+		    destroy_pool(pconf);
+		    exit(0);
 		}
 	    }
 
@@ -2714,13 +2719,18 @@
 	    if (deferred_die) {
 		/* ok maybe not, see ya later */
 		child_exit_modules(pconf, server_conf);
+		destroy_pool(pconf);
+		exit(0);
 	    }
 	    /* or maybe we missed a signal, you never know on systems
 	     * without reliable signals
 	     */
 	    sync_scoreboard_image();
-	    if (scoreboard_image->global.exit_generation >= generation)
+	    if (scoreboard_image->global.exit_generation >= generation) {
 		child_exit_modules(pconf, server_conf);
+		destroy_pool(pconf);
+		exit(0);
+	    }
         }
 
         SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
@@ -2805,6 +2815,8 @@
             if (scoreboard_image->global.exit_generation >= generation) {
                 bclose(conn_io);
 		child_exit_modules(pconf, server_conf);
+		destroy_pool(pconf);
+		exit(0);
             }
 
 	    /* In case we get a graceful restart while we're blocked
@@ -3126,9 +3138,9 @@
 
 	log_error ("Server configured -- resuming normal operations",
 	    server_conf);
-	restart_pending = 0;
+	restart_pending = shutdown_pending = 0;
 
-	while (!restart_pending) {
+	while (!restart_pending && !shutdown_pending) {
 	    int child_slot;
 	    int pid = wait_or_timeout ();
 
@@ -3179,6 +3191,21 @@
 	    perform_idle_server_maintenance();
 	}
 
+	if (shutdown_pending) {
+	    /* Time to gracefully shut down:
+	     * Kill child processes, tell them to call child_exit, etc...
+	     */
+	    if (ap_killpg (pgrp, SIGTERM) < 0) {
+		log_unixerr ("killpg SIGTERM", NULL, NULL, server_conf);
+	    }
+	    reclaim_child_processes(2); /* Start with SIGTERM */
+	    log_error("httpd: caught SIGTERM, shutting down", server_conf);
+
+	    /* Clear the pool - including any registered cleanups */
+	    destroy_pool(pconf);
+	    exit(0);
+	}
+
 	/* we've been told to restart */
 	signal (SIGHUP, SIG_IGN);
 	signal (SIGUSR1, SIG_IGN);
@@ -3222,7 +3249,7 @@
 	    if (ap_killpg (pgrp, SIGHUP) < 0) {
 		log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
 	    }
-	    reclaim_child_processes(); /* Not when just starting up */
+	    reclaim_child_processes(1); /* Not when just starting up */
 	    log_error ("SIGHUP received.  Attempting to restart", server_conf);
 	}
 	++generation;


-- Alexei Kosut <ak...@organic.com>


Re: SIG{TERM,KILL} and child_exit

Posted by Dean Gaudet <dg...@arctic.org>.
Oh yeah, so there's that bug to be fixed ;)  sig_term could do a
reclaim_child_processes in which case it needs to have Nathan's bug fixed
... uh I forget the PR, but we just fixed it for SIGHUP and SIGUSR1.  An
issue is that during a USR1/HUP restart I don't really care if another
restart signal is received, we'll just continue restarting.  But if a
SIGTERM is received we want to stop restarting and do an exit and cleanup. 
It's not a quick fix, but needs to happen for 1.3. 

My new log buffer code keeps a 4k buffer.  If a log entry would overflow
the buffer it flushes first, then starts off the fresh buffer with the new
entry.  On child_exit it flushes the log.  This maintains the atomicity
... but I really need to use whatever POSIX #define it is that defines the
max atomic write. 

Dean

On Tue, 19 Aug 1997, Rodent of Unusual Size wrote:

> >From the fingers of Dean Gaudet flowed the following:
> >
> >                                   The main one I have is buffered (but
> >still atomic) logging.  It would be an option of course.  It actually uses
> >child_exit, whee! 
> 
>     Erm, how is it doing that?  Alexei already identified that
>     child_exit shouldn't be working cleanly on normal server shutdown:
> 
> void sig_term(int sig) {
>     log_error("httpd: caught SIGTERM, shutting down", server_conf);
>     cleanup_scoreboard();
>     accept_mutex_cleanup();
> #ifdef SIGKILL
>     ap_killpg (pgrp, SIGKILL);
> #endif /* SIGKILL */
>     close(sd);
>     exit(1);
> }
> 
>     It looks like child_exit will actually only get called on
>     child_oldage.  I've been meaning to look at a solution for this, but
>     I'm pretty far behind.  I agree with Alexei that this needs to be
>     addressed before 1.3b1.
> 
>     #ken    :-)}
>