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
};
