]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
merge this feature, and code cleanups for signal handlers,
authorJeff Trawick <trawick@apache.org>
Thu, 26 Feb 2004 20:32:23 +0000 (20:32 +0000)
committerJeff Trawick <trawick@apache.org>
Thu, 26 Feb 2004 20:32:23 +0000 (20:32 +0000)
from 2.1-dev:

      Add fatal exception hook for use by diagnostic modules.  The hook
      is only available if the --enable-exception-hook configure parm
      is used and the EnableExceptionHook directive has been set to
      "on".

Reviewed by: stoddard, jerenkrantz, gregames

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/APACHE_2_0_BRANCH@102786 13f79535-47bb-0310-9956-ffa450edef68

17 files changed:
CHANGES
STATUS
configure.in
include/ap_mpm.h
include/mpm_common.h
server/core.c
server/mpm/experimental/leader/leader.c
server/mpm/experimental/leader/mpm.h
server/mpm/experimental/perchild/mpm.h
server/mpm/experimental/perchild/perchild.c
server/mpm/experimental/threadpool/mpm.h
server/mpm/experimental/threadpool/threadpool.c
server/mpm/prefork/mpm.h
server/mpm/prefork/prefork.c
server/mpm/worker/mpm.h
server/mpm/worker/worker.c
server/mpm_common.c

diff --git a/CHANGES b/CHANGES
index 921c46ab4459fa7182f66a0883f68a2fbf78e668..e4ee2c533c9e19c8ed421fea18a5043ce55def01 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
 Changes with Apache 2.0.49
 
+  *) Add fatal exception hook for use by diagnostic modules.  The hook
+     is only available if the --enable-exception-hook configure parm 
+     is used and the EnableExceptionHook directive has been set to 
+     "on".  [Jeff Trawick]
+
   *) Allow mod_auth_digest to work with sub-requests with different
      methods than the original request.  PR 25040.
      [Josh Dady <jpd indecisive.com>]
diff --git a/STATUS b/STATUS
index dc7c1981152c091eeb7d2f41a211c5199fe22215..0205c420ec7f7d33a34f84f3b3cab73798237f01 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -1,5 +1,5 @@
 APACHE 2.0 STATUS:                                              -*-text-*-
-Last modified at [$Date: 2004/02/26 20:30:26 $]
+Last modified at [$Date: 2004/02/26 20:32:19 $]
 
 Release:
 
@@ -276,15 +276,6 @@ PATCHES TO BACKPORT FROM 2.1
       http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/arch/win32/mod_isapi.c?r1=1.98&r2=1.99
       +1: trawick, stoddard
 
-    * fatal exception hook and related signal handler cleanups
-      This also fixes an issue for me on Solaris where the cgid daemon
-      won't restart multiple times because of something different
-      about the signal handling the second time it is started.  With
-      this patch I can "kill -SEGV" the cgid daemon process a number
-      of times and the daemon will be restarted each time.
-      http://www.apache.org/~trawick/fatal_exception_20.patch
-      +1: trawick, stoddard, jerenkrantz, gregames
-
 CURRENT RELEASE NOTES:
 
     * Backwards compatibility is expected of future Apache 2.0 releases,
index 687d83a4819f9fad4064279c985465cb8ddafcad..aa4dceabfd4baf94d913f7f695b757005f14efe7 100644 (file)
@@ -368,6 +368,12 @@ else
     nonssl_listen_stmt_2="Listen [[::]]:@@Port@@"
 fi
 
