httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeff Trawick <trawi...@bellsouth.net>
Subject [PATCH] get threaded MPM to terminate
Date Tue, 24 Apr 2001 14:50:17 GMT
With the level of code in CVS, SIGTERM wakes up the main thread in
each child.  The main thread then enters pthread_join() to wait for a
worker thread to complete but nothing ever happens because there is
nothing to wake up a worker thread.

This patch moves the workers_may_exit field to the scoreboard and has
the parent process set this field and bombard the pipe of death before
sending SIGTERM to the child processes.

The workers_may_exit field is Paul's new life_status field.  Since
this field applies to the entire child process it was moved to a
different place in the scoreboard and prefork.c was updated as
appropriate.

Try to ignore the mpm_trace() stuff in the patch...

Anything good in the following patch is from Greg Ames.  The rest is
mine.

Comments?

Index: include/scoreboard.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/scoreboard.h,v
retrieving revision 1.17
diff -u -r1.17 scoreboard.h
--- include/scoreboard.h	2001/04/23 23:14:35	1.17
+++ include/scoreboard.h	2001/04/24 14:13:05
@@ -1,4 +1,3 @@
-
 /* ====================================================================
  * The Apache Software License, Version 1.1
  *
@@ -152,6 +151,9 @@
 #define SB_WORKING  0  /* The server is busy and the child is useful. */
 #define SB_IDLE_DIE 1  /* The server is idle and the child is superfluous. */
                        /*   The child should check for this and exit gracefully. */
+#define SB_TERM_DIE 2  /* The child is going away on the whim of the parent. */
+#define SB_MAXREQ_DIE 3 /* This child has served enough requests. */
+#define SB_FATAL_DIE  4 /* Some fatal error has occurred. */
 
 /* stuff which is thread/process specific */
 typedef struct {
@@ -170,7 +172,6 @@
     unsigned long my_bytes_served;
     unsigned long conn_bytes;
     unsigned short conn_count;
-    unsigned short life_status;    /* Either SB_WORKING or SB_IDLE_DIE */
     apr_time_t start_time;
     apr_time_t stop_time;
 #ifdef HAVE_TIMES
@@ -191,11 +192,15 @@
                                          * should still be serving requests. */
 } global_score;
 
-/* stuff which the parent generally writes and the children rarely read */
+/* stuff which (mostly) the parent generally writes and the children rarely read 
+ * exception: life_status is written to by both parent and children and is
+ *            checked often by children
+ */
 typedef struct {
     pid_t pid;
     ap_generation_t generation;	/* generation of this child */
     int worker_threads;
+    unsigned short life_status; /* Either SB_WORKING or SB_IDLE_DIE */
 #ifdef OPTIMIZE_TIMEOUTS
     time_t last_rtime;		/* time(0) of the last change */
     vtime_t last_vtime;		/* the last vtime the parent has seen */
Index: server/mpm/prefork/prefork.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/prefork/prefork.c,v
retrieving revision 1.173
diff -u -r1.173 prefork.c
--- server/mpm/prefork/prefork.c	2001/04/13 19:00:38	1.173
+++ server/mpm/prefork/prefork.c	2001/04/24 14:13:10
@@ -232,7 +232,7 @@
     if (pchild) {
 	apr_pool_destroy(pchild);
     }
-    ap_scoreboard_image->servers[my_child_num][0].life_status = SB_WORKING;
+    ap_scoreboard_image->parent[my_child_num].life_status = SB_WORKING;
     chdir_for_gprof();
     exit(code);
 }
