From 5f33010a643ac7c67b7733484797d41366e328ecdb Mon Sep 17 00:00:00 2001 From: icing Date: Tue, 30 Aug 2022 14:47:19 +0800 Subject: [PATCH] Handle children killed pathologically Conflict:NA Reference:https://github.com/apache/httpd/commit/5f3010a643ac7c67b733484797d41366e328ecdb --- server/mpm/event/event.c | 26 +++++++++++++++++++++++--- server/mpm/worker/worker.c | 26 +++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index dddff35..5969c88 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -2983,6 +2983,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) static void server_main_loop(int remaining_children_to_start, int num_buckets) { + int successive_kills = 0; int child_slot; apr_exit_why_e exitwhy; int status, processed_status; @@ -3072,11 +3073,30 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) /* 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 a child is + * killed by a signal (faulting) we want to restart it ASAP + * though, up to 3 successive faults or we stop this until + * a timeout happens again (to avoid the flood of fork()ed + * process that keep being killed early). */ - continue; + if (child_slot < 0 || !APR_PROC_CHECK_SIGNALED(exitwhy)) { + continue; + } + if (++successive_kills >= 3) { + if (successive_kills % 10 == 3) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + ap_server_conf, APLOGNO(10392) + "children are killed successively!"); + } + continue; + } + ++remaining_children_to_start; + } + else { + successive_kills = 0; } - else if (remaining_children_to_start) { + + 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. diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index bd56f61..30d5aeb 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -1569,6 +1569,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) static void server_main_loop(int remaining_children_to_start, int num_buckets) { + int successive_kills = 0; ap_generation_t old_gen; int child_slot; apr_exit_why_e exitwhy; @@ -1663,11 +1664,30 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) /* 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 a child is + * killed by a signal (faulting) we want to restart if ASAP + * though, up to 3 successive faults or we stop this until + * a timeout happens again (to avoid the flood of fork()ed + * processes that keep being killed early). */ - continue; + if (child_slot < 0 || !APR_PROC_CHECK_SIGNALED(exitwhy)) { + continue; + } + if (++successive_kills >= 3) { + if (successive_kills % 10 == 3) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, + ap_server_conf, APLOGNO(10392) + "children are killed successively!"); + } + continue; + } + ++remaining_children_to_start; + } + else { + successive_kills = 0; } - else if (remaining_children_to_start) { + + 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. -- 2.23.0