From: Jim Jagielski Date: Mon, 19 Aug 2013 15:42:12 +0000 (+0000) Subject: Merge r1470679, r1477094 from trunk: X-Git-Tag: 2.4.7~284 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3ee5174b2a6a3ab55cd4c23555cdc998bb1cfaec;p=apache Merge r1470679, r1477094 from trunk: core, mod_ssl: Lift the restriction that prevents mod_ssl taking full advantage of the event MPM. Enable the ability for a module to reverse the sense of a poll event from a read to a write or vice versa. Update the docs to note that SSL now works with the event MPM as per r1470679. Submitted by: minfrin Reviewed/backported by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1515476 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 9dea413a35..de5aa4bfb3 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,11 @@ Changes with Apache 2.4.7 + *) core, mod_ssl: Enable the ability for a module to reverse the sense of + a poll event from a read to a write or vice versa. This is a step on + the way to allow mod_ssl taking full advantage of the event MPM. + [Graham Leggett] + *) Makefile.win: Install proper pcre DLL file during debug build install. PR 55235. [Ben Reser ] diff --git a/STATUS b/STATUS index 0bb4e1a83e..a68f6344f5 100644 --- a/STATUS +++ b/STATUS @@ -92,18 +92,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * core, mod_ssl: Lift the restriction that prevents mod_ssl taking - full advantage of the event MPM. Enable the ability for a module - to reverse the sense of a poll event from a read to a write or vice - versa. - trunk patches: http://svn.apache.org/r1470679 - http://svn.apache.org/r1477094 - 2.4.x patch: http://people.apache.org/~minfrin/httpd-event-ssl.patch - +1: minfrin, jim, sf - sf: These docs/CHANGES commits should be included, too: - http://svn.apache.org/r1514214 - http://svn.apache.org/r1514617 - * configure: '--enable-maintainer-mode' should also auto-enable mod_bucketeer trunk: http://svn.apache.org/viewvc?view=revision&revision=1503680 2.4.x patch: trunk patch works diff --git a/docs/manual/mod/event.xml b/docs/manual/mod/event.xml index c27136058d..764608c164 100644 --- a/docs/manual/mod/event.xml +++ b/docs/manual/mod/event.xml @@ -60,10 +60,19 @@ of consuming threads only for connections with active processing status page of mod_status shows how many connections are in the mentioned states.

-

The improved connection handling does not yet work for certain - connection filters, in particular SSL. For SSL connections, this MPM will - fall back to the behaviour of the worker MPM and - reserve one worker thread per connection.

+

The improved connection handling may not work for certain connection + filters that have declared themselves as incompatible with event. In these + cases, this MPM will fall back to the behaviour of the + worker MPM and reserve one worker thread per connection. + All modules shipped with the server are compatible with the event MPM.

+ +

A similar restriction is currently present for requests involving an + output filter that needs to read and/or modify the whole response body, + like for example mod_ssl, mod_deflate, or mod_include. If the + connection to the client blocks while the filter is processing the + data, and the amount of data produced by the filter is too big to be + buffered in memory, the thread used for the request is not freed while + httpd waits until the pending data is sent to the client.

The MPM assumes that the underlying apr_pollset implementation is reasonably threadsafe. This enables the MPM to @@ -152,10 +161,10 @@ of consuming threads only for connections with active processing

The event MPM handles some connections in an asynchronous way, where request worker threads are only allocated for short periods of time as - needed, and other (mostly SSL) connections with one request worker thread - reserved per connection. This can lead to situations where all workers are - tied up and no worker thread is available to handle new work on established - async connections.

+ needed, and other connections with one request worker thread reserved per + connection. This can lead to situations where all workers are tied up and + no worker thread is available to handle new work on established async + connections.

To mitigate this problem, the event MPM does two things: Firstly, it limits the number of connections accepted per process, depending on the diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 82a0acb00d..4f5ed0677e 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -419,6 +419,7 @@ * 20120211.22 (2.4.5-dev) No longer prevent usage of strtoul() * 20120211.23 (2.4.5-dev) Add ap_proxy_clear_connection() * 20120211.24 (2.4.7-dev) add open_htaccess hook. + * 20120211.25 (2.4.7-dev) Add conn_sense_e */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -426,7 +427,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 24 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 25 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index 36cd58d542..c84e24468a 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1175,12 +1175,20 @@ typedef enum { CONN_STATE_LINGER_SHORT /* MPM has started lingering close with short timeout */ } conn_state_e; +typedef enum { + CONN_SENSE_DEFAULT, + CONN_SENSE_WANT_READ, /* next event must be read */ + CONN_SENSE_WANT_WRITE /* next event must be write */ +} conn_sense_e; + /** * @brief A structure to contain connection state information */ struct conn_state_t { /** Current state of the connection */ conn_state_e state; + /** Whether to read instead of write, or write instead of read */ + conn_sense_e sense; }; /* Per-vhost config... */ diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index d135bd3815..cca15b4c7c 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -775,6 +775,18 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, */ outctx->rc = APR_EAGAIN; } + else if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * If OpenSSL wants to read during write, and we were + * nonblocking, set the sense explicitly to read and + * report as an EAGAIN. + * + * (This is usually the case when the client forces an SSL + * renegotiation which is handled implicitly by OpenSSL.) + */ + outctx->c->cs->sense = CONN_SENSE_WANT_READ; + outctx->rc = APR_EAGAIN; + } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, APLOGNO(01993) "SSL output filter write failed."); @@ -1902,8 +1914,10 @@ void ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl) filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); - /* We insert a clogging input filter. Let the core know. */ - c->clogging_input_filters = 1; + /* write is non blocking for the benefit of async mpm */ + if (c->cs) { + BIO_set_nbio(filter_ctx->pbioWrite, 1); + } ssl_io_input_add_filter(filter_ctx, c, r, ssl); diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index c64b08f5f4..f12468f51a 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -790,7 +790,10 @@ static int start_lingering_close_common(event_conn_state_t *cs) apr_atomic_inc32(&lingering_count); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(*q, cs); - cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT : + APR_POLLIN) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rv = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { @@ -938,6 +941,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; } else { c = cs->c; @@ -946,9 +950,11 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc } if (c->clogging_input_filters && !c->aborted) { - /* Since we have an input filter which 'cloggs' the input stream, - * like mod_ssl, lets just do the normal read from input filters, - * like the Worker MPM does. + /* Since we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. */ apr_atomic_inc32(&clogged_count); ap_run_process_connection(c); @@ -994,7 +1000,10 @@ read_request: cs->expiration_time = ap_server_conf->timeout + apr_time_now(); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); - cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rc = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); return;