+AC_ARG_ENABLE(exception-hook,APACHE_HELP_STRING(--enable-exception-hook,Enable fatal exception hook),
+[
+    AC_DEFINE(AP_ENABLE_EXCEPTION_HOOK, 1,
+              [Allow modules to run hook after a fatal exception])
+])dnl
+
 AC_ARG_ENABLE(maintainer-mode,APACHE_HELP_STRING(--enable-maintainer-mode,Turn on debugging and compile time warnings),
 [
   APR_ADDTO(CPPFLAGS, -DAP_DEBUG)
index afe030678f57fd0bc890f2835f46aafff1e9f919..ce351aff31d29e4c6ccbcb159db92a04540f0613 100644 (file)
@@ -163,4 +163,13 @@ extern void moncontrol(int);
 #define AP_MONCONTROL(x)
 #endif
 
+#if AP_ENABLE_EXCEPTION_HOOK
+typedef struct ap_exception_info_t {
+    int sig;
+    pid_t pid;
+} ap_exception_info_t;
+
+AP_DECLARE_HOOK(int,fatal_exception,(ap_exception_info_t *ei))
+#endif /*AP_ENABLE_EXCEPTION_HOOK*/
+
 #endif
index 0605131093aa8dd592b587dc152ae0c6d5d60409..13d7afd9bb8b79ab094bf33201ffef9d3dcb1129 100644 (file)
@@ -249,6 +249,16 @@ extern const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
                                            const char *arg);
 #endif
 
+#ifdef AP_MPM_WANT_FATAL_SIGNAL_HANDLER
+extern apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *pconf);
+extern apr_status_t ap_fatal_signal_child_setup(server_rec *s);
+#endif
+
+#if AP_ENABLE_EXCEPTION_HOOK
+extern const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
+                                             const char *arg);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index abc0befac714b9d8c9cdd64cfa224a50db142099..5ca95130b8563526d5fc05c41660cadf1ee5753a 100644 (file)
@@ -3242,6 +3242,10 @@ AP_INIT_TAKE1("AcceptMutex", ap_mpm_set_accept_lock_mech, NULL, RSRC_CONF,
 AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
               "Maximum number of 1k blocks a particular childs allocator may hold."),
 #endif
+#if AP_ENABLE_EXCEPTION_HOOK
+AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
+              "Controls whether exception hook may be called after a crash"),
+#endif
 { NULL }
 };
 
