From: Jeff Trawick Date: Sat, 30 Nov 2013 17:56:25 +0000 (+0000) Subject: Add suspend_connection and resume_connection hooks to notify modules X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1e0d2c7456b481af9da5e105d62d743c1a08fd16;p=thirdparty%2Fapache%2Fhttpd.git Add suspend_connection and resume_connection hooks to notify modules when the thread/connection relationship changes. (Currently implemented only for the Event MPM; should be implemented for all async MPMs.) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1546759 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 3fbc5aa7655..f41f6c43b92 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) Add suspend_connection and resume_connection hooks to notify modules + when the thread/connection relationship changes. (Currently implemented + only for the Event MPM; should be implemented for all async MPMs.) + [Jeff Trawick] + *) mod_ssl: Don't flush when an EOS is received. Prepares mod_ssl to support write completion. [Graham Leggett] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index b0ef6bf3615..f52604b6949 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -442,6 +442,7 @@ * 20130924.0 (2.5.0-dev) Add ap_errorlog_provider * 20130924.1 (2.5.0-dev) Add ap_proxy_connection_reusable() * 20131112.0 (2.5.0-dev) Add parse_errorlog_arg to ap_errorlog_provider + * 20131112.1 (2.5.0-dev) Add suspend_connection and resume_connection hooks */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -449,7 +450,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20131112 #endif -#define MODULE_MAGIC_NUMBER_MINOR 0 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/mpm_common.h b/include/mpm_common.h index 76bb59488d2..15dfc4602d2 100644 --- a/include/mpm_common.h +++ b/include/mpm_common.h @@ -419,6 +419,47 @@ AP_DECLARE_HOOK(apr_status_t, mpm_unregister_socket_callback, /* get MPM name (e.g., "prefork" or "event") */ AP_DECLARE_HOOK(const char *,mpm_get_name,(void)) +/** + * Notification that connection handling is suspending (disassociating from the + * current thread) + * @param c The current connection + * @param r The current request, or NULL if there is no active request + * @ingroup hooks + * @see ap_hook_resume_connection + * @note This hook is not implemented by MPMs like Prefork and Worker which + * handle all processing of a particular connection on the same thread. + * @note This hook will be called on the thread that was previously + * processing the connection. + * @note This hook is not called at the end of connection processing. This + * hook only notifies a module when processing of an active connection is + * suspended. + * @note Resumption and subsequent suspension of a connection solely to perform + * I/O by the MPM, with no execution of non-MPM code, may not necessarily result + * in a call to this hook. + */ +AP_DECLARE_HOOK(void, suspend_connection, + (conn_rec *c, request_rec *r)) + +/** + * Notification that connection handling is resuming (associating with a thread) + * @param c The current connection + * @param r The current request, or NULL if there is no active request + * @ingroup hooks + * @see ap_hook_suspend_connection + * @note This hook is not implemented by MPMs like Prefork and Worker which + * handle all processing of a particular connection on the same thread. + * @note This hook will be called on the thread that will resume processing + * the connection. + * @note This hook is not called at the beginning of connection processing. + * This hook only notifies a module when processing resumes for a + * previously-suspended connection. + * @note Resumption and subsequent suspension of a connection solely to perform + * I/O by the MPM, with no execution of non-MPM code, may not necessarily result + * in a call to this hook. + */ +AP_DECLARE_HOOK(void, resume_connection, + (conn_rec *c, request_rec *r)) + /* mutex type string for accept mutex, if any; MPMs should use the * same mutex type for ease of configuration */ diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index c1d78b46984..4fbbc429493 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -83,6 +83,7 @@ #include "http_config.h" /* for read_config */ #include "http_core.h" /* for get_remote_host */ #include "http_connection.h" +#include "http_protocol.h" #include "ap_mpm.h" #include "mpm_common.h" #include "ap_listen.h" @@ -190,6 +191,8 @@ static int mpm_state = AP_MPMQ_STARTING; static apr_thread_mutex_t *timeout_mutex; +module AP_MODULE_DECLARE_DATA mpm_event_module; + struct event_conn_state_t { /** APR_RING of expiration timeouts */ APR_RING_ENTRY(event_conn_state_t) timeout_list; @@ -197,6 +200,13 @@ struct event_conn_state_t { apr_time_t expiration_time; /** connection record this struct refers to */ conn_rec *c; + /** request record (if any) this struct refers to */ + request_rec *r; + /** is the current conn_rec suspended? (disassociated with + * a particular MPM thread; for suspend_/resume_connection + * hooks) + */ + int suspended; /** memory pool to allocate from */ apr_pool_t *p; /** bucket allocator */ @@ -905,6 +915,62 @@ static int stop_lingering_close(event_conn_state_t *cs) return 0; } +static void notify_suspend(event_conn_state_t *cs) +{ + static int how_many = 0; + + if (++how_many == 7) { + *(int *)0xcafebabe = 0; + } + ap_run_suspend_connection(cs->c, cs->r); + cs->suspended = 1; +} + +static void notify_resume(event_conn_state_t *cs) +{ + cs->suspended = 0; + ap_run_resume_connection(cs->c, cs->r); +} + +/* + * This runs before any non-MPM cleanup code on the connection; + * if the connection is currently suspended as far as modules + * know, provide notification of resumption. + */ +static apr_status_t ptrans_pre_cleanup(void *dummy) +{ + event_conn_state_t *cs = dummy; + + if (cs->suspended) { + notify_resume(cs); + } + return APR_SUCCESS; +} + +/* + * event_pre_read_request() and event_request_cleanup() track the + * current r for a given connection. + */ +static apr_status_t event_request_cleanup(void *dummy) +{ + conn_rec *c = dummy; + event_conn_state_t *cs = ap_get_module_config(c->conn_config, + &mpm_event_module); + + cs->r = NULL; + return APR_SUCCESS; +} + +static void event_pre_read_request(request_rec *r, conn_rec *c) +{ + event_conn_state_t *cs = ap_get_module_config(c->conn_config, + &mpm_event_module); + + cs->r = r; + apr_pool_cleanup_register(r->pool, c, event_request_cleanup, + apr_pool_cleanup_null); +} + /* * process one connection in the worker */ @@ -935,6 +1001,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc apr_atomic_inc32(&connection_count); apr_pool_cleanup_register(c->pool, cs, decrement_connection_count, apr_pool_cleanup_null); + ap_set_module_config(c->conn_config, &mpm_event_module, cs); c->current_thread = thd; cs->c = c; c->cs = &(cs->pub); @@ -945,6 +1012,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc pt->type = PT_CSD; pt->baton = cs; cs->pfd.client_data = pt; + apr_pool_pre_cleanup_register(p, cs, ptrans_pre_cleanup); TO_QUEUE_ELEM_INIT(cs); ap_update_vhost_given_ip(c); @@ -976,6 +1044,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc else { c = cs->c; c->sbh = sbh; + notify_resume(cs); c->current_thread = thd; } @@ -1029,6 +1098,7 @@ read_request: */ cs->expiration_time = ap_server_conf->timeout + apr_time_now(); c->sbh = NULL; + notify_suspend(cs); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); cs->pfd.reqevents = ( @@ -1055,6 +1125,7 @@ read_request: if (cs->pub.state == CONN_STATE_LINGER) { if (!start_lingering_close_blocking(cs)) { c->sbh = NULL; + notify_suspend(cs); return; } } @@ -1070,6 +1141,7 @@ read_request: cs->expiration_time = ap_server_conf->keep_alive_timeout + apr_time_now(); c->sbh = NULL; + notify_suspend(cs); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(keepalive_q, cs); @@ -1095,6 +1167,7 @@ read_request: * or timeout. */ c->sbh = NULL; + notify_suspend(cs); return; } @@ -3360,7 +3433,7 @@ static void event_hooks(apr_pool_t * p) APR_HOOK_MIDDLE); ap_hook_mpm_unregister_socket_callback(event_unregister_socket_callback, NULL, NULL, APR_HOOK_MIDDLE); - + ap_hook_pre_read_request(event_pre_read_request, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_mpm_get_name(event_get_name, NULL, NULL, APR_HOOK_MIDDLE); } diff --git a/server/mpm_common.c b/server/mpm_common.c index e1f05324474..b5b142aac36 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -75,6 +75,8 @@ APR_HOOK_STRUCT( APR_HOOK_LINK(mpm_get_name) APR_HOOK_LINK(end_generation) APR_HOOK_LINK(child_status) + APR_HOOK_LINK(suspend_connection) + APR_HOOK_LINK(resume_connection) ) AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception, (ap_exception_info_t *ei), (ei), OK, DECLINED) @@ -119,6 +121,12 @@ AP_IMPLEMENT_HOOK_VOID(end_generation, AP_IMPLEMENT_HOOK_VOID(child_status, (server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status status), (s,pid,gen,slot,status)) +AP_IMPLEMENT_HOOK_VOID(suspend_connection, + (conn_rec *c, request_rec *r), + (c, r)) +AP_IMPLEMENT_HOOK_VOID(resume_connection, + (conn_rec *c, request_rec *r), + (c, r)) /* hooks with no args are implemented last, after disabling APR hook probes */ #if defined(APR_HOOK_PROBES_ENABLED)