You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Justin Erenkrantz <je...@ebuilt.com> on 2001/07/14 22:54:50 UTC

[PATCH] Add intraprocess mutex to threaded MPM WAS Re: Terminiting threads in a process RE: [PATCH] Problems with MPM threaded

> > Ah.  Yes, that makes more sense.  But, that's not what's there now.
> >
> > Shall I submit a patch to threaded MPM to do this?  -- justin
> 
> Please.

This also includes my POD patch.  I can separate it out if you don't
want the POD code merged yet.  -- justin

Index: threaded.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/threaded/threaded.c,v
retrieving revision 1.44
diff -u -r1.44 threaded.c
--- threaded.c	2001/07/03 13:58:10	1.44
+++ threaded.c	2001/07/14 20:48:04
@@ -143,10 +143,7 @@
 
 char ap_coredump_dir[MAX_STRING_LEN];
 
-static apr_file_t *pipe_of_death_in = NULL;
-static apr_file_t *pipe_of_death_out = NULL;
-static apr_lock_t *pipe_of_death_mutex;   /* insures that a child process only
-                                             consumes one character */
+static ap_pod_t *pipe_of_death;
 
 /* *Non*-shared http_main globals... */
 
@@ -178,7 +175,13 @@
 static int worker_thread_count;
 static apr_lock_t *worker_thread_count_mutex;
 
-/* Locks for accept serialization */
+/* Locks for accept serialization
+ * worker_accept_mutex ensures that only one thread in a child process
+ * may be in accept.  It also ensures that when we have 
+ * workers_may_exit=1 that we exit.
+ * accept_mutex is the cross-process mutex which all children have.
+ */
+static apr_lock_t *worker_accept_mutex;
 static apr_lock_t *accept_mutex;
 static apr_lockmech_e_np accept_lock_mech = APR_LOCK_DEFAULT;
 static const char *lock_fname;
@@ -494,29 +497,6 @@
     }
 }
 
-/* Sets workers_may_exit if we received a character on the pipe_of_death */
-static void check_pipe_of_death(void)
-{
-    apr_lock_acquire(pipe_of_death_mutex);
-    if (!workers_may_exit) {
-        apr_status_t ret;
-        char pipe_read_char;
-	apr_size_t n = 1;
-
-        ret = apr_recv(listensocks[0], &pipe_read_char, &n);
-        if (APR_STATUS_IS_EAGAIN(ret)) {
-            /* It lost the lottery. It must continue to suffer
-             * through a life of servitude. */
-        }
-        else {
-            /* It won the lottery (or something else is very
-             * wrong). Embrace death with open arms. */
-            workers_may_exit = 1;
-        }
-    }
-    apr_lock_release(pipe_of_death_mutex);
-}
-
 static void * worker_thread(void * dummy)
 {
     proc_info * ti = dummy;
@@ -539,8 +519,8 @@
     worker_thread_count++;
     apr_lock_release(worker_thread_count_mutex);
 
-    apr_poll_setup(&pollset, num_listensocks+1, tpool);
-    for(n=0 ; n <= num_listensocks ; ++n)
+    apr_poll_setup(&pollset, num_listensocks, tpool);
+    for(n = 0; n < num_listensocks; ++n)
 	apr_poll_socket_add(pollset, listensocks[n], APR_POLLIN);
 
     /* TODO: Switch to a system where threads reuse the results from earlier
@@ -553,7 +533,10 @@
 
         (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
                                       (request_rec *) NULL);
-        if ((rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
+
+        apr_lock_acquire(worker_accept_mutex);
+        if (!workers_may_exit && 
+            (rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex)))
             != APR_SUCCESS) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                          "apr_lock_acquire failed. Attempting to shutdown "
@@ -580,12 +563,8 @@
 
             if (workers_may_exit) break;
 
-	    apr_poll_revents_get(&event, listensocks[0], pollset);
-            if (event & APR_POLLIN) {
-                /* A process got a signal on the shutdown pipe. Check if we're
-                 * the lucky process to die. */
-                check_pipe_of_death();
-                continue;
+            if (!ap_mpm_pod_check(pipe_of_death)) {
+                workers_may_exit = 1;
             }
 
             if (num_listensocks == 1) {
@@ -624,6 +603,12 @@
                              "process gracefully.");
                 workers_may_exit = 1;
             }
+            if ((rv = apr_lock_release(worker_accept_mutex)) != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+                             "apr_lock_release failed. Attempting to shutdown "
+                             "process gracefully.");
+                workers_may_exit = 1;
+            }
             if (csd != NULL) {
                 process_socket(ptrans, csd, process_slot, thread_slot);
                 requests_this_child--;
@@ -637,6 +622,12 @@
                              "process gracefully.");
                 workers_may_exit = 1;
             }
