diff --git a/CHANGES b/CHANGES index 1b7ada49993..14b085ebe6d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,14 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) mpm_event: Add optional hooks for modules that manage connections + outside the MPM accept loop (UDP connections) can be accounted for. + [Tarek Ibrahim ] + + *) mpm_event: Avoid crashes in setup_slave_conn() when handling + connections not managed by the MPM. + [Tarek Ibrahim ] + *) mod_proxy_beacon: Back-end reverse proxy servers can announce themselves and be auto-added to their front-end proxy balancer. [Jim Jagielski] 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) { 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) {