diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index c7726ec..9673c92 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -2615 +2618 diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 5b82a44..1cd5b32 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -449,6 +449,8 @@ * 20131230.2 (2.5.0-dev) Prefix REWRITE_REDIRECT_HANDLER_NAME in mod_rewrite.h * 20140207.0 (2.5.0-dev) Support for slaved connections in core.c * 20140207.1 (2.5.0-dev) Add SSL reusable SNI to mod_proxy.h's proxy_conn_rec + * 20140207.2 (2.5.0-dev) Add ap_mpm_resume_suspended(), AP_MPMQ_CAN_SUSPEND to + * ap_mpm_query(), and suspended_baton to conn_rec */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -456,7 +458,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20140207 #endif -#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/ap_mpm.h b/include/ap_mpm.h index ba7a95b..f1d037c 100644 --- a/include/ap_mpm.h +++ b/include/ap_mpm.h @@ -178,6 +178,8 @@ AP_DECLARE(apr_status_t) ap_os_create_privileged_process( #define AP_MPMQ_GENERATION 15 /** MPM can drive serf internally */ #define AP_MPMQ_HAS_SERF 16 +/** MPM supports suspending/resuming connections */ +#define AP_MPMQ_CAN_SUSPEND 17 /** @} */ /** @@ -198,6 +200,8 @@ AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result); typedef void (ap_mpm_callback_fn_t)(void *baton); /* only added support in the Event MPM.... check for APR_ENOTIMPL */ +AP_DECLARE(apr_status_t) ap_mpm_resume_suspended(conn_rec *c); +/* only added support in the Event MPM.... check for APR_ENOTIMPL */ AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton); diff --git a/include/httpd.h b/include/httpd.h index 228b81f..a063efe 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1173,6 +1173,9 @@ struct conn_rec { /** context of this connection */ void *ctx; + + /** Context under which this connection was suspended */ + void *suspended_baton; }; struct conn_slave_rec { diff --git a/include/mpm_common.h b/include/mpm_common.h index 92b6af6..0c05f6c 100644 --- a/include/mpm_common.h +++ b/include/mpm_common.h @@ -415,6 +415,9 @@ AP_DECLARE_HOOK(apr_status_t, mpm_register_socket_callback, AP_DECLARE_HOOK(apr_status_t, mpm_unregister_socket_callback, (apr_socket_t **s, apr_pool_t *p)) +/* Resume the suspended connection */ +AP_DECLARE_HOOK(apr_status_t, mpm_resume_suspended, (conn_rec*)) + /* get MPM name (e.g., "prefork" or "event") */ AP_DECLARE_HOOK(const char *,mpm_get_name,(void)) diff --git a/modules/test/mod_dialup.c b/modules/test/mod_dialup.c index 93e9743..b46097a 100644 --- a/modules/test/mod_dialup.c +++ b/modules/test/mod_dialup.c @@ -105,6 +105,7 @@ dialup_callback(void *baton) { int status; dialup_baton_t *db = (dialup_baton_t *)baton; + conn_rec *c = db->r->connection; apr_thread_mutex_lock(db->r->invoke_mtx); @@ -127,6 +128,8 @@ dialup_callback(void *baton) } apr_thread_mutex_unlock(db->r->invoke_mtx); + + ap_mpm_resume_suspended(c); } static int @@ -139,7 +142,7 @@ dialup_handler(request_rec *r) apr_file_t *fd; dialup_baton_t *db; apr_bucket *e; - + int mpm_can_suspend = 0; /* See core.c, default handler for all of the cases we just decline. */ if (r->method_number != M_GET || @@ -148,6 +151,13 @@ dialup_handler(request_rec *r) return DECLINED; } + rv = ap_mpm_query(AP_MPMQ_CAN_SUSPEND, &mpm_can_suspend); + if (!mpm_can_suspend) { + ap_log_rerror (APLOG_MARK, LOG_NOTICE, rv, r, APLOGNO(02617) + "dialup: MPM doesn't support suspending"); + return DECLINED; + } + dcfg = ap_get_module_config(r->per_dir_config, &dialup_module); diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index be90c7d..2e95f10 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -550,6 +550,9 @@ static int event_query(int query_code, int *result, apr_status_t *rv) case AP_MPMQ_GENERATION: *result = retained->my_generation; break; + case AP_MPMQ_CAN_SUSPEND: + *result = 1; + break; default: *rv = APR_ENOTIMPL; break; @@ -1153,6 +1156,7 @@ read_request: return; } else if (cs->pub.state == CONN_STATE_SUSPENDED) { + cs->c->suspended_baton = cs; apr_atomic_inc32(&suspended_count); } /* @@ -1166,6 +1170,33 @@ read_request: return; } +/* Put a SUSPENDED connection back into a queue. */ +static apr_status_t event_resume_suspended (conn_rec *c) { + event_conn_state_t* cs = (event_conn_state_t*) c->suspended_baton; + if (cs == NULL) { + ap_log_cerror (APLOG_MARK, LOG_WARNING, 0, c, APLOGNO(02615) + "ap_resume_suspended: suspended_baton is NULL"); + return APR_EGENERAL; + } else if (!cs->suspended) { + ap_log_cerror (APLOG_MARK, LOG_WARNING, 0, c, APLOGNO(02616) + "ap_resume_suspended: Thread isn't suspended"); + return APR_EGENERAL; + } + apr_atomic_dec32(&suspended_count); + c->suspended_baton = NULL; + + apr_thread_mutex_lock(timeout_mutex); + TO_QUEUE_APPEND(write_completion_q, cs); + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; + apr_pollset_add(event_pollset, &cs->pfd); + apr_thread_mutex_unlock(timeout_mutex); + + return OK; +} + /* conns_this_child has gone to zero or below. See if the admin coded "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way simplifies the hot path in worker_thread */ @@ -3430,6 +3461,7 @@ static void event_hooks(apr_pool_t * p) 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); + ap_hook_mpm_resume_suspended(event_resume_suspended, NULL, NULL, APR_HOOK_MIDDLE); } static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, diff --git a/server/mpm_common.c b/server/mpm_common.c index 5d0f36a..4762f92 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -71,6 +71,7 @@ APR_HOOK_LINK(mpm_register_socket_callback) \ APR_HOOK_LINK(mpm_unregister_socket_callback) \ APR_HOOK_LINK(mpm_get_name) \ + APR_HOOK_LINK(mpm_resume_suspended) \ APR_HOOK_LINK(end_generation) \ APR_HOOK_LINK(child_status) \ APR_HOOK_LINK(suspend_connection) \ @@ -102,6 +103,9 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm_query, AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback, (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton), (t, cbfn, baton), APR_ENOTIMPL) +AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_resume_suspended, + (conn_rec *c), + (c), APR_ENOTIMPL) AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_socket_callback, (apr_socket_t **s, apr_pool_t *p, int for_read, ap_mpm_callback_fn_t *cbfn, void *baton), (s, p, for_read, cbfn, baton), APR_ENOTIMPL) @@ -543,6 +547,10 @@ void ap_core_child_status(server_rec *s, pid_t pid, pid, gen, slot, status_msg); } +AP_DECLARE(apr_status_t) ap_mpm_resume_suspended(conn_rec *c) { + return ap_run_mpm_resume_suspended(c); +} + AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton) { return ap_run_mpm_register_timed_callback(t, cbfn, baton);