index af427c4322e41feeca0345226d7bfedb6c074bb7..6142b326385d8603dbe5f63dec38923ea0e6869c 100644 (file)
@@ -422,40 +422,6 @@ static void clean_child_exit(int code)
     exit(code);
 }
 
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    apr_filepath_set(ap_coredump_dir, pconf);
-    apr_signal(sig, SIG_DFL);
-    /* linuxthreads issue calling getpid() here:
-     *   This comparison won't match if the crashing thread is
-     *   some module's thread that runs in the parent process.
-     *   The fallout, which is limited to linuxthreads:
-     *   The special log message won't be written when such a
-     *   thread in the parent causes the parent to crash.
-     */
-    if (getpid() == parent_pid) {
-        ap_log_error(APLOG_MARK, APLOG_NOTICE,
-                     0, ap_server_conf,
-                     "seg fault or similar nasty error detected "
-                     "in the parent process");
-        
-        /* XXX we can probably add some rudimentary cleanup code here,
-         * like getting rid of the pid file.  If any additional bad stuff
-         * happens, we are protected from recursive errors taking down the
-         * system since this function is no longer the signal handler   GLA
-         */
-    }
-    kill(ap_my_pid, sig);
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
 static void just_die(int sig)
 {
     clean_child_exit(0);
@@ -535,42 +501,16 @@ static void set_signals(void)
 {
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
+#endif
+
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
 
+#ifndef NO_USE_SIGACTION
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
 
-    if (!one_process) {
-        sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-        sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-        sa.sa_flags = SA_RESETHAND;
-#endif
-        if (sigaction(SIGSEGV, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-        if (sigaction(SIGBUS, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-        if (sigaction(SIGABORT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-        if (sigaction(SIGABRT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-        if (sigaction(SIGILL, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGILL)");
-#endif
-        sa.sa_flags = 0;
-    }
     sa.sa_handler = sig_term;
     if (sigaction(SIGTERM, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
@@ -612,19 +552,6 @@ static void set_signals(void)
                      "sigaction(" AP_SIG_GRACEFUL_STRING ")");
 #else
     if (!one_process) {
-        apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-        apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-        apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-        apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-        apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
 #ifdef SIGXCPU
         apr_signal(SIGXCPU, SIG_DFL);
 #endif /* SIGXCPU */
@@ -1080,6 +1007,7 @@ static void child_main(int child_num_arg)
                                   */
 
     ap_my_pid = getpid();
+    ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
     /*stuff to do before we switch id's, so we have permissions.*/
index ec4129a7b14543a020ae2009a103a3f1930e5b42..e9e51438dce447157e962c9dba8ba0337282b064 100644 (file)
@@ -34,6 +34,7 @@
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 #define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
 #define AP_MPM_USES_POD 1
index 2ae76146caf97d3ccfba9b9d31c82dc3ec87bf63..95f3eb35f3e66c36d6e678ed60b1b8be44f32cd3 100644 (file)
@@ -34,6 +34,7 @@
 #define AP_MPM_WANT_SET_COREDUMPDIR
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 #define AP_MPM_WANT_SIGNAL_SERVER
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_USES_POD
 
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
index 4ddaee6a4f29a098091fadc6f1b3594738d2778f..d068152f91bac6ccfde867cfec412a953782028f 100644 (file)
@@ -281,21 +281,6 @@ static void clean_child_exit(int code)
     exit(code);
 }
 
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    chdir(ap_coredump_dir);
-    apr_signal(sig, SIG_DFL);
-    kill(getpid(), sig);
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
 static void just_die(int sig)
 {
     clean_child_exit(0);
@@ -375,42 +360,16 @@ static void set_signals(void)
 {
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
+#endif
 
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
+
+#ifndef NO_USE_SIGACTION
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
 
-    if (!one_process) {
-        sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-        sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-        sa.sa_flags = SA_RESETHAND;
-#endif
-        if (sigaction(SIGSEGV, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
-                         "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-        if (sigaction(SIGBUS, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
-                         "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-        if (sigaction(SIGABORT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
-                         "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-        if (sigaction(SIGABRT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
-                         "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-        if (sigaction(SIGILL, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
-                         "sigaction(SIGILL)");
-#endif
-        sa.sa_flags = 0;
-    }
     sa.sa_handler = sig_term;
     if (sigaction(SIGTERM, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
@@ -452,19 +411,6 @@ static void set_signals(void)
                      "sigaction(" AP_SIG_GRACEFUL_STRING ")");
 #else
     if (!one_process) {
-        apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-        apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-        apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-        apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-        apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
 #ifdef SIGXCPU
         apr_signal(SIGXCPU, SIG_DFL);
 #endif /* SIGXCPU */
@@ -982,6 +928,7 @@ static void child_main(int child_num_arg)
     ap_listen_rec *lr;
     
     my_pid = getpid();
+    ap_fatal_signal_child_setup(ap_server_conf);
     child_num = child_num_arg;
     apr_pool_create(&pchild, pconf);
 
index 7423c4c3670dab8951694b88a34e2dd028dded80..afdcce52100dd72197de7077612e2d7ede4a68c0 100644 (file)
@@ -34,6 +34,7 @@
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 #define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
index a821d8eec73b3357bc09f5eeddbd7a23427bf9aa..a0df66ceeac20b866647352e8f57b3a1fe4c62a2 100644 (file)
@@ -498,40 +498,6 @@ static void clean_child_exit(int code)
     exit(code);
 }
 
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    apr_filepath_set(ap_coredump_dir, pconf);
-    apr_signal(sig, SIG_DFL);
-    /* linuxthreads issue calling getpid() here:
-     *   This comparison won't match if the crashing thread is
-     *   some module's thread that runs in the parent process.
-     *   The fallout, which is limited to linuxthreads:
-     *   The special log message won't be written when such a
-     *   thread in the parent causes the parent to crash.
-     */
-    if (getpid() == parent_pid) {
-        ap_log_error(APLOG_MARK, APLOG_NOTICE,
-                     0, ap_server_conf,
-                     "seg fault or similar nasty error detected "
-                     "in the parent process");
-        
-        /* XXX we can probably add some rudimentary cleanup code here,
-         * like getting rid of the pid file.  If any additional bad stuff
-         * happens, we are protected from recursive errors taking down the
-         * system since this function is no longer the signal handler   GLA
-         */
-    }
-    kill(ap_my_pid, sig);
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
 static void just_die(int sig)
 {
     clean_child_exit(0);
@@ -606,42 +572,16 @@ static void set_signals(void)
 {
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
+#endif
+
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
 
+#ifndef NO_USE_SIGACTION
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
 
-    if (!one_process) {
-        sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-        sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-        sa.sa_flags = SA_RESETHAND;
-#endif
-        if (sigaction(SIGSEGV, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-        if (sigaction(SIGBUS, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-        if (sigaction(SIGABORT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-        if (sigaction(SIGABRT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-        if (sigaction(SIGILL, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGILL)");
-#endif
-        sa.sa_flags = 0;
-    }
     sa.sa_handler = sig_term;
     if (sigaction(SIGTERM, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
@@ -683,19 +623,6 @@ static void set_signals(void)
                      "sigaction(" AP_SIG_GRACEFUL_STRING ")");
 #else
     if (!one_process) {
-        apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-        apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-        apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-        apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-        apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
 #ifdef SIGXCPU
         apr_signal(SIGXCPU, SIG_DFL);
 #endif /* SIGXCPU */
@@ -1294,6 +1221,7 @@ static void child_main(int child_num_arg)
                                    * child initializes
                                    */
     ap_my_pid = getpid();
+    ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
     /*stuff to do before we switch id's, so we have permissions.*/
index cb4385a666d88bff8aa46f94f05bc9cb811a44cc..64c1114866c3a431b87f2ac24dc74d5be67d75a7 100644 (file)
@@ -36,6 +36,7 @@
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 #define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
 #define AP_MPM_USES_POD 1
index 7e42acede88a3ce85c1f241ad444d0ff91236896..cd14da135b2a375d3ff380ebca29b1f2636388aa 100644 (file)
@@ -315,34 +315,6 @@ int reap_children(int *exitcode, apr_exit_why_e *status)
 }
 #endif
 
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    chdir(ap_coredump_dir);
-    apr_signal(sig, SIG_DFL);
-    /* linuxthreads issue calling getpid() here:
-     *   This comparison won't match if the crashing thread is
-     *   some module's thread that runs in the parent process.
-     *   The fallout, which is limited to linuxthreads:
-     *   The special log message won't be written when such a
-     *   thread in the parent causes the parent to crash.
-     */
-    if (getpid() == parent_pid) {
-            ap_log_error(APLOG_MARK, APLOG_NOTICE,
-                         0, ap_server_conf,
-                         "seg fault or similar nasty error detected "
-                         "in the parent process");
-    }
-    kill(getpid(), sig);
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
 /*****************************************************************
  * Connection structures and accounting...
  */
@@ -386,37 +358,16 @@ static void set_signals(void)
 {
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
+#endif
+
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
 
+#ifndef NO_USE_SIGACTION
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
 
-    if (!one_process) {
-       sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-       sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-       sa.sa_flags = SA_RESETHAND;
-#endif
-       if (sigaction(SIGSEGV, &sa, NULL) < 0)
-           ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-       if (sigaction(SIGBUS, &sa, NULL) < 0)
-           ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-       if (sigaction(SIGABORT, &sa, NULL) < 0)
-           ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-       if (sigaction(SIGABRT, &sa, NULL) < 0)
-           ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-       if (sigaction(SIGILL, &sa, NULL) < 0)
-           ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
-#endif
-       sa.sa_flags = 0;
-    }
     sa.sa_handler = sig_term;
     if (sigaction(SIGTERM, &sa, NULL) < 0)
        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
@@ -451,19 +402,6 @@ static void set_signals(void)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
 #else
     if (!one_process) {
-       apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-       apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-       apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-       apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-       apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
 #ifdef SIGXCPU
        apr_signal(SIGXCPU, SIG_DFL);
 #endif /* SIGXCPU */
@@ -528,6 +466,8 @@ static void child_main(int child_num_arg)
     csd = NULL;
     requests_this_child = 0;
 
+    ap_fatal_signal_child_setup(ap_server_conf);
+
     /* Get a sub context for global allocations in this child, so that
      * we can have cleanups occur when the child exits.
      */
index 4a926ab251c4c01e0185ebe7d62c5dd56ffa12c1..b152569dd2cb1664e9baff84b66355a91a5cc8e1 100644 (file)
@@ -34,6 +34,7 @@
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 #define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
index 9c874973da2640053cda197b432d4c71641d32d2..d9e463c4fa3e32769e007195d07e8819b02c19ae 100644 (file)
@@ -337,40 +337,6 @@ static void clean_child_exit(int code)
     exit(code);
 }
 
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
-    apr_filepath_set(ap_coredump_dir, pconf);
-    apr_signal(sig, SIG_DFL);
-    /* linuxthreads issue calling getpid() here:
-     *   This comparison won't match if the crashing thread is
-     *   some module's thread that runs in the parent process.
-     *   The fallout, which is limited to linuxthreads:
-     *   The special log message won't be written when such a
-     *   thread in the parent causes the parent to crash.
-     */
-    if (getpid() == parent_pid) {
-        ap_log_error(APLOG_MARK, APLOG_NOTICE,
-                     0, ap_server_conf,
-                     "seg fault or similar nasty error detected "
-                     "in the parent process");
-        
-        /* XXX we can probably add some rudimentary cleanup code here,
-         * like getting rid of the pid file.  If any additional bad stuff
-         * happens, we are protected from recursive errors taking down the
-         * system since this function is no longer the signal handler   GLA
-         */
-    }
-    kill(ap_my_pid, sig);
-    /* At this point we've got sig blocked, because we're still inside
-     * the signal handler.  When we leave the signal handler it will
-     * be unblocked, and we'll take the signal... and coredump or whatever
-     * is appropriate for this particular Unix.  In addition the parent
-     * will see the real signal we received -- whereas if we called
-     * abort() here, the parent would only see SIGABRT.
-     */
-}
-
 static void just_die(int sig)
 {
     clean_child_exit(0);
@@ -445,42 +411,16 @@ static void set_signals(void)
 {
 #ifndef NO_USE_SIGACTION
     struct sigaction sa;
+#endif
+
+    if (!one_process) {
+        ap_fatal_signal_setup(ap_server_conf, pconf);
+    }
 
+#ifndef NO_USE_SIGACTION
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
 
-    if (!one_process) {
-        sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
-        sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
-        sa.sa_flags = SA_RESETHAND;
-#endif
-        if (sigaction(SIGSEGV, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGSEGV)");
-#ifdef SIGBUS
-        if (sigaction(SIGBUS, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
-        if (sigaction(SIGABORT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
-        if (sigaction(SIGABRT, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
-        if (sigaction(SIGILL, &sa, NULL) < 0)
-            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
-                         "sigaction(SIGILL)");
-#endif
-        sa.sa_flags = 0;
-    }
     sa.sa_handler = sig_term;
     if (sigaction(SIGTERM, &sa, NULL) < 0)
         ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
@@ -522,19 +462,6 @@ static void set_signals(void)
                      "sigaction(" AP_SIG_GRACEFUL_STRING ")");
 #else
     if (!one_process) {
-        apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
-        apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
-        apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
-        apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
-        apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
 #ifdef SIGXCPU
         apr_signal(SIGXCPU, SIG_DFL);
 #endif /* SIGXCPU */
@@ -1165,6 +1092,7 @@ static void child_main(int child_num_arg)
                                    * child initializes
                                    */
     ap_my_pid = getpid();
+    ap_fatal_signal_child_setup(ap_server_conf);
     apr_pool_create(&pchild, pconf);
 
     /*stuff to do before we switch id's, so we have permissions.*/
index 15da034db310351f24a8c4f7de73801f2011f636..e17b552f1fb17fd1600cdc72587e362a44d0927a 100644 (file)
@@ -54,6 +54,9 @@
 #ifdef HAVE_GRP_H
 #include <grp.h>
 #endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
 void ap_reclaim_child_processes(int terminate)
@@ -867,3 +870,161 @@ const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
 }
 
 #endif /* AP_MPM_WANT_SET_MAX_MEM_FREE */
+
+#ifdef AP_MPM_WANT_FATAL_SIGNAL_HANDLER
+
+static pid_t parent_pid, my_pid;
+apr_pool_t *pconf;
+
+#if AP_ENABLE_EXCEPTION_HOOK
+
+static int exception_hook_enabled;
+
+const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
+                                      const char *arg)
+{
+    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (cmd->server->is_virtual) {
+       return "EnableExceptionHook directive not allowed in <VirtualHost>";
+    }
+
+    if (strcasecmp(arg, "on") == 0) {
+        exception_hook_enabled = 1;
+    }
+    else if (strcasecmp(arg, "off") == 0) {
+        exception_hook_enabled = 0;
+    }
+    else {
+        return "parameter must be 'on' or 'off'";
+    }
+
+    return NULL;
+}
+
+APR_HOOK_STRUCT(
+    APR_HOOK_LINK(fatal_exception)
+)
+
+AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
+                          (ap_exception_info_t *ei), (ei), OK, DECLINED)
+
+static void run_fatal_exception_hook(int sig)
+{
+    ap_exception_info_t ei = {0};
+
+    if (exception_hook_enabled &&
+        geteuid() != 0 && 
+        my_pid != parent_pid) {
+        ei.sig = sig;
+        ei.pid = my_pid;
+        ap_run_fatal_exception(&ei);
+    }
+}
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
+/* handle all varieties of core dumping signals */
+static void sig_coredump(int sig)
+{
+    apr_filepath_set(ap_coredump_dir, pconf);
+    apr_signal(sig, SIG_DFL);
+#if AP_ENABLE_EXCEPTION_HOOK
+    run_fatal_exception_hook(sig);
+#endif
+    /* linuxthreads issue calling getpid() here:
+     *   This comparison won't match if the crashing thread is
+     *   some module's thread that runs in the parent process.
+     *   The fallout, which is limited to linuxthreads:
+     *   The special log message won't be written when such a
+     *   thread in the parent causes the parent to crash.
+     */
+    if (getpid() == parent_pid) {
+        ap_log_error(APLOG_MARK, APLOG_NOTICE,
+                     0, ap_server_conf,
+                     "seg fault or similar nasty error detected "
+                     "in the parent process");
+        /* XXX we can probably add some rudimentary cleanup code here,
+         * like getting rid of the pid file.  If any additional bad stuff
+         * happens, we are protected from recursive errors taking down the
+         * system since this function is no longer the signal handler   GLA
+         */
+    }
+    kill(getpid(), sig);
+    /* At this point we've got sig blocked, because we're still inside
+     * the signal handler.  When we leave the signal handler it will
+     * be unblocked, and we'll take the signal... and coredump or whatever
+     * is appropriate for this particular Unix.  In addition the parent
+     * will see the real signal we received -- whereas if we called
+     * abort() here, the parent would only see SIGABRT.
+     */
+}
+
+apr_status_t ap_fatal_signal_child_setup(server_rec *s)
+{
+    my_pid = getpid();
+    return APR_SUCCESS;
+}
+
+apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf)
+{
+#ifndef NO_USE_SIGACTION
+    struct sigaction sa;
+
+    sigemptyset(&sa.sa_mask);
+    
+#if defined(SA_ONESHOT)
+    sa.sa_flags = SA_ONESHOT;
+#elif defined(SA_RESETHAND)
+    sa.sa_flags = SA_RESETHAND;
+#else
+    sa.sa_flags = 0;
+#endif
+
+    sa.sa_handler = sig_coredump;
+    if (sigaction(SIGSEGV, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGSEGV)");
+#ifdef SIGBUS
+    if (sigaction(SIGBUS, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGBUS)");
+#endif
+#ifdef SIGABORT
+    if (sigaction(SIGABORT, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABORT)");
+#endif
+#ifdef SIGABRT
+    if (sigaction(SIGABRT, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABRT)");
+#endif
+#ifdef SIGILL
+    if (sigaction(SIGILL, &sa, NULL) < 0)
+        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)");
+#endif
+
+#else /* NO_USE_SIGACTION */
+    
+    apr_signal(SIGSEGV, sig_coredump);
+#ifdef SIGBUS
+    apr_signal(SIGBUS, sig_coredump);
+#endif /* SIGBUS */
+#ifdef SIGABORT
+    apr_signal(SIGABORT, sig_coredump);
+#endif /* SIGABORT */
+#ifdef SIGABRT
+    apr_signal(SIGABRT, sig_coredump);
+#endif /* SIGABRT */
+#ifdef SIGILL
+    apr_signal(SIGILL, sig_coredump);
+#endif /* SIGILL */
+
+#endif /* NO_USE_SIGACTION */
+
+    pconf = in_pconf;
+    parent_pid = my_pid = getpid();
+
+    return APR_SUCCESS;
+}
+
+#endif /* AP_MPM_WANT_FATAL_SIGNAL_HANDLER */