You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Dean Gaudet <dg...@arctic.org> on 1997/11/03 05:51:31 UTC

[PATCH] PR#1211: race condition in unblock_alarms

This fixes a very small race condition in unblock_alarms that's present
even after the race condition that used to cause the "Ouch!  Freeing free
block". 

I also create a function clean_child_exit() because I'm tired of the same
three lines of code being duplicated all over http_main.c.

Dean

Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.242
diff -u -r1.242 http_main.c
--- http_main.c	1997/11/01 22:15:59	1.242
+++ http_main.c	1997/11/03 04:47:13
@@ -678,6 +678,14 @@
 }
 #endif
 
+/* a clean exit from a child with proper cleanup */
+static void __attribute__((noreturn)) clean_child_exit(int code)
+{
+    child_exit_modules(pconf, server_conf);
+    destroy_pool(pconf);
+    exit(code);
+}
+
 void timeout(int sig)
 {				/* Also called on SIGPIPE */
     char errstr[MAX_STRING_LEN];
@@ -688,6 +696,9 @@
 	alarm_pending = 1;
 	return;
     }
+    if (exit_after_unblock) {
+	clean_child_exit(0);
+    }
 
     if (!current_conn) {
 	ap_longjmp(jmpbuffer, 1);
@@ -760,10 +771,16 @@
     --alarms_blocked;
     if (alarms_blocked == 0) {
 	if (exit_after_unblock) {
+	    /* We have a couple race conditions to deal with here, we can't
+	     * allow a timeout that comes in this small interval to allow
+	     * the child to jump back to the main loop.  Instead we block
+	     * alarms again, and then note that exit_after_unblock is
+	     * being dealt with.  We choose this way to solve this so that
+	     * the common path through unblock_alarms() is really short.
+	     */
+	    ++alarms_blocked;
 	    exit_after_unblock = 0;
-	    child_exit_modules(pconf, server_conf);
-	    destroy_pool(pconf);
-	    exit(0);
+	    clean_child_exit(0);
 	}
 	if (alarm_pending) {
 	    alarm_pending = 0;
@@ -1964,9 +1981,7 @@
 	exit_after_unblock = 1;
     }
     else {
-	child_exit_modules(pconf, server_conf);
-	destroy_pool(pconf);
-	exit(0);
+	clean_child_exit(0);
     }
 }
 
@@ -2668,16 +2683,12 @@
 
 	sync_scoreboard_image();
 	if (scoreboard_image->global.exit_generation >= generation) {
-	    child_exit_modules(pconf, server_conf);
-	    destroy_pool(pconf);
-	    exit(0);
+	    clean_child_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);
+	    clean_child_exit(0);
 	}
 
 	(void) update_child_status(my_child_num, SERVER_READY, (request_rec *) NULL);
@@ -2700,9 +2711,7 @@
 		    if (errno == EFAULT) {
 			aplog_error(APLOG_MARK, APLOG_ERR, server_conf,
 				    "select: (listen) fatal, child exiting");
-			child_exit_modules(pconf, server_conf);
-			destroy_pool(pconf);
-			exit(1);
+			clean_child_exit(1);
 		    }
 #endif
 		    aplog_error(APLOG_MARK, APLOG_ERR, server_conf, "select: (listen)");
@@ -2733,9 +2742,7 @@
 		    break;
 		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);
+		    clean_child_exit(0);
 		}
 	    }
 
@@ -2758,18 +2765,14 @@
 	    usr1_just_die = 1;
 	    if (deferred_die) {
 		/* ok maybe not, see ya later */
-		child_exit_modules(pconf, server_conf);
-		destroy_pool(pconf);
-		exit(0);
+		clean_child_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) {
-		child_exit_modules(pconf, server_conf);
-		destroy_pool(pconf);
-		exit(0);
+		clean_child_exit(0);
 	    }
 	}
 
@@ -2855,9 +2858,7 @@
 	    sync_scoreboard_image();
 	    if (scoreboard_image->global.exit_generation >= generation) {
 		bclose(conn_io);
-		child_exit_modules(pconf, server_conf);
-		destroy_pool(pconf);
-		exit(0);
+		clean_child_exit(0);
 	    }
 
 	    /* In case we get a graceful restart while we're blocked




Re: [PATCH] PR#1211: race condition in unblock_alarms

Posted by Martin Kraemer <Ma...@mch.sni.de>.
On Sun, Nov 02, 1997 at 08:51:31PM -0800, Dean Gaudet wrote:
> This fixes a very small race condition in unblock_alarms

+1

    Martin
-- 
| S I E M E N S |  <Ma...@mch.sni.de>  |      Siemens Nixdorf
| ------------- |   Voice: +49-89-636-46021     |  Informationssysteme AG
| N I X D O R F |   FAX:   +49-89-636-44994     |   81730 Munich, Germany
~~~~~~~~~~~~~~~~My opinions only, of course; pgp key available on request

Re: [PATCH] PR#1211: race condition in unblock_alarms

Posted by Marc Slemko <ma...@worldgate.com>.
On Sun, 2 Nov 1997, Dean Gaudet wrote:

> This fixes a very small race condition in unblock_alarms that's present
> even after the race condition that used to cause the "Ouch!  Freeing free
> block". 
> 
> I also create a function clean_child_exit() because I'm tired of the same
> three lines of code being duplicated all over http_main.c.

+1