@@ -373,7 +373,7 @@
 static void please_die_gracefully(int sig)
 {
     /* clean_child_exit(0); */
-    ap_scoreboard_image->servers[my_child_num][0].life_status = SB_IDLE_DIE;
+    ap_scoreboard_image->parent[my_child_num].life_status = SB_IDLE_DIE;
     if (sig == SIGHUP) {
         (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num),
                                       SERVER_GRACEFUL, (request_rec *) NULL);
@@ -529,7 +529,7 @@
 static fd_set main_fds;
 
 #define I_AM_TO_SHUTDOWN()                                                   \
-(ap_scoreboard_image->servers[my_child_num][0].life_status != SB_WORKING)
+(ap_scoreboard_image->parent[my_child_num].life_status != SB_WORKING)
    
 int ap_graceful_stop_signalled(void)
 {
@@ -840,7 +840,7 @@
 	apr_signal(SIGQUIT, SIG_DFL);
 #endif
 	apr_signal(SIGTERM, please_die_gracefully);
-        ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING;
+        ap_scoreboard_image->parent[slot].life_status = SB_WORKING;
 	child_main(slot);
     }
 
@@ -891,7 +891,7 @@
 	apr_signal(SIGHUP, please_die_gracefully);
 	apr_signal(SIGWINCH, please_die_gracefully);
 	apr_signal(SIGTERM, please_die_gracefully);
-        ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING;
+        ap_scoreboard_image->parent[slot].life_status = SB_WORKING;
 	child_main(slot);
     }
 
@@ -1254,7 +1254,7 @@
     update_scoreboard_global();
     
     for (index = 0; index < ap_daemons_limit; ++index) {
-        ap_scoreboard_image->servers[index][0].life_status = SB_IDLE_DIE;
+        ap_scoreboard_image->parent[index].life_status = SB_IDLE_DIE;
     }
 
     if (is_graceful) {
Index: server/mpm/threaded/threaded.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/mpm/threaded/threaded.c,v
retrieving revision 1.26
diff -u -r1.26 threaded.c
--- server/mpm/threaded/threaded.c	2001/04/23 23:14:35	1.26
+++ server/mpm/threaded/threaded.c	2001/04/24 14:13:13
@@ -105,11 +105,17 @@
 static int min_spare_threads=0;
 static int max_spare_threads=0;
 static int ap_daemons_limit=0;
-static int workers_may_exit = 0;
 static int requests_this_child;
 static int num_listensocks = 0;
 static apr_socket_t **listensocks;
+static int my_child_num;
 
+#define CHK_WORKERS_MAY_EXIT() \
+(ap_scoreboard_image->parent[my_child_num].life_status != SB_WORKING && \
+ mpm_trace("workers should exit now"))
+#define SET_WORKERS_MAY_EXIT(reason) \
+ap_scoreboard_image->parent[my_child_num].life_status = (reason)
+
 /* The structure used to pass unique initialization info to each thread */
 typedef struct {
     int pid;
@@ -171,6 +177,13 @@
 #define SAFE_ACCEPT(stmt) (stmt)
 #endif
 
+static int mpm_trace(const char *s)
+{
+    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, ap_server_conf, "thread %d/%ld: %s",
+                 ap_my_pid, (long)pthread_self(), s);
+    return 1;
+}
+
 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
 {
     switch(query_code){
@@ -284,6 +297,7 @@
 
 static void sig_term(int sig)
 {
+    mpm_trace("got SIGTERM");
     ap_start_shutdown();
 }
 
@@ -435,11 +449,12 @@
         ap_lingering_close(current_conn);
     }
 }
-/* Sets workers_may_exit if we received a character on the pipe_of_death */
+/* Sets WORKERS_MAY_EXIT if we received a character on the pipe_of_death */
 static void check_pipe_of_death(void)
 {
+    mpm_trace("got data on pipe of death");
     apr_lock_acquire(pipe_of_death_mutex);
-    if (!workers_may_exit) {
+    if (!CHK_WORKERS_MAY_EXIT()) {
         apr_status_t ret;
         char pipe_read_char;
 	apr_size_t n = 1;
@@ -452,7 +467,7 @@
         else {
             /* It won the lottery (or something else is very
              * wrong). Embrace death with open arms. */
-            workers_may_exit = 1;
+            SET_WORKERS_MAY_EXIT(SB_TERM_DIE);
         }
     }
     apr_lock_release(pipe_of_death_mutex);
@@ -487,8 +502,9 @@
     /* TODO: Switch to a system where threads reuse the results from earlier
        poll calls - manoj */
     while (1) {
-        workers_may_exit |= (ap_max_requests_per_child != 0) && (requests_this_child
<= 0);
-        if (workers_may_exit) break;
+        if ((ap_max_requests_per_child != 0) && (requests_this_child <= 0))
+            SET_WORKERS_MAY_EXIT(SB_MAXREQ_DIE);
+        if (CHK_WORKERS_MAY_EXIT()) break;
 
         (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, 
                                       (request_rec *) NULL);
@@ -497,10 +513,10 @@
             ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                          "apr_lock_acquire failed. Attempting to shutdown "
                          "process gracefully.");
-            workers_may_exit = 1;
+            SET_WORKERS_MAY_EXIT(SB_FATAL_DIE);
         }
 
-        while (!workers_may_exit) {
+        while (!CHK_WORKERS_MAY_EXIT()) {
 	    apr_status_t ret;
 	    apr_int16_t event;
 
@@ -514,10 +530,10 @@
                  * circumstances. Let's try exiting gracefully, for now. */
                 ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *)
                              ap_server_conf, "apr_poll: (listen)");
-                workers_may_exit = 1;
+                SET_WORKERS_MAY_EXIT(SB_FATAL_DIE);
             }
 
-            if (workers_may_exit) break;
+            if (CHK_WORKERS_MAY_EXIT()) break;
 
 	    apr_poll_revents_get(&event, listensocks[0], pollset);
             if (event & APR_POLLIN) {
@@ -550,7 +566,7 @@
             }
         }
     got_fd:
