You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Jeff Trawick <tr...@bellsouth.net> on 2001/06/01 20:52:26 UTC

[PATCH] get prefork MPM to wake up from accept mutex or select after signal

If it checks the I_AM_TO_SHUTDOWN() macro when the mutex or select()
returns EINTR then we are able to shut down idle server processes
which are in select() or waiting to acquire the accept mutex.

Certainly some polish is needed in prefork.c and some code for other
platforms is needed in APR, but that is a minor detail.  The important
issue is whether or not to continue using signals for killing idle
servers and if so how to exit once we are signalled.

Some mildly disturbing issues are raised by this experiment:

1) apr_set_lock_interruptible() is Unix-specific AFAIK; either
   apr_set_lock_interruptible returns APR_ENOTIMPL everywhere else or
   we introduce APR_HAS_INTERRUPTIBLE_LOCKS or similar

2) apr_set_lock_interruptible() can't work when we are using pthread
   cross process locks as they don't do the EINTR thing

Index: server/mpm/prefork/prefork.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v
retrieving revision 1.175
diff -u -r1.175 prefork.c
--- server/mpm/prefork/prefork.c	2001/05/15 02:38:15	1.175
+++ server/mpm/prefork/prefork.c	2001/06/01 17:49:54
@@ -272,14 +272,10 @@
 	ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't create accept mutex");
         exit(APEXIT_INIT);
     }
-}
-
-static void accept_mutex_on(void)
-{
-    apr_status_t rv = apr_lock_acquire(accept_lock);
-    if (rv != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't grab the accept mutex");
-        exit(APEXIT_CHILDFATAL);
+    rv = apr_lock_set_interruptible(accept_lock);
+    if (rv) {
+	ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't make accept mutex interruptible");
+        exit(APEXIT_INIT);
     }
 }
 
@@ -581,6 +577,8 @@
     apr_signal(SIGHUP, please_die_gracefully);
 
     ap_sync_scoreboard_image();
+
+ restart:
     while (!I_AM_TO_SHUTDOWN()) {
 
 	/* Prepare to receive a SIGWINCH due to graceful restart so that
@@ -609,7 +607,22 @@
 	 */
 
 	/* Lock around "accept", if necessary */
-	SAFE_ACCEPT(accept_mutex_on());
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+        if (ap_listeners->next) {
+#endif
+            stat = apr_lock_acquire(accept_lock);
+            switch(stat) {
+            case APR_SUCCESS:
+                break;
+            case APR_EINTR:
+                continue;
+            default:
+                ap_log_error(APLOG_MARK, APLOG_EMERG, stat, NULL, "couldn't grab the accept mutex");
+                exit(APEXIT_CHILDFATAL);
+            }
+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+        }
+#endif
 
 	for (;;) {
 	    if (ap_listeners->next) {
@@ -617,7 +630,14 @@
 		memcpy(&main_fds, &listenfds, sizeof(fd_set));
 		srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, NULL);
 
-		if (srv < 0 && errno != EINTR) {
+		if (srv <= 0) {
+                    if (srv == 0)
+                        continue;
+                    else if (errno == EINTR) {
+                        /* Go back to a point where we'll see if we should shut down. */
+                        SAFE_ACCEPT(accept_mutex_off());
+                        goto restart;
+                    }
 		    /* Single Unix documents select as returning errnos
 		     * EBADF, EINTR, and EINVAL... and in none of those
 		     * cases does it make sense to continue.  In fact
@@ -627,9 +647,6 @@
 		    ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, "select: (listen)");
 		    clean_child_exit(1);
 		}
-
-		if (srv <= 0)
-		    continue;
 
 		/* we remember the last_lr we searched last time around so that
 		   we don't end up starving any particular listening socket */
Index: srclib/apr/include/apr_lock.h
===================================================================
RCS file: /home/cvs/apr/include/apr_lock.h,v
retrieving revision 1.24
diff -u -r1.24 apr_lock.h
--- srclib/apr/include/apr_lock.h	2001/05/31 03:29:53	1.24
+++ srclib/apr/include/apr_lock.h	2001/06/01 17:50:18
@@ -178,6 +178,8 @@
                                            const char *key,
                                            apr_status_t (*cleanup)(void *));
 
+APR_DECLARE(apr_status_t) apr_lock_set_interruptible(apr_lock_t *lock);
+
 #ifdef __cplusplus
 }
 #endif
Index: srclib/apr/include/arch/unix/locks.h
===================================================================
RCS file: /home/cvs/apr/include/arch/unix/locks.h,v
retrieving revision 1.27
diff -u -r1.27 locks.h
--- srclib/apr/include/arch/unix/locks.h	2001/05/31 03:29:54	1.27
+++ srclib/apr/include/arch/unix/locks.h	2001/06/01 17:50:24
@@ -134,6 +134,9 @@
     pthread_rwlock_t rwlock;
 #endif
 #endif
+#if !APR_USE_PROC_PTHREAD_SERIALIZE
+    int interruptible;
+#endif
     /* At some point, we should do a scope for both inter and intra process
      * locking here.  Something like pthread_mutex with PTHREAD_PROCESS_SHARED
      */    
Index: srclib/apr/locks/unix/crossproc.c
===================================================================
RCS file: /home/cvs/apr/locks/unix/crossproc.c,v
retrieving revision 1.42
diff -u -r1.42 crossproc.c
--- srclib/apr/locks/unix/crossproc.c	2001/02/23 20:29:07	1.42
+++ srclib/apr/locks/unix/crossproc.c	2001/06/01 17:50:29
@@ -110,7 +110,7 @@
 
     do {
         rc = semop(lock->interproc, &op_on, 1);
-    } while (rc < 0 && errno == EINTR);
+    } while (rc < 0 && errno == EINTR && !lock->interruptible);
     if (rc < 0) {
         return errno;
     }
@@ -326,7 +326,7 @@
 
     do {
         rc = fcntl(lock->interproc, F_SETLKW, &lock_it);
-    } while (rc < 0 && errno == EINTR);
+    } while (rc < 0 && errno == EINTR && !lock->interruptible);
     if (rc < 0) {
         return errno;
     }
@@ -406,7 +406,7 @@
 
     do {
         rc = flock(lock->interproc, LOCK_EX);
-    } while (rc < 0 && errno == EINTR);
+    } while (rc < 0 && errno == EINTR && !lock->interruptible);
     if (rc < 0) {
         return errno;
     }
Index: srclib/apr/locks/unix/locks.c
===================================================================
RCS file: /home/cvs/apr/locks/unix/locks.c,v
retrieving revision 1.47
diff -u -r1.47 locks.c
--- srclib/apr/locks/unix/locks.c	2001/05/31 03:29:59	1.47
+++ srclib/apr/locks/unix/locks.c	2001/06/01 17:50:29
@@ -309,4 +309,17 @@
 #endif
     return APR_SUCCESS;
 }
-    
+
+apr_status_t apr_lock_set_interruptible(apr_lock_t *lock)
+{
+    if (lock->scope != APR_CROSS_PROCESS) {
+        return APR_ENOTIMPL;
+    }
+
+#if APR_USE_PROC_PTHREAD_SERIALIZE
+    return APR_ENOTIMPL;
+#else
+    lock->interruptible = 1;
+    return APR_SUCCESS;
+#endif
+}

-- 
Jeff Trawick | trawickj@bellsouth.net | PGP public key at web site:
       http://www.geocities.com/SiliconValley/Park/9289/
             Born in Roswell... married an alien...