Hi Stefan,
On Sun, Feb 5, 2017 at 7:51 PM, Stefan Priebe - Profihost AG
<[email protected]> wrote:
>
> tested your patch against mod_ssl. I haven't seen any pool crashes again
> so it seems to fix this issue.
>
> But two new ones:
Possibly a promising fix suggested (in another thread) by yet another
talented Stefan :)
He has spotted a possible issue in mpm_event which could affect mainly
mod_http2.
I applied his suggestion in the attached patch, and did some
extrapolation for similar code in mod_h2 (so all possible errors are
mine...).
Would you test this one please?
@icing: I changed the parent pool of the slave connection from the
mplx pool to the master connection's (ptrans), just to simplify the
allocators in place for now.
I don't see it was needed from a concurrency POV, but if you wanted to
avoid locking when creating slaves' pool we can probably keep the
dedicated allocator finally (to reduce possible contention on
ptrans->mutex? No mutex needed I think since mplx doesn't seem to have
other subpools. Trade off with memory consumption, though).
Regards,
Yann.
Index: server/mpm/event/event.c
===================================================================
--- server/mpm/event/event.c (revision 1781789)
+++ server/mpm/event/event.c (working copy)
@@ -1749,6 +1749,7 @@ static void * APR_THREAD_FUNC listener_thread(apr_
if (ptrans == NULL) {
/* create a new transaction pool for each accepted socket */
apr_allocator_t *allocator;
+ apr_thread_mutex_t *mutex = NULL;
apr_allocator_create(&allocator);
apr_allocator_max_free_set(allocator,
@@ -1762,6 +1763,8 @@ static void * APR_THREAD_FUNC listener_thread(apr_
signal_threads(ST_GRACEFUL);
return NULL;
}
+ apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, ptrans);
+ apr_allocator_mutex_set(allocator, mutex);
}
apr_pool_tag(ptrans, "transaction");
Index: modules/http2/h2_conn.c
===================================================================
--- modules/http2/h2_conn.c (revision 1781789)
+++ modules/http2/h2_conn.c (working copy)
@@ -247,9 +247,10 @@ apr_status_t h2_conn_pre_close(struct h2_ctx *ctx,
return status;
}
-conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
+conn_rec *h2_slave_create(conn_rec *master, int slave_id)
{
- apr_allocator_t *allocator;
+ apr_allocator_t *allocator = NULL;
+ apr_thread_mutex_t *mutex = NULL;
apr_pool_t *pool;
conn_rec *c;
void *cfg;
@@ -264,9 +265,11 @@ apr_status_t h2_conn_pre_close(struct h2_ctx *ctx,
* another thread.
*/
apr_allocator_create(&allocator);
- apr_pool_create_ex(&pool, parent, NULL, allocator);
+ apr_pool_create_ex(&pool, master->pool, NULL, allocator);
apr_pool_tag(pool, "h2_slave_conn");
apr_allocator_owner_set(allocator, pool);
+ apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, pool);
+ apr_allocator_mutex_set(allocator, mutex);
c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
if (c == NULL) {
Index: modules/http2/h2_conn.h
===================================================================
--- modules/http2/h2_conn.h (revision 1781789)
+++ modules/http2/h2_conn.h (working copy)
@@ -66,7 +66,7 @@ typedef enum {
h2_mpm_type_t h2_conn_mpm_type(void);
-conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent);
+conn_rec *h2_slave_create(conn_rec *master, int slave_id);
void h2_slave_destroy(conn_rec *slave);
apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd);
Index: modules/http2/h2_mplx.c
===================================================================
--- modules/http2/h2_mplx.c (revision 1781789)
+++ modules/http2/h2_mplx.c (working copy)
@@ -33,6 +33,7 @@
#include "h2_private.h"
#include "h2_bucket_beam.h"
#include "h2_config.h"
+#include "h2_session.h"
#include "h2_conn.h"
#include "h2_ctx.h"
#include "h2_h2.h"
@@ -245,7 +246,7 @@ static void h2_mplx_destroy(h2_mplx *m)
m->id, (int)h2_ihash_count(m->tasks));
check_tx_free(m);
/* pool will be destroyed as child of h2_session->pool,
- slave connection pools are children of m->pool */
+ slave connection pools are children of m->c->pool */
}
/**
@@ -259,32 +260,27 @@ static void h2_mplx_destroy(h2_mplx *m)
* their HTTP/1 cousins, the separate allocator seems to work better
* than protecting a shared h2_session one with an own lock.
*/
-h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
- const h2_config *conf,
- apr_interval_time_t stream_timeout,
- h2_workers *workers)
+h2_mplx *h2_mplx_create(h2_session *session, h2_workers *workers)
{
apr_status_t status = APR_SUCCESS;
- apr_allocator_t *allocator = NULL;
+ apr_pool_t *parent = session->pool;
+ const h2_config *conf = session->config;
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) {
+ conn_rec *c = session->c;
+
m->id = c->id;
APR_RING_ELEM_INIT(m, link);
m->c = c;
- apr_pool_create_ex(&m->pool, parent, NULL, allocator);
+
+ apr_pool_create(&m->pool, parent);
if (!m->pool) {
return NULL;
}
apr_pool_tag(m->pool, "h2_mplx");
- apr_allocator_owner_set(allocator, m->pool);
status = apr_thread_mutex_create(&m->lock, APR_THREAD_MUTEX_DEFAULT,
m->pool);
@@ -311,7 +307,7 @@ static void h2_mplx_destroy(h2_mplx *m)
m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id));
m->redo_tasks = h2_ihash_create(m->pool, offsetof(h2_task, stream_id));
- m->stream_timeout = stream_timeout;
+ m->stream_timeout = session->s->timeout;
m->workers = workers;
m->workers_max = workers->max_workers;
m->workers_limit = 6; /* the original h1 max parallel connections */
@@ -891,7 +887,7 @@ static h2_task *next_stream_task(h2_mplx *m)
slave = *pslave;
}
else {
- slave = h2_slave_create(m->c, stream->id, m->pool);
+ slave = h2_slave_create(m->c, stream->id);
new_conn = 1;
}
Index: modules/http2/h2_mplx.h
===================================================================
--- modules/http2/h2_mplx.h (revision 1781789)
+++ modules/http2/h2_mplx.h (working copy)
@@ -38,7 +38,7 @@ struct apr_pool_t;
struct apr_thread_mutex_t;
struct apr_thread_cond_t;
struct h2_bucket_beam;
-struct h2_config;
+struct h2_session;
struct h2_ihash_t;
struct h2_task;
struct h2_stream;
@@ -124,9 +124,7 @@ apr_status_t h2_mplx_child_init(apr_pool_t *pool,
* Create the multiplexer for the given HTTP2 session.
* Implicitly has reference count 1.
*/
-h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *master,
- const struct h2_config *conf,
- apr_interval_time_t stream_timeout,
+h2_mplx *h2_mplx_create(struct h2_session *session,
struct h2_workers *workers);
/**
Index: modules/http2/h2_session.c
===================================================================
--- modules/http2/h2_session.c (revision 1781789)
+++ modules/http2/h2_session.c (working copy)
@@ -920,8 +920,7 @@ static h2_session *h2_session_create_int(conn_rec
return NULL;
}
- session->mplx = h2_mplx_create(c, session->pool, session->config,
- session->s->timeout, workers);
+ session->mplx = h2_mplx_create(session, workers);
h2_mplx_set_consumed_cb(session->mplx, update_window, session);