From 545d49b0371722c44696db307eca94237f32ab89 Mon Sep 17 00:00:00 2001 From: t4r3k <142579274+machine-moon@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:46:12 -0400 Subject: [PATCH 1/7] mpm_event update --- include/mpm_common.h | 15 +++++++++++++++ server/mpm/event/event.c | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/mpm_common.h b/include/mpm_common.h index f60c473d537..c60cce1fbf8 100644 --- a/include/mpm_common.h +++ b/include/mpm_common.h @@ -40,6 +40,7 @@ #include "ap_config.h" #include "ap_mpm.h" #include "scoreboard.h" +#include "apr_optional.h" #if APR_HAVE_NETINET_TCP_H #include /* for TCP_NODELAY */ @@ -560,6 +561,20 @@ AP_DECLARE_HOOK(void, child_stopped, */ void mpm_common_pre_config(apr_pool_t *pconf); +/** + * Hooks for modules to report connections the MPM did not accept itself. + * + * MPMs that wait for their connection count to drain before stopping a child + * need this so externally accepted connections keep the child alive until + * they finish. + * + * Call ap_mpm_note_extra_connection_added() when such a connection starts, + * and ap_mpm_note_extra_connection_removed() when it ends. These functions + * may be NULL if the active MPM does not implement them. + */ +APR_DECLARE_OPTIONAL_FN(void, ap_mpm_note_extra_connection_added, (void)); +APR_DECLARE_OPTIONAL_FN(void, ap_mpm_note_extra_connection_removed, (void)); + #ifdef __cplusplus } #endif diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 385532d03b4..eac7f70f8e6 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -871,6 +871,21 @@ static apr_status_t decrement_connection_count(void *cs_) return APR_SUCCESS; } +static void ap_mpm_note_extra_connection_added(void) +{ + apr_atomic_inc32(&connection_count); +} + +static void ap_mpm_note_extra_connection_removed(void) +{ + int is_last_connection = !apr_atomic_dec32(&connection_count); + + /* Wake a listener blocked waiting for connection_count to drain. */ + if (listener_is_wakeable && is_last_connection && listener_may_exit) { + apr_pollset_wakeup(event_pollset); + } +} + static void notify_suspend(event_conn_state_t *cs) { ap_run_suspend_connection(cs->c, cs->r); @@ -3876,6 +3891,10 @@ static void setup_slave_conn(conn_rec *c, void *csd) event_conn_state_t *cs; mcs = ap_get_module_config(c->master->conn_config, &mpm_event_module); + if (!mcs) { + /* Master connection is not managed by this MPM; nothing to inherit. */ + return; + } cs = apr_pcalloc(c->pool, sizeof(*cs)); cs->c = c; @@ -3954,6 +3973,9 @@ static int event_pre_config(apr_pool_t * pconf, apr_pool_t * plog, const char *userdata_key = "mpm_event_module"; int test_atomics = 0; + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_added); + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_removed); + debug = ap_exists_config_define("DEBUG"); if (debug) { From fd5171806fa1b52eb1404d572cadf1953928c702 Mon Sep 17 00:00:00 2001 From: Tarek Ibrahim Date: Wed, 15 Jul 2026 14:12:56 -0400 Subject: [PATCH 2/7] mpm prefork and worker update --- server/mpm/prefork/prefork.c | 20 ++++++++++++++++++++ server/mpm/worker/worker.c | 21 +++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 3de062f367a..8e2dc024ba3 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -18,6 +18,7 @@ #include "apr_portable.h" #include "apr_strings.h" #include "apr_thread_proc.h" +#include "apr_atomic.h" #include "apr_signal.h" #define APR_WANT_STDIO @@ -89,6 +90,7 @@ /* config globals */ +static apr_uint32_t connection_count = 0; /* Number of open connections */ static int ap_daemons_to_start=0; static int ap_daemons_min_free=0; static int ap_daemons_max_free=0; @@ -229,6 +231,11 @@ static void clean_child_exit_ex(int code, int from_signal) if (pchild) { if (!code && !from_signal) { ap_run_child_stopping(pchild, !retained->mpm->is_ungraceful); + if (!retained->mpm->is_ungraceful) { + while (apr_atomic_read32(&connection_count) > 0) { + apr_sleep(apr_time_from_msec(100)); + } + } ap_run_child_stopped(pchild, !retained->mpm->is_ungraceful); } apr_pool_destroy(pchild); @@ -380,6 +387,16 @@ static void just_die(int sig) /* volatile because it's updated from a signal handler */ static int volatile die_now = 0; +static void ap_mpm_note_extra_connection_added(void) +{ + apr_atomic_inc32(&connection_count); +} + +static void ap_mpm_note_extra_connection_removed(void) +{ + apr_atomic_dec32(&connection_count); +} + static void stop_listening(int sig) { retained->mpm->mpm_state = AP_MPMQ_STOPPING; @@ -1321,6 +1338,9 @@ static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp apr_status_t rv; const char *userdata_key = "mpm_prefork_module"; + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_added); + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_removed); + debug = ap_exists_config_define("DEBUG"); if (debug) { diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 42b81a8ed1b..89f091a4ba8 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -30,6 +30,7 @@ #include "apr_thread_mutex.h" #include "apr_proc_mutex.h" #include "apr_poll.h" +#include "apr_atomic.h" #include @@ -117,6 +118,7 @@ * Actual definitions of config globals */ +static apr_uint32_t connection_count = 0; /* Number of open connections */ static int threads_per_child = 0; /* Worker threads per child */ static int ap_daemons_to_start = 0; static int min_spare_threads = 0; @@ -511,6 +513,16 @@ static void check_infinite_requests(void) } } +static void ap_mpm_note_extra_connection_added(void) +{ + apr_atomic_inc32(&connection_count); +} + +static void ap_mpm_note_extra_connection_removed(void) +{ + apr_atomic_dec32(&connection_count); +} + static void unblock_signal(int sig) { sigset_t sig_mask; @@ -1328,6 +1340,12 @@ static void child_main(int child_num_arg, int child_bucket) rv == AP_MPM_PODX_GRACEFUL ? ST_GRACEFUL : ST_UNGRACEFUL); } + if (terminate_mode == ST_GRACEFUL) { + while (apr_atomic_read32(&connection_count) > 0) { + apr_sleep(apr_time_from_msec(100)); + } + } + free(threads); clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0); @@ -2103,6 +2121,9 @@ static int worker_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_status_t rv; const char *userdata_key = "mpm_worker_module"; + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_added); + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_removed); + debug = ap_exists_config_define("DEBUG"); if (debug) { From e473a8647a45a6e4a09ba7a7b98606ce5e3b8db3 Mon Sep 17 00:00:00 2001 From: Tarek Ibrahim Date: Sun, 9 Aug 2026 03:38:13 -0400 Subject: [PATCH 3/7] mpm_winnt update --- server/mpm/winnt/child.c | 18 ++++++++++++++++++ server/mpm/winnt/mpm_winnt.c | 3 +++ server/mpm/winnt/mpm_winnt.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index 1ad8df0374b..e9157e3ec0b 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -131,9 +131,21 @@ static apr_thread_mutex_t *ctxpool_lock; static winnt_conn_ctx_t *ctxpool_head = NULL; static apr_uint32_t num_completion_contexts = 0; static apr_uint32_t max_num_completion_contexts = 0; +static apr_uint32_t extra_connection_count = 0; static HANDLE ThreadDispatchIOCP = NULL; static HANDLE ctxpool_wait_event = NULL; +/* Connections a module accepted itself, which the worker threads do not serve. */ +void ap_mpm_note_extra_connection_added(void) +{ + apr_atomic_inc32(&extra_connection_count); +} + +void ap_mpm_note_extra_connection_removed(void) +{ + apr_atomic_dec32(&extra_connection_count); +} + static void mpm_recycle_completion_context(winnt_conn_ctx_t *context) { /* Recycle the completion context. @@ -1237,6 +1249,12 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) } } + /* Drain externally accepted connections within what is left of the deadline. */ + while (apr_atomic_read32(&extra_connection_count) > 0 && time_remains >= 0) { + Sleep(100); + time_remains -= 100; + } + if (threads_created) { ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00363) "Child: Waiting for %d threads timed out, terminating process.", diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index cbc090fb662..818eb276187 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -1368,6 +1368,9 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt * -k runservice [WinNT errors logged from rewrite_args] */ + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_added); + APR_REGISTER_OPTIONAL_FN(ap_mpm_note_extra_connection_removed); + /* Initialize shared static objects. * TODO: Put config related statics into an sconf structure. */ diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h index 7d71a28837e..e9398e48dd2 100644 --- a/server/mpm/winnt/mpm_winnt.h +++ b/server/mpm/winnt/mpm_winnt.h @@ -93,6 +93,8 @@ void hold_console_open_on_error(void); /* From child.c: */ void child_main(apr_pool_t *pconf, DWORD parent_pid); +void ap_mpm_note_extra_connection_added(void); +void ap_mpm_note_extra_connection_removed(void); #endif /* APACHE_MPM_WINNT_H */ /** @} */ From 61ac0b778390188582ee339c3d68c3d9a5b121a1 Mon Sep 17 00:00:00 2001 From: t4r3k <142579274+machine-moon@users.noreply.github.com> Date: Mon, 10 Aug 2026 12:34:38 -0400 Subject: [PATCH 4/7] update CHANGES --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 2344887d8c8..6c1bb2bb2c8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) mpm_event, mpm_worker, mpm_winnt, mpm_prefork: Add optional hooks to + account for connections managed outside the MPM accept loop (e.g., UDP). + [Tarek Ibrahim ] + * mod_ssl: Add support for OpenSSL provider based certificate stores. [Graham Leggett] From 4beed2d9cee1b5d4c61deaf3bfa2d76891193eac Mon Sep 17 00:00:00 2001 From: Tarek Ibrahim Date: Fri, 14 Aug 2026 11:22:23 -0400 Subject: [PATCH 5/7] bump mmn --- include/ap_mmn.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/ap_mmn.h b/include/ap_mmn.h index ccd504d8e82..0f3fa966f80 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -737,6 +737,7 @@ * 20211221.29 (2.5.1-dev) Add ap_set_time_process_request() to scoreboard.h * 20211221.30 (2.5.1-dev) Add ap_stat_check() to httpd.h * 20211221.31 (2.5.1-dev) Add ap_*_timingsafe() to httpd.h + * 20211221.32 (2.5.1-dev) Add optional hooks for MPM to accept UDP conns. */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -744,7 +745,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20211221 #endif -#define MODULE_MAGIC_NUMBER_MINOR 31 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 32 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a From fbc56bf3269a36df67baa1f115ee843071f522b3 Mon Sep 17 00:00:00 2001 From: Tarek Ibrahim Date: Sat, 15 Aug 2026 06:53:10 -0400 Subject: [PATCH 6/7] bounded graceful shutdown for extra connections --- docs/log-message-tags/next-number | 2 +- server/mpm/event/event.c | 38 +++++++++++++++++++++++++---- server/mpm/prefork/prefork.c | 32 ++++++++++++++++++++++--- server/mpm/winnt/child.c | 40 ++++++++++++++++++++++++++----- server/mpm/worker/worker.c | 32 ++++++++++++++++++++++--- 5 files changed, 126 insertions(+), 18 deletions(-) diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index 6c6f5d54af5..29cdba2b98b 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10619 +10623 diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index eac7f70f8e6..0eff784fdda 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -188,6 +188,7 @@ static int num_listensocks = 0; static apr_int32_t conns_this_child; /* MaxConnectionsPerChild, only access in listener thread */ static apr_uint32_t connection_count = 0; /* Number of open connections */ +static apr_uint32_t extra_connection_count = 0; /* Number of open connections that the MPM does not own */ static apr_uint32_t lingering_count = 0; /* Number of connections in lingering close */ static apr_uint32_t suspended_count = 0; /* Number of suspended connections */ static apr_uint32_t clogged_count = 0; /* Number of threads processing ssl conns */ @@ -873,16 +874,39 @@ static apr_status_t decrement_connection_count(void *cs_) static void ap_mpm_note_extra_connection_added(void) { - apr_atomic_inc32(&connection_count); + apr_atomic_inc32(&extra_connection_count); } static void ap_mpm_note_extra_connection_removed(void) { - int is_last_connection = !apr_atomic_dec32(&connection_count); + apr_atomic_dec32(&extra_connection_count); +} - /* Wake a listener blocked waiting for connection_count to drain. */ - if (listener_is_wakeable && is_last_connection && listener_may_exit) { - apr_pollset_wakeup(event_pollset); +static void wait_for_extra_connections(void) +{ + apr_uint32_t count = apr_atomic_read32(&extra_connection_count); + apr_time_t graceful, timeout, deadline; + + if (count == 0) { + return; + } + + graceful = apr_time_from_sec(ap_graceful_shutdown_timeout); + timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout; + deadline = apr_time_now() + timeout; + + do { + apr_sleep(apr_time_from_msec(100)); + count = apr_atomic_read32(&extra_connection_count); + } while (count > 0 && apr_time_now() < deadline); + + if (count > 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, + APLOGNO(10619) + "Child: %u connection(s) noted by modules did not " + "finish within %" APR_TIME_T_FMT " seconds, " + "exiting anyway", + count, apr_time_sec(timeout)); } } @@ -3154,6 +3178,10 @@ static void child_main(int child_num_arg, int child_bucket) rv == AP_MPM_PODX_GRACEFUL ? "graceful" : "ungraceful"); } + if (terminate_mode == ST_GRACEFUL) { + wait_for_extra_connections(); + } + free(threads); clean_child_exit(resource_shortage ? APEXIT_CHILDSICK : 0); diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 8e2dc024ba3..68a3f9f66fe 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -219,6 +219,34 @@ static void prefork_note_child_started(int slot, pid_t pid) ap_run_child_status(ap_server_conf, pid, gen, slot, MPM_CHILD_STARTED); } +static void wait_for_extra_connections(void) +{ + apr_uint32_t count = apr_atomic_read32(&connection_count); + apr_time_t graceful, timeout, deadline; + + if (count == 0) { + return; + } + + graceful = apr_time_from_sec(ap_graceful_shutdown_timeout); + timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout; + deadline = apr_time_now() + timeout; + + do { + apr_sleep(apr_time_from_msec(100)); + count = apr_atomic_read32(&connection_count); + } while (count > 0 && apr_time_now() < deadline); + + if (count > 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, + APLOGNO(10620) + "Child: %u connection(s) noted by modules did not " + "finish within %" APR_TIME_T_FMT " seconds, " + "exiting anyway", + count, apr_time_sec(timeout)); + } +} + /* a clean exit from a child with proper cleanup */ static void clean_child_exit_ex(int code, int from_signal) __attribute__ ((noreturn)); static void clean_child_exit_ex(int code, int from_signal) @@ -232,9 +260,7 @@ static void clean_child_exit_ex(int code, int from_signal) if (!code && !from_signal) { ap_run_child_stopping(pchild, !retained->mpm->is_ungraceful); if (!retained->mpm->is_ungraceful) { - while (apr_atomic_read32(&connection_count) > 0) { - apr_sleep(apr_time_from_msec(100)); - } + wait_for_extra_connections(); } ap_run_child_stopped(pchild, !retained->mpm->is_ungraceful); } diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index e9157e3ec0b..b5461cc4c19 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -146,6 +146,36 @@ void ap_mpm_note_extra_connection_removed(void) apr_atomic_dec32(&extra_connection_count); } +static void wait_for_extra_connections(void) +{ + apr_uint32_t count = apr_atomic_read32(&extra_connection_count); + apr_time_t graceful, timeout; + int time_remains; + + if (count == 0) { + return; + } + + graceful = apr_time_from_sec(ap_graceful_shutdown_timeout); + timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout; + time_remains = (int)(timeout / APR_TIME_C(1000)); + + do { + Sleep(100); + time_remains -= 100; + count = apr_atomic_read32(&extra_connection_count); + } while (count > 0 && time_remains > 0); + + if (count > 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ap_server_conf, + APLOGNO(10622) + "Child: %u connection(s) noted by modules did not " + "finish within %" APR_TIME_T_FMT " seconds, " + "exiting anyway", + count, apr_time_sec(timeout)); + } +} + static void mpm_recycle_completion_context(winnt_conn_ctx_t *context) { /* Recycle the completion context. @@ -1249,12 +1279,6 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) } } - /* Drain externally accepted connections within what is left of the deadline. */ - while (apr_atomic_read32(&extra_connection_count) > 0 && time_remains >= 0) { - Sleep(100); - time_remains -= 100; - } - if (threads_created) { ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00363) "Child: Waiting for %d threads timed out, terminating process.", @@ -1280,6 +1304,10 @@ void child_main(apr_pool_t *pconf, DWORD parent_pid) ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf, APLOGNO(00364) "Child: All worker threads have exited."); + if (graceful_shutdown) { + wait_for_extra_connections(); + } + ap_run_child_stopped(pchild, graceful_shutdown); apr_thread_mutex_destroy(child_lock); diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index 89f091a4ba8..d96fb6d384c 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -523,6 +523,34 @@ static void ap_mpm_note_extra_connection_removed(void) apr_atomic_dec32(&connection_count); } +static void wait_for_extra_connections(void) +{ + apr_uint32_t count = apr_atomic_read32(&connection_count); + apr_time_t graceful, timeout, deadline; + + if (count == 0) { + return; + } + + graceful = apr_time_from_sec(ap_graceful_shutdown_timeout); + timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout; + deadline = apr_time_now() + timeout; + + do { + apr_sleep(apr_time_from_msec(100)); + count = apr_atomic_read32(&connection_count); + } while (count > 0 && apr_time_now() < deadline); + + if (count > 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, + APLOGNO(10621) + "Child: %u connection(s) noted by modules did not " + "finish within %" APR_TIME_T_FMT " seconds, " + "exiting anyway", + count, apr_time_sec(timeout)); + } +} + static void unblock_signal(int sig) { sigset_t sig_mask; @@ -1341,9 +1369,7 @@ static void child_main(int child_num_arg, int child_bucket) } if (terminate_mode == ST_GRACEFUL) { - while (apr_atomic_read32(&connection_count) > 0) { - apr_sleep(apr_time_from_msec(100)); - } + wait_for_extra_connections(); } free(threads); From 8d6202e641ab19f948349b12542d04d250f2b215 Mon Sep 17 00:00:00 2001 From: Tarek Ibrahim Date: Sat, 15 Aug 2026 07:00:04 -0400 Subject: [PATCH 7/7] consistency sweep --- CHANGES | 8 ++++++-- include/ap_mmn.h | 4 +++- include/mpm_common.h | 6 ++++++ server/mpm/prefork/prefork.c | 26 +++++++++++++------------- server/mpm/winnt/child.c | 8 +++----- server/mpm/worker/worker.c | 10 +++++----- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index 6c1bb2bb2c8..0828db3fde0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,12 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 - *) mpm_event, mpm_worker, mpm_winnt, mpm_prefork: Add optional hooks to - account for connections managed outside the MPM accept loop (e.g., UDP). + *) mpm_event, mpm_worker, mpm_winnt, mpm_prefork: Add the optional functions + ap_mpm_note_extra_connection_added() and + ap_mpm_note_extra_connection_removed() to account for connections managed + outside the MPM accept loop (e.g., UDP). On graceful stop a child waits + for those connections no longer than max(Timeout, + GracefulShutdownTimeout), then warns and exits. [Tarek Ibrahim ] * mod_ssl: Add support for OpenSSL provider based certificate diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 0f3fa966f80..3bc5f4de9fc 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -737,7 +737,9 @@ * 20211221.29 (2.5.1-dev) Add ap_set_time_process_request() to scoreboard.h * 20211221.30 (2.5.1-dev) Add ap_stat_check() to httpd.h * 20211221.31 (2.5.1-dev) Add ap_*_timingsafe() to httpd.h - * 20211221.32 (2.5.1-dev) Add optional hooks for MPM to accept UDP conns. + * 20211221.32 (2.5.1-dev) Add the optional functions ap_mpm_note_extra_ + * connection_added() and ap_mpm_note_extra_ + * connection_removed() to mpm_common.h */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ diff --git a/include/mpm_common.h b/include/mpm_common.h index c60cce1fbf8..cca0e74e72a 100644 --- a/include/mpm_common.h +++ b/include/mpm_common.h @@ -571,6 +571,12 @@ void mpm_common_pre_config(apr_pool_t *pconf); * Call ap_mpm_note_extra_connection_added() when such a connection starts, * and ap_mpm_note_extra_connection_removed() when it ends. These functions * may be NULL if the active MPM does not implement them. + * + * A module using them is expected to notice that the child is stopping (e.g. + * with the child_stopping hook) and to end the connections it noted in a + * timely manner, gracefully or not. The MPM waits for them no longer than + * max(Timeout, GracefulShutdownTimeout), then logs a warning and exits + * anyway, possibly cutting those connections short. */ APR_DECLARE_OPTIONAL_FN(void, ap_mpm_note_extra_connection_added, (void)); APR_DECLARE_OPTIONAL_FN(void, ap_mpm_note_extra_connection_removed, (void)); diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index 68a3f9f66fe..2a82e09507f 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -90,7 +90,7 @@ /* config globals */ -static apr_uint32_t connection_count = 0; /* Number of open connections */ +static apr_uint32_t extra_connection_count = 0; /* Number of open connections that the MPM does not own */ static int ap_daemons_to_start=0; static int ap_daemons_min_free=0; static int ap_daemons_max_free=0; @@ -219,9 +219,19 @@ static void prefork_note_child_started(int slot, pid_t pid) ap_run_child_status(ap_server_conf, pid, gen, slot, MPM_CHILD_STARTED); } +static void ap_mpm_note_extra_connection_added(void) +{ + apr_atomic_inc32(&extra_connection_count); +} + +static void ap_mpm_note_extra_connection_removed(void) +{ + apr_atomic_dec32(&extra_connection_count); +} + static void wait_for_extra_connections(void) { - apr_uint32_t count = apr_atomic_read32(&connection_count); + apr_uint32_t count = apr_atomic_read32(&extra_connection_count); apr_time_t graceful, timeout, deadline; if (count == 0) { @@ -234,7 +244,7 @@ static void wait_for_extra_connections(void) do { apr_sleep(apr_time_from_msec(100)); - count = apr_atomic_read32(&connection_count); + count = apr_atomic_read32(&extra_connection_count); } while (count > 0 && apr_time_now() < deadline); if (count > 0) { @@ -413,16 +423,6 @@ static void just_die(int sig) /* volatile because it's updated from a signal handler */ static int volatile die_now = 0; -static void ap_mpm_note_extra_connection_added(void) -{ - apr_atomic_inc32(&connection_count); -} - -static void ap_mpm_note_extra_connection_removed(void) -{ - apr_atomic_dec32(&connection_count); -} - static void stop_listening(int sig) { retained->mpm->mpm_state = AP_MPMQ_STOPPING; diff --git a/server/mpm/winnt/child.c b/server/mpm/winnt/child.c index b5461cc4c19..faf90da69b1 100644 --- a/server/mpm/winnt/child.c +++ b/server/mpm/winnt/child.c @@ -131,11 +131,10 @@ static apr_thread_mutex_t *ctxpool_lock; static winnt_conn_ctx_t *ctxpool_head = NULL; static apr_uint32_t num_completion_contexts = 0; static apr_uint32_t max_num_completion_contexts = 0; -static apr_uint32_t extra_connection_count = 0; +static apr_uint32_t extra_connection_count = 0; /* Number of open connections that the MPM does not own */ static HANDLE ThreadDispatchIOCP = NULL; static HANDLE ctxpool_wait_event = NULL; -/* Connections a module accepted itself, which the worker threads do not serve. */ void ap_mpm_note_extra_connection_added(void) { apr_atomic_inc32(&extra_connection_count); @@ -149,8 +148,7 @@ void ap_mpm_note_extra_connection_removed(void) static void wait_for_extra_connections(void) { apr_uint32_t count = apr_atomic_read32(&extra_connection_count); - apr_time_t graceful, timeout; - int time_remains; + apr_time_t graceful, timeout, time_remains; if (count == 0) { return; @@ -158,7 +156,7 @@ static void wait_for_extra_connections(void) graceful = apr_time_from_sec(ap_graceful_shutdown_timeout); timeout = (graceful > ap_server_conf->timeout) ? graceful : ap_server_conf->timeout; - time_remains = (int)(timeout / APR_TIME_C(1000)); + time_remains = timeout / APR_TIME_C(1000); do { Sleep(100); diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index d96fb6d384c..252f732645b 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -118,7 +118,7 @@ * Actual definitions of config globals */ -static apr_uint32_t connection_count = 0; /* Number of open connections */ +static apr_uint32_t extra_connection_count = 0; /* Number of open connections that the MPM does not own */ static int threads_per_child = 0; /* Worker threads per child */ static int ap_daemons_to_start = 0; static int min_spare_threads = 0; @@ -515,17 +515,17 @@ static void check_infinite_requests(void) static void ap_mpm_note_extra_connection_added(void) { - apr_atomic_inc32(&connection_count); + apr_atomic_inc32(&extra_connection_count); } static void ap_mpm_note_extra_connection_removed(void) { - apr_atomic_dec32(&connection_count); + apr_atomic_dec32(&extra_connection_count); } static void wait_for_extra_connections(void) { - apr_uint32_t count = apr_atomic_read32(&connection_count); + apr_uint32_t count = apr_atomic_read32(&extra_connection_count); apr_time_t graceful, timeout, deadline; if (count == 0) { @@ -538,7 +538,7 @@ static void wait_for_extra_connections(void) do { apr_sleep(apr_time_from_msec(100)); - count = apr_atomic_read32(&connection_count); + count = apr_atomic_read32(&extra_connection_count); } while (count > 0 && apr_time_now() < deadline); if (count > 0) {