-*- 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]
* 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" */
#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
/* 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
*/
#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"
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;
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 */
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
*/
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);
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);
else {
c = cs->c;
c->sbh = sbh;
+ notify_resume(cs);
c->current_thread = thd;
}
*/
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 = (
if (cs->pub.state == CONN_STATE_LINGER) {
if (!start_lingering_close_blocking(cs)) {
c->sbh = NULL;
+ notify_suspend(cs);
return;
}
}
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);
* or timeout.
*/
c->sbh = NULL;
+ notify_suspend(cs);
return;
}
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);
}
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)
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)