+            if ((rv = apr_lock_release(worker_accept_mutex)) != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
+                             "apr_lock_release failed. Attempting to shutdown "
+                             "process gracefully.");
+                workers_may_exit = 1;
+            }
             break;
         }
         apr_pool_clear(ptrans);
@@ -780,12 +771,8 @@
     }
     
     /* Set up the pollfd array */
-    listensocks = apr_pcalloc(pchild,
-			    sizeof(*listensocks) * (num_listensocks + 1));
-#if APR_FILES_AS_SOCKETS
-    apr_socket_from_file(&listensocks[0], pipe_of_death_in);
-#endif
-    for (lr = ap_listeners, i = 1; i <= num_listensocks; lr = lr->next, ++i)
+    listensocks = apr_pcalloc(pchild, sizeof(*listensocks) * num_listensocks);
+    for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, ++i)
 	listensocks[i]=lr->sd;
 
     /* Setup worker threads */
@@ -799,9 +786,8 @@
     worker_thread_count = 0;
     apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS,
                     NULL, pchild);
-    apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS, 
+    apr_lock_create(&worker_accept_mutex, APR_MUTEX, APR_INTRAPROCESS,
                     NULL, pchild);
-
     ts = apr_palloc(pchild, sizeof(*ts));
 
     apr_threadattr_create(&thread_attr, pchild);
@@ -894,29 +880,6 @@
     return 0;
 }
 
-/* If there aren't many connections coming in from the network, the child 
- * processes may need to be awakened from their network i/o waits.
- * The pipe of death is an effective prod.
- */
-   
-static void wake_up_and_die(void) 
-{
-    int i;
-    char char_of_death = '!';
-    apr_size_t one = 1;
-    apr_status_t rv;
-    
-    for (i = 0; i < ap_daemons_limit;) {
-        if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) 
-                                 != APR_SUCCESS) {
-            if (APR_STATUS_IS_EINTR(rv)) continue;
-            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, 
-                         "write pipe_of_death");
-        }
-        i++;
-    }
-}
-
 /* start up a bunch of children */
 static void startup_children(int number_to_start)
 {
@@ -955,8 +918,6 @@
     int free_slots[MAX_SPAWN_RATE];
     int last_non_dead;
     int total_non_dead;
-    apr_size_t one = 1;
-    apr_status_t rv;
 
     /* initialize the free_list */
     free_length = 0;
@@ -1004,11 +965,7 @@
     ap_max_daemons_limit = last_non_dead + 1;
 
     if (idle_thread_count > max_spare_threads) {
-        char char_of_death = '!';
-        /* Kill off one child */
-        if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death");
-        }
+        ap_mpm_pod_signal(pipe_of_death);
         idle_spawn_rate = 1;
     }
     else if (idle_thread_count < min_spare_threads) {
@@ -1129,18 +1086,11 @@
     pconf = _pconf;
     ap_server_conf = s;
 
-    rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf);
+    rv = ap_mpm_pod_open(pconf, &pipe_of_death);
     if (rv != APR_SUCCESS) {
         ap_log_error(APLOG_MARK, APLOG_ERR, rv,
-                     (const server_rec*) ap_server_conf,
-                     "apr_file_pipe_create (pipe_of_death)");
-        exit(1);
-    }
-
-    if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, rv,
                      (const server_rec*) ap_server_conf,
-                     "apr_file_pipe_timeout_set (pipe_of_death)");
+                     "ap_mpm_pod_open");
         exit(1);
     }
 
@@ -1208,7 +1158,7 @@
         /* Time to gracefully shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
-        wake_up_and_die();
+        ap_mpm_pod_killpg(pipe_of_death, ap_daemons_limit);
 
         if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
@@ -1249,7 +1199,7 @@
     update_scoreboard_global();
     
     /* wake up the children...time to die.  But we'll have more soon */
-    wake_up_and_die();
+    ap_mpm_pod_killpg(pipe_of_death, ap_daemons_limit);
     
     if (is_graceful) {
 	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,
Index: mpm.h
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/threaded/mpm.h,v
retrieving revision 1.5
diff -u -r1.5 mpm.h
--- mpm.h	2001/05/07 18:41:48	1.5
+++ mpm.h	2001/07/14 20:48:04
@@ -66,6 +66,7 @@
 #define MPM_NAME "Threaded"
 
 #define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1
+#define AP_MPM_USES_POD 1
 #define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image())
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
 #define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)