--- os/unix/unixd.c (revision 1809975) +++ os/unix/unixd.c (working copy) @@ -437,11 +437,19 @@ AP_DECLARE(apr_status_t) ap_unixd_accept(void **ac /* Unixes MPMs' */ static ap_unixd_mpm_retained_data *retained_data = NULL; +static apr_status_t retained_data_cleanup(void *unused) +{ + (void)unused; + retained_data = NULL; + return APR_SUCCESS; +} + AP_DECLARE(ap_unixd_mpm_retained_data *) ap_unixd_mpm_get_retained_data() { if (!retained_data) { retained_data = ap_retained_data_create("ap_unixd_mpm_retained_data", sizeof(*retained_data)); + apr_pool_pre_cleanup_register(ap_pglobal, NULL, retained_data_cleanup); retained_data->mpm_state = AP_MPMQ_STARTING; } return retained_data; @@ -449,6 +457,10 @@ AP_DECLARE(ap_unixd_mpm_retained_data *) ap_unixd_ static void sig_term(int sig) { + if (!retained_data) { + /* Main process (ap_pglobal) is dying */ + return; + } retained_data->mpm_state = AP_MPMQ_STOPPING; if (retained_data->shutdown_pending && (retained_data->is_ungraceful @@ -465,6 +477,10 @@ static void sig_term(int sig) static void sig_restart(int sig) { + if (!retained_data) { + /* Main process (ap_pglobal) is dying */ + return; + } retained_data->mpm_state = AP_MPMQ_STOPPING; if (retained_data->restart_pending && (retained_data->is_ungraceful @@ -481,6 +497,10 @@ static void sig_restart(int sig) static apr_status_t unset_signals(void *unused) { + if (!retained_data) { + /* Main process (ap_pglobal) is dying */ + return APR_SUCCESS; + } retained_data->shutdown_pending = retained_data->restart_pending = 0; retained_data->was_graceful = !retained_data->is_ungraceful; retained_data->is_ungraceful = 0; @@ -494,6 +514,10 @@ AP_DECLARE(void) ap_unixd_mpm_set_signals(apr_pool struct sigaction sa; #endif + if (!one_process) { + ap_fatal_signal_setup(ap_server_conf, pconf); + } + /* Signals' handlers depend on retained data */ (void)ap_unixd_mpm_get_retained_data(); --- server/main.c (revision 1809975) +++ server/main.c (working copy) @@ -273,6 +273,30 @@ static int abort_on_oom(int retcode) return retcode; /* unreachable, hopefully. */ } +/* Deregister all hooks when clearing pconf (pre_cleanup). + * TODO: have a hook to deregister and run them from here? + * ap_clear_auth_internal() is already a candidate. + */ +static apr_status_t deregister_all_hooks(void *unused) +{ + (void)unused; + ap_clear_auth_internal(); + apr_hook_deregister_all(); + return APR_SUCCESS; +} + +static void reset_process_pconf(process_rec *process) +{ + if (process->pconf) { + apr_pool_clear(process->pconf); + } + else { + apr_pool_create(&process->pconf, process->pool); + apr_pool_tag(process->pconf, "pconf"); + } + apr_pool_pre_cleanup_register(process->pconf, NULL, deregister_all_hooks); +} + static process_rec *init_process(int *argc, const char * const * *argv) { process_rec *process; @@ -317,8 +341,9 @@ static process_rec *init_process(int *argc, const process = apr_palloc(cntx, sizeof(process_rec)); process->pool = cntx; - apr_pool_create(&process->pconf, process->pool); - apr_pool_tag(process->pconf, "pconf"); + process->pconf = NULL; + reset_process_pconf(process); + process->argc = *argc; process->argv = *argv; process->short_name = apr_filepath_name_get((*argv)[0]); @@ -721,9 +746,7 @@ int main(int argc, const char * const argv[]) do { ap_main_state = AP_SQ_MS_DESTROY_CONFIG; - apr_hook_deregister_all(); - apr_pool_clear(pconf); - ap_clear_auth_internal(); + reset_process_pconf(process); ap_main_state = AP_SQ_MS_CREATE_CONFIG; ap_config_generation++; --- server/mpm/event/event.c (revision 1809975) +++ server/mpm/event/event.c (working copy) @@ -2880,9 +2880,6 @@ static int event_run(apr_pool_t * _pconf, apr_pool ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; } - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } ap_unixd_mpm_set_signals(pconf, one_process); /* Don't thrash since num_buckets depends on the --- server/mpm/prefork/prefork.c (revision 1809975) +++ server/mpm/prefork/prefork.c (working copy) @@ -863,9 +863,6 @@ static int prefork_run(apr_pool_t *_pconf, apr_poo ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; } - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } ap_unixd_mpm_set_signals(pconf, one_process); if (one_process) { --- server/mpm/worker/worker.c (revision 1809975) +++ server/mpm/worker/worker.c (working copy) @@ -1671,9 +1671,6 @@ static int worker_run(apr_pool_t *_pconf, apr_pool ap_scoreboard_image->global->running_generation = retained->mpm->my_generation; } - if (!one_process) { - ap_fatal_signal_setup(ap_server_conf, pconf); - } ap_unixd_mpm_set_signals(pconf, one_process); /* Don't thrash since num_buckets depends on the --- server/mpm_unix.c (revision 1809975) +++ server/mpm_unix.c (working copy) @@ -1009,6 +1009,33 @@ AP_DECLARE(apr_status_t) ap_fatal_signal_child_set return APR_SUCCESS; } +/* We can't call sig_coredump (ap_log_error) once pconf is destroyed, so + * avoid double faults by restoring each default signal handler on cleanup. + */ +static apr_status_t fatal_signal_cleanup(void *unused) +{ + (void)unused; + + apr_signal(SIGSEGV, SIG_DFL); +#ifdef SIGBUS + apr_signal(SIGBUS, SIG_DFL); +#endif /* SIGBUS */ +#ifdef SIGABORT + apr_signal(SIGABORT, SIG_DFL); +#endif /* SIGABORT */ +#ifdef SIGABRT + apr_signal(SIGABRT, SIG_DFL); +#endif /* SIGABRT */ +#ifdef SIGILL + apr_signal(SIGILL, SIG_DFL); +#endif /* SIGILL */ +#ifdef SIGFPE + apr_signal(SIGFPE, SIG_DFL); +#endif /* SIGFPE */ + + return APR_SUCCESS; +} + AP_DECLARE(apr_status_t) ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) { @@ -1071,6 +1098,8 @@ AP_DECLARE(apr_status_t) ap_fatal_signal_setup(ser pconf = in_pconf; parent_pid = my_pid = getpid(); + apr_pool_cleanup_register(pconf, NULL, fatal_signal_cleanup, + fatal_signal_cleanup); return APR_SUCCESS; }