From: Jim Jagielski Date: Tue, 15 Apr 2014 19:15:02 +0000 (+0000) Subject: Merge r1546759, r1546760 from trunk: X-Git-Tag: 2.4.10~343 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0dd6174440278a404eb330c9563ad5f45a1a03e0;p=apache Merge r1546759, r1546760 from trunk: 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.) follow-up to r1546759: remove an inadvertently committed testcase Submitted by: trawick Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1587695 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 04f1866501..ad0180d764 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,10 @@ Changes with Apache 2.4.10 "http-equiv" meta tag specifies a Content-Type behind any other "http-equiv" meta tag. PR 56287 [Micha Lenk ] + *) Add suspend_connection and resume_connection hooks to notify modules + when the thread/connection relationship changes. (Should be implemented + for any third-party async MPMs.) [Jeff Trawick] + *) mod_lua: Redesign how request record table access behaves, in order to utilize the request record from within these tables [Daniel Gruno] diff --git a/STATUS b/STATUS index 1b240eabb3..fd442fce03 100644 --- a/STATUS +++ b/STATUS @@ -114,13 +114,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: 2.4.x patch: trunk works +1 covener, jim, ylavic - * event: Add suspend/resume hooks to event MPM to inform modules when - connections/requests change thread affinity. - trunk: http://svn.apache.org/viewvc?view=revision&revision=1546759 - http://svn.apache.org/viewvc?view=revision&revision=1546760 - 2.4.x patch: http://people.apache.org/~trawick/suspend_resume_24.txt - +1: trawick, jim, ylavic - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 8918e1a5f3..32e05d55b4 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -427,6 +427,7 @@ * 20120211.30 (2.4.7-dev) REWRITE_REDIRECT_HANDLER_NAME in mod_rewrite.h * 20120211.31 (2.4.7-dev) Add ap_proxy_port_of_scheme() * 20120211.32 (2.4.10-dev) Add SSL reusable SNI to mod_proxy.h's proxy_conn_rec + * 20120211.33 (2.4.10-dev) Add suspend_connection and resume_connection hooks */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -434,7 +435,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 32 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 33 /* 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 59684313c6..69afef8c94 100644 --- a/include/mpm_common.h +++ b/include/mpm_common.h @@ -411,6 +411,47 @@ AP_DECLARE_HOOK(apr_status_t, mpm_register_timed_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 7a95498ea3..9bcad5c38e 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" @@ -185,6 +186,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; @@ -192,6 +195,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 */ @@ -875,6 +885,57 @@ static int stop_lingering_close(event_conn_state_t *cs) return 0; } +static void notify_suspend(event_conn_state_t *cs) +{ + 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 */ @@ -905,6 +966,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); @@ -915,6 +977,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); @@ -946,6 +1009,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; } @@ -998,6 +1062,7 @@ read_request: * event thread poll for writeability. */ cs->expiration_time = ap_server_conf->timeout + apr_time_now(); + notify_suspend(cs); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); cs->pfd.reqevents = ( @@ -1023,6 +1088,7 @@ read_request: if (cs->pub.state == CONN_STATE_LINGER) { if (!start_lingering_close_blocking(cs)) + notify_suspend(cs); return; } else if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) { @@ -1037,6 +1103,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); @@ -1062,6 +1129,7 @@ read_request: * or timeout. */ c->sbh = NULL; + notify_suspend(cs); return; } @@ -3171,6 +3239,7 @@ static void event_hooks(apr_pool_t * p) ap_hook_mpm_query(event_query, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_mpm_register_timed_callback(event_register_timed_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 348e667606..3b8e4ebccf 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -73,6 +73,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) @@ -108,6 +110,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)