From: Yann Ylavic Date: Mon, 20 Feb 2017 13:41:59 +0000 (+0000) Subject: mod_http2: use a mutex for mplx and slave connections's allocator to be safe X-Git-Tag: 2.5.0-alpha~643 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e50f64f80d3decec117e66e85d4c1d0c4680ba57;p=thirdparty%2Fapache%2Fhttpd.git mod_http2: use a mutex for mplx and slave connections's allocator to be safe with concurrent creation and destruction of their subpools. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1783756 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http2/h2_conn.c b/modules/http2/h2_conn.c index b13d47f83fb..a8de28425b3 100644 --- a/modules/http2/h2_conn.c +++ b/modules/http2/h2_conn.c @@ -26,6 +26,8 @@ #include #include +#include + #include "h2_private.h" #include "h2.h" #include "h2_config.h" @@ -253,6 +255,8 @@ apr_status_t h2_conn_pre_close(struct h2_ctx *ctx, conn_rec *c) conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent) { apr_allocator_t *allocator; + apr_thread_mutex_t *mutex; + apr_status_t status; apr_pool_t *pool; conn_rec *c; void *cfg; @@ -265,18 +269,30 @@ conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent) /* We create a pool with its own allocator to be used for * processing a request. This is the only way to have the processing * independant of its parent pool in the sense that it can work in - * another thread. + * another thread. Also, the new allocator needs its own mutex to + * synchronize sub-pools. */ apr_allocator_create(&allocator); + apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&pool, parent, NULL, allocator); apr_pool_tag(pool, "h2_slave_conn"); apr_allocator_owner_set(allocator, pool); - + status = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool); + if (status != APR_SUCCESS) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, status, master, + APLOGNO() "h2_session(%ld-%d): create slave mutex", + master->id, slave_id); + apr_pool_destroy(pool); + return NULL; + } + apr_allocator_mutex_set(allocator, mutex); + c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec)); if (c == NULL) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, master, APLOGNO(02913) "h2_session(%ld-%d): create slave", master->id, slave_id); + apr_pool_destroy(pool); return NULL; } diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 5f3a0d0635a..ad2342b61e5 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -27,6 +27,8 @@ #include #include +#include + #include "mod_http2.h" #include "h2.h" @@ -232,35 +234,53 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent, h2_workers *workers) { apr_status_t status = APR_SUCCESS; - apr_allocator_t *allocator = NULL; + apr_allocator_t *allocator; + apr_thread_mutex_t *mutex; h2_mplx *m; ap_assert(conf); - status = apr_allocator_create(&allocator); - if (status != APR_SUCCESS) { - return NULL; - } - m = apr_pcalloc(parent, sizeof(h2_mplx)); if (m) { m->id = c->id; APR_RING_ELEM_INIT(m, link); m->c = c; + + /* We create a pool with its own allocator to be used for + * processing slave connections. This is the only way to have the + * processing independant of its parent pool in the sense that it + * can work in another thread. Also, the new allocator needs its own + * mutex to synchronize sub-pools. + */ + status = apr_allocator_create(&allocator); + if (status != APR_SUCCESS) { + return NULL; + } + apr_allocator_max_free_set(allocator, ap_max_mem_free); apr_pool_create_ex(&m->pool, parent, NULL, allocator); if (!m->pool) { + apr_allocator_destroy(allocator); return NULL; } apr_pool_tag(m->pool, "h2_mplx"); apr_allocator_owner_set(allocator, m->pool); - + status = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, + m->pool); + if (status != APR_SUCCESS) { + apr_pool_destroy(m->pool); + return NULL; + } + apr_allocator_mutex_set(allocator, mutex); + status = apr_thread_mutex_create(&m->lock, APR_THREAD_MUTEX_DEFAULT, m->pool); if (status != APR_SUCCESS) { + apr_pool_destroy(m->pool); return NULL; } status = apr_thread_cond_create(&m->task_thawed, m->pool); if (status != APR_SUCCESS) { + apr_pool_destroy(m->pool); return NULL; }