-        if (!workers_may_exit) {
+        if (!CHK_WORKERS_MAY_EXIT()) {
             if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) {
                 csd = NULL;
                 ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, 
@@ -561,7 +577,7 @@
                 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                              "apr_lock_release failed. Attempting to shutdown "
                              "process gracefully.");
-                workers_may_exit = 1;
+                SET_WORKERS_MAY_EXIT(SB_FATAL_DIE);
             }
             if (csd != NULL) {
                 process_socket(ptrans, csd, process_slot, thread_slot);
@@ -574,7 +590,7 @@
                 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
                              "apr_lock_release failed. Attempting to shutdown "
                              "process gracefully.");
-                workers_may_exit = 1;
+                SET_WORKERS_MAY_EXIT(SB_FATAL_DIE);
             }
             break;
         }
@@ -611,12 +627,11 @@
     apr_thread_t **threads;
     apr_threadattr_t *thread_attr;
     int i;
-    int my_child_num = child_num_arg;
     proc_info *my_info = NULL;
     ap_listen_rec *lr;
     apr_status_t rv;
-
 
+    my_child_num = child_num_arg;
     ap_my_pid = getpid();
     apr_pool_create(&pchild, pconf);
 
@@ -1073,11 +1088,35 @@
     restart_pending = shutdown_pending = 0;
 
     server_main_loop(remaining_children_to_start);
-
+    mpm_trace("back from server_main_loop");
     if (shutdown_pending) {
+        int i;
+        char char_of_death = '!';
+
         /* Time to gracefully shut down:
          * Kill child processes, tell them to call child_exit, etc...
          */
+        /* sequence of operations:
+         * 1) set the workers_may_exit flag for each child process
+         * 2) write data on the pipe of death so that the worker threads
+         *    are awakened
+         * 3) send SIGTERM to the main threads (blocked in sigwait()) so they
+         *    wake up and join up with the exited worker threads
+         */
+        mpm_trace("setting workers_may_exit");
+        for (i = 0; i < ap_daemons_limit; ++i) {
+            ap_scoreboard_image->parent[i].life_status = SB_TERM_DIE;
+        }
+	/* give the children the signal to die */
+        mpm_trace("sending pipe of death signals");
+        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++;
+        }
+        mpm_trace("sending SIGTERM");
         if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
             ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
         }

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

Mime
View raw message