From: Jeff Trawick Date: Mon, 18 Mar 2002 18:24:55 +0000 (+0000) Subject: Fix a hang condition with graceful restart and prefork MPM X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=364f44f0c9fea0b8d49a1591f0b83d6091a0288c;p=apache Fix a hang condition with graceful restart and prefork MPM in the situation where MaxClients is very high but much fewer servers are actually started at the time of the restart. The way we notify an entire generation to die at once is changed so that we don't have to use the pod (and deal with the ease of filling the kernel pipe buffer). git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@93999 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index f3d07bc23c..d48b4eb531 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ Changes with Apache 2.0.34-dev + *) Fix a hang condition with graceful restart and prefork MPM + in the situation where MaxClients is very high but + much fewer servers are actually started at the time of the + restart. [Jeff Trawick] + *) Small performance fixes for mod_include [Brian Pane] *) Performance improvement for the error logger [Brian Pane] diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 43121289b3..80c73de297 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -675,14 +675,19 @@ static void child_main(int child_num_arg) ap_lingering_close(current_conn); } - /* Check the pod after processing a connection so that we'll go away - * if a graceful restart occurred while we were processing the - * connection. Otherwise, we won't wake up until a real connection - * comes in and we'll use the wrong config to process it and we may - * block in the wrong syscall (because the new generation is using a - * different accept mutex) and in general it is goofy. + /* Check the pod and the generation number after processing a + * connection so that we'll go away if a graceful restart occurred + * while we were processing the connection or we are the lucky + * idle server process that gets to die. */ - if (!ap_mpm_pod_check(pod)) { + if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ + die_now = 1; + } + else if (ap_my_generation != + ap_scoreboard_image->global->running_generation) { /* restart? */ + /* yeah, this could be non-graceful restart, in which case the + * parent will kill us soon enough, but why bother checking? + */ die_now = 1; } ap_sync_scoreboard_image(); diff --git a/server/mpm_common.c b/server/mpm_common.c index 6e9f23a51d..66a1d25a0b 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -540,14 +540,21 @@ void ap_mpm_pod_killpg(ap_pod_t *pod, int num) int i; apr_status_t rv = APR_SUCCESS; + /* we don't write anything to the pod here... we assume + * that the would-be reader of the pod has another way to + * see that it is time to die once we wake it up + * + * writing lots of things to the pod at once is very + * problematic... we can fill the kernel pipe buffer and + * be blocked until somebody consumes some bytes or + * we hit a timeout... if we hit a timeout we can't just + * keep trying because maybe we'll never successfully + * write again... but then maybe we'll leave would-be + * readers stranded (a number of them could be tied up for + * a while serving time-consuming requests) + */ for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod); - } - - if (rv == APR_SUCCESS) { - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = dummy_connection(pod); - } + rv = dummy_connection(pod); } } #endif /* #ifdef AP_MPM_USES_POD */