mod_whatkilledus.c is a pretty trim module, with no current ability to deal with multi-threaded MPMs, but with relatively little code it puts the hook to good use in order to log a synopsis of what was going on at the time of the fatal exception.
Here is an example of information written by mod_whatkilledus, followed by the real trace message written by the parent when it realizes that a child has died:
Fatal signal 11 received in pid 6518:
Active request: GET /silly?fn=govrr
Client IP: 127.0.0.1
Local port: 8080
Connection aborted? no
[Wed Feb 19 13:56:04 2003] [notice] child pid 6518 exit signal Segmentation fault (11), possible coredump in /home/trawick/apacheinst
Some of the obvious things to consider:
have common sig_coredump for Unix
let sig_coredump receive siginfo_t on platforms that support that flavor, and store it in ap_exception_info_t
recognize a recursive call to sig_coredump and don't call the hook since presumably a hook has itself segfaulted
have a way for module to know that the hook is available (I have no
plans to implement exception handlers and related hook on Win32 :) )
get some feeling that Win32 or other non-Unix platforms could represent relevant info in ap_exception_info_t
Thoughts/concerns?
Index: include/ap_mpm.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/ap_mpm.h,v retrieving revision 1.34 diff -u -r1.34 ap_mpm.h --- include/ap_mpm.h 3 Feb 2003 17:52:53 -0000 1.34 +++ include/ap_mpm.h 19 Feb 2003 18:46:54 -0000 @@ -197,4 +197,10 @@ #define AP_MONCONTROL(x) #endif +typedef struct ap_exception_info_tag { + int sig; +} ap_exception_info_t; + +AP_DECLARE_HOOK(int,fatal_exception_received,(ap_exception_info_t *ei)) + #endif Index: server/mpm/prefork/prefork.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v retrieving revision 1.273 diff -u -r1.273 prefork.c --- server/mpm/prefork/prefork.c 3 Feb 2003 17:53:24 -0000 1.273 +++ server/mpm/prefork/prefork.c 19 Feb 2003 18:46:55 -0000 @@ -353,9 +353,26 @@ } #endif +APR_HOOK_STRUCT( + APR_HOOK_LINK(fatal_exception_received) +) + +AP_IMPLEMENT_HOOK_RUN_ALL(int,fatal_exception_received, + (ap_exception_info_t *ei), (ei), OK, DECLINED) + +static int prefork_fatal_exception_received(ap_exception_info_t *ei) +{ + /* maybe prefork needs to do something to release any mutex it could be holding? +*/ + return 0; +} + /* handle all varieties of core dumping signals */ static void sig_coredump(int sig) { + ap_exception_info_t ei = {0}; + + ei.sig = sig; + ap_run_fatal_exception_received(&ei); chdir(ap_coredump_dir); apr_signal(sig, SIG_DFL); if (ap_my_pid == parent_pid) { @@ -1285,6 +1302,7 @@ ap_hook_open_logs(prefork_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_fatal_exception_received(prefork_fatal_exception_received, NULL, NULL, +APR_HOOK_MIDDLE); } static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
#include <unistd.h>
#include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "http_connection.h" #include "http_log.h" #include "ap_mpm.h" #include "apr_strings.h" #include "apr_network_io.h" module AP_MODULE_DECLARE_DATA whatkilledus_module; typedef struct wku_req_info_tag { struct wku_req_info_tag *next; request_rec *r; } wku_req_info_t; typedef struct wku_conn_info_tag { int active; apr_pool_t *p; conn_rec *c; wku_req_info_t *reqs; } wku_conn_info_t; static wku_conn_info_t staticci; static wku_req_info_t *get_new_ri(wku_conn_info_t *ci) { wku_req_info_t *new = malloc(sizeof(*new)); memset(new, 0, sizeof(*new)); new->next = ci->reqs; ci->reqs = new; return new; } static wku_conn_info_t *get_new_ci(conn_rec *c) { /* non-threaded MPM only :) */ ap_assert(staticci.active == 0); memset(&staticci, 0, sizeof(staticci)); staticci.active = 1; return &staticci; } static wku_conn_info_t *get_cur_ci(conn_rec *c) { /* non-threaded MPM only :) */ return &staticci; } static void free_ci(wku_conn_info_t *ci) { /* todo: free any chained requests! */ ci->active = 0; } static int wku_fatal_exception_received(ap_exception_info_t *ei) { int sig = ei->sig; wku_conn_info_t *curconn; wku_req_info_t *curreq; char buf[4096]; curconn = get_cur_ci(NULL); /* no conn_rec avail */ if (!curconn) { const char *msg = "no active connection at time of fatal exception\n"; write(2, msg, strlen(msg)); return 0; } curreq = curconn->reqs; /* head of list */ apr_snprintf(buf, sizeof(buf), "Fatal signal %d received in pid %ld:\n" "Active request: %s\n" "Client IP: %s\n" "Local port: %d\n" "Connection aborted? %s\n" "", sig, (long)getpid(), curreq ? curreq->r->the_request : "no active request", curconn->c->remote_ip, (int)curconn->c->local_addr->port, curconn->c->aborted ? "yes" : "no" ); write(2, buf, strlen(buf)); return 0; } static apr_status_t wku_connection_end(void *void_ci) { wku_conn_info_t *ci = void_ci; free_ci(ci); return APR_SUCCESS; } static int wku_pre_connection(conn_rec *c, void *vcsd) { wku_conn_info_t *new; new = get_new_ci(c); new->c = c; new->p = c->pool; apr_pool_cleanup_register(c->pool, new, wku_connection_end, NULL); return DECLINED; } static int wku_post_read_request(request_rec *r) { wku_conn_info_t *cur; wku_req_info_t *new; cur = get_cur_ci(r->connection); new = get_new_ri(cur); new->r = r; return DECLINED; } static void wku_error_log(const char *file, int line, int level, apr_status_t status, const server_rec *s, const request_rec *r, apr_pool_t *pool, const char *errstr) { } static void wku_register_hooks(apr_pool_t *p) { ap_hook_pre_connection(wku_pre_connection, NULL, NULL, APR_HOOK_LAST); ap_hook_post_read_request(wku_post_read_request, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_error_log(wku_error_log, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_fatal_exception_received(wku_fatal_exception_received, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA whatkilledus_module = { STANDARD20_MODULE_STUFF, NULL, NULL, NULL, NULL, NULL, wku_register_hooks };