From: Yann Ylavic Date: Thu, 14 Apr 2022 14:38:03 +0000 (+0000) Subject: mpm_event: Handle children killed pathologically. X-Git-Tag: 2.5.0-alpha2-ci-test-only~393 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33e7deed8d0418458cf229cf3b82d60acde96654;p=thirdparty%2Fapache%2Fhttpd.git mpm_event: Handle children killed pathologically. If children processes get killed (SIGSEGV/SIGABRT/..) early after starting or frequently enough then we never enter perform_idle_server_maintenance() to try something. Below three successive children killed restart them immediately, above three let's sleep the usual 1s (to avoid fork()s flood) and do the idle maintenance. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1899858 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 595fac0b0f1..b4361cc8988 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -3382,6 +3382,7 @@ static void server_main_loop(int remaining_children_to_start) { int num_buckets = retained->mpm->num_buckets; int max_daemon_used = 0; + int successive_signals = 0; int child_slot; apr_exit_why_e exitwhy; int status, processed_status; @@ -3460,11 +3461,31 @@ static void server_main_loop(int remaining_children_to_start) /* Don't perform idle maintenance when a child dies, * only do it when there's a timeout. Remember only a * finite number of children can die, and it's pretty - * pathological for a lot to die suddenly. + * pathological for a lot to die suddenly. If that happens + * anyway, protect against fork()+kill() flood by not restarting + * more than 3 children if no timeout happened in between, + * otherwise we keep going with idle maintenance. */ - continue; + if (child_slot < 0 || !APR_PROC_CHECK_SIGNALED(exitwhy)) { + continue; + } + if (++successive_signals >= 3) { + if (successive_signals % 10 == 3) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + ap_server_conf, APLOGNO(10392) + "children are killed successively!"); + } + apr_sleep(apr_time_from_sec(1)); + } + else { + ++remaining_children_to_start; + } } - else if (remaining_children_to_start) { + else { + successive_signals = 0; + } + + if (remaining_children_to_start) { /* we hit a 1 second timeout in which none of the previous * generation of children needed to be reaped... so assume * they're all done, and pick up the slack if any is left.