You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2016/03/02 12:21:29 UTC
svn commit: r1733259 [4/4] - in /httpd/httpd/branches/2.4.x: ./
modules/http2/
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_util.h?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_util.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_util.h Wed Mar 2 11:21:28 2016
@@ -16,6 +16,9 @@
#ifndef __mod_h2__h2_util__
#define __mod_h2__h2_util__
+/*******************************************************************************
+ * some debugging/format helpers
+ ******************************************************************************/
struct h2_request;
struct nghttp2_frame;
@@ -28,10 +31,53 @@ size_t h2_util_header_print(char *buffer
void h2_util_camel_case_header(char *s, size_t len);
-int h2_req_ignore_header(const char *name, size_t len);
-int h2_req_ignore_trailer(const char *name, size_t len);
-void h2_req_strip_ignored_header(apr_table_t *headers);
-int h2_res_ignore_trailer(const char *name, size_t len);
+int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen);
+
+/*******************************************************************************
+ * ihash - hash for structs with int identifier
+ ******************************************************************************/
+typedef struct h2_ihash_t h2_ihash_t;
+typedef int h2_ihash_iter_t(void *ctx, void *val);
+
+/**
+ * Create a hash for structures that have an identifying int member.
+ * @param pool the pool to use
+ * @param offset_of_int the offsetof() the int member in the struct
+ */
+h2_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int);
+
+size_t h2_ihash_count(h2_ihash_t *ih);
+int h2_ihash_is_empty(h2_ihash_t *ih);
+void *h2_ihash_get(h2_ihash_t *ih, int id);
+
+/**
+ * Iterate over the hash members (without defined order) and invoke
+ * fn for each member until 0 is returned.
+ * @param ih the hash to iterate over
+ * @param fn the function to invoke on each member
+ * @param ctx user supplied data passed into each iteration call
+ */
+void h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx);
+
+void h2_ihash_add(h2_ihash_t *ih, void *val);
+void h2_ihash_remove(h2_ihash_t *ih, int id);
+void h2_ihash_clear(h2_ihash_t *ih);
+
+/*******************************************************************************
+ * common helpers
+ ******************************************************************************/
+/* h2_log2(n) iff n is a power of 2 */
+unsigned char h2_log2(apr_uint32_t n);
+
+/**
+ * Count the bytes that all key/value pairs in a table have
+ * in length (exlucding terminating 0s), plus additional extra per pair.
+ *
+ * @param t the table to inspect
+ * @param pair_extra the extra amount to add per pair
+ * @return the number of bytes all key/value pairs have
+ */
+apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra);
/**
* Return != 0 iff the string s contains the token, as specified in
@@ -42,6 +88,32 @@ int h2_util_contains_token(apr_pool_t *p
const char *h2_util_first_token_match(apr_pool_t *pool, const char *s,
const char *tokens[], apr_size_t len);
+/** Match a header value against a string constance, case insensitive */
+#define H2_HD_MATCH_LIT(l, name, nlen) \
+ ((nlen == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
+
+/*******************************************************************************
+ * HTTP/2 header helpers
+ ******************************************************************************/
+int h2_req_ignore_header(const char *name, size_t len);
+int h2_req_ignore_trailer(const char *name, size_t len);
+int h2_res_ignore_trailer(const char *name, size_t len);
+int h2_proxy_res_ignore_header(const char *name, size_t len);
+
+/**
+ * Set the push policy for the given request. Takes request headers into
+ * account, see draft https://tools.ietf.org/html/draft-ruellan-http-accept-push-policy-00
+ * for details.
+ *
+ * @param req the request to determine the policy for
+ * @param p the pool to use
+ * @param push_enabled if HTTP/2 server push is generally enabled for this request
+ */
+void h2_push_policy_determine(struct h2_request *req, apr_pool_t *p, int push_enabled);
+
+/*******************************************************************************
+ * base64 url encoding, different table from normal base64
+ ******************************************************************************/
/**
* I always wanted to write my own base64url decoder...not. See
* https://tools.ietf.org/html/rfc4648#section-5 for description.
@@ -52,8 +124,9 @@ apr_size_t h2_util_base64url_decode(cons
const char *h2_util_base64url_encode(const char *data,
apr_size_t len, apr_pool_t *pool);
-#define H2_HD_MATCH_LIT(l, name, nlen) \
- ((nlen == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
+/*******************************************************************************
+ * nghttp2 helpers
+ ******************************************************************************/
#define H2_HD_MATCH_LIT_CS(l, name) \
((strlen(name) == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
@@ -87,6 +160,9 @@ h2_ngheader *h2_util_ngheader_make_res(a
h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p,
const struct h2_request *req);
+/*******************************************************************************
+ * apr brigade helpers
+ ******************************************************************************/
/**
* Moves data from one brigade into another. If maxlen > 0, it only
* moves up to maxlen bytes into the target brigade, making bucket splits
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_version.h?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_version.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_version.h Wed Mar 2 11:21:28 2016
@@ -26,7 +26,7 @@
* @macro
* Version number of the http2 module as c string
*/
-#define MOD_HTTP2_VERSION "1.2.2"
+#define MOD_HTTP2_VERSION "1.3.2"
/**
* @macro
@@ -34,7 +34,7 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_HTTP2_VERSION_NUM 0x010202
+#define MOD_HTTP2_VERSION_NUM 0x010302
#endif /* mod_h2_h2_version_h */
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c Wed Mar 2 11:21:28 2016
@@ -22,81 +22,43 @@
#include <http_core.h>
#include <http_log.h>
+#include "h2.h"
#include "h2_private.h"
#include "h2_conn.h"
#include "h2_ctx.h"
#include "h2_h2.h"
#include "h2_mplx.h"
-#include "h2_request.h"
#include "h2_task.h"
#include "h2_worker.h"
static void* APR_THREAD_FUNC execute(apr_thread_t *thread, void *wctx)
{
h2_worker *worker = (h2_worker *)wctx;
- apr_status_t status;
-
- (void)thread;
- /* Other code might want to see a socket for this connection this
- * worker processes. Allocate one without further function...
- */
- status = apr_socket_create(&worker->socket,
- APR_INET, SOCK_STREAM,
- APR_PROTO_TCP, worker->pool);
- if (status != APR_SUCCESS) {
- ap_log_perror(APLOG_MARK, APLOG_ERR, status, worker->pool,
- APLOGNO(02948) "h2_worker(%d): alloc socket",
- worker->id);
- worker->worker_done(worker, worker->ctx);
- return NULL;
- }
+ int sticky;
while (!worker->aborted) {
- h2_mplx *m;
- const h2_request *req;
+ h2_task *task;
- /* Get a h2_mplx + h2_request from the main workers queue. */
- status = worker->get_next(worker, &m, &req, worker->ctx);
-
- while (req) {
- conn_rec *c, *master = m->c;
- int stream_id = req->id;
+ /* Get a h2_task from the main workers queue. */
+ worker->get_next(worker, worker->ctx, &task, &sticky);
+ while (task) {
+ h2_task_do(task, worker->io);
- c = h2_slave_create(master, worker->task_pool,
- worker->thread, worker->socket);
- if (!c) {
- ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, c,
- APLOGNO(02957) "h2_request(%ld-%d): error setting up slave connection",
- m->id, stream_id);
- h2_mplx_out_rst(m, stream_id, H2_ERR_INTERNAL_ERROR);
+ /* if someone was waiting on this task, time to wake up */
+ apr_thread_cond_signal(worker->io);
+ /* report the task done and maybe get another one from the same
+ * mplx (= master connection), if we can be sticky.
+ */
+ if (sticky && !worker->aborted) {
+ h2_mplx_task_done(task->mplx, task, &task);
}
else {
- h2_task *task;
-
- task = h2_task_create(m->id, req, worker->task_pool, m);
- h2_ctx_create_for(c, task);
- h2_task_do(task, c, worker->io, worker->socket);
+ h2_mplx_task_done(task->mplx, task, NULL);
task = NULL;
-
- apr_thread_cond_signal(worker->io);
}
-
- /* clean our references and report request as done. Signal
- * that we want another unless we have been aborted */
- /* TODO: this will keep a worker attached to this h2_mplx as
- * long as it has requests to handle. Might no be fair to
- * other mplx's. Perhaps leave after n requests? */
- req = NULL;
- apr_pool_clear(worker->task_pool);
- h2_mplx_request_done(&m, stream_id, worker->aborted? NULL : &req);
}
}
- if (worker->socket) {
- apr_socket_close(worker->socket);
- worker->socket = NULL;
- }
-
worker->worker_done(worker, worker->ctx);
return NULL;
}
@@ -116,6 +78,7 @@ h2_worker *h2_worker_create(int id,
apr_allocator_create(&allocator);
apr_allocator_max_free_set(allocator, ap_max_mem_free);
apr_pool_create_ex(&pool, parent_pool, NULL, allocator);
+ apr_pool_tag(pool, "h2_worker");
apr_allocator_owner_set(allocator, pool);
w = apr_pcalloc(pool, sizeof(h2_worker));
@@ -134,7 +97,6 @@ h2_worker *h2_worker_create(int id,
return NULL;
}
- apr_pool_create(&w->task_pool, w->pool);
apr_thread_create(&w->thread, attr, execute, w, w->pool);
}
return w;
@@ -173,13 +135,4 @@ int h2_worker_is_aborted(h2_worker *work
return worker->aborted;
}
-h2_task *h2_worker_create_task(h2_worker *worker, h2_mplx *m,
- const h2_request *req)
-{
- h2_task *task;
-
- task = h2_task_create(m->id, req, worker->task_pool, m);
- return task;
-}
-
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h Wed Mar 2 11:21:28 2016
@@ -30,9 +30,9 @@ typedef struct h2_worker h2_worker;
* until a h2_mplx becomes available or the worker itself
* gets aborted (idle timeout, for example). */
typedef apr_status_t h2_worker_mplx_next_fn(h2_worker *worker,
- struct h2_mplx **pm,
- const struct h2_request **preq,
- void *ctx);
+ void *ctx,
+ struct h2_task **ptask,
+ int *psticky);
/* Invoked just before the worker thread exits. */
typedef void h2_worker_done_fn(h2_worker *worker, void *ctx);
@@ -45,9 +45,7 @@ struct h2_worker {
int id;
apr_thread_t *thread;
apr_pool_t *pool;
- apr_pool_t *task_pool;
struct apr_thread_cond_t *io;
- apr_socket_t *socket;
h2_worker_mplx_next_fn *get_next;
h2_worker_done_fn *worker_done;
@@ -142,7 +140,4 @@ int h2_worker_get_id(h2_worker *worker);
int h2_worker_is_aborted(h2_worker *worker);
-struct h2_task *h2_worker_create_task(h2_worker *worker, struct h2_mplx *m,
- const struct h2_request *req);
-
#endif /* defined(__mod_h2__h2_worker__) */
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c Wed Mar 2 11:21:28 2016
@@ -23,10 +23,10 @@
#include <http_core.h>
#include <http_log.h>
+#include "h2.h"
#include "h2_private.h"
#include "h2_mplx.h"
-#include "h2_request.h"
-#include "h2_task_queue.h"
+#include "h2_task.h"
#include "h2_worker.h"
#include "h2_workers.h"
@@ -61,124 +61,137 @@ static void cleanup_zombies(h2_workers *
}
}
+static h2_task *next_task(h2_workers *workers)
+{
+ h2_task *task = NULL;
+ h2_mplx *last = NULL;
+ int has_more;
+
+ /* Get the next h2_mplx to process that has a task to hand out.
+ * If it does, place it at the end of the queu and return the
+ * task to the worker.
+ * If it (currently) has no tasks, remove it so that it needs
+ * to register again for scheduling.
+ * If we run out of h2_mplx in the queue, we need to wait for
+ * new mplx to arrive. Depending on how many workers do exist,
+ * we do a timed wait or block indefinitely.
+ */
+ while (!task && !H2_MPLX_LIST_EMPTY(&workers->mplxs)) {
+ h2_mplx *m = H2_MPLX_LIST_FIRST(&workers->mplxs);
+
+ if (last == m) {
+ break;
+ }
+ H2_MPLX_REMOVE(m);
+ --workers->mplx_count;
+
+ task = h2_mplx_pop_task(m, &has_more);
+ if (has_more) {
+ H2_MPLX_LIST_INSERT_TAIL(&workers->mplxs, m);
+ ++workers->mplx_count;
+ if (!last) {
+ last = m;
+ }
+ }
+ }
+ return task;
+}
+
/**
* Get the next task for the given worker. Will block until a task arrives
* or the max_wait timer expires and more than min workers exist.
- * The previous h2_mplx instance might be passed in and will be served
- * with preference, since we can ask it for the next task without aquiring
- * the h2_workers lock.
*/
-static apr_status_t get_mplx_next(h2_worker *worker, h2_mplx **pm,
- const h2_request **preq, void *ctx)
+static apr_status_t get_mplx_next(h2_worker *worker, void *ctx,
+ h2_task **ptask, int *psticky)
{
apr_status_t status;
- apr_time_t max_wait, start_wait;
- h2_workers *workers = (h2_workers *)ctx;
+ apr_time_t wait_until = 0, now;
+ h2_workers *workers = ctx;
+ h2_task *task = NULL;
- max_wait = apr_time_from_sec(apr_atomic_read32(&workers->max_idle_secs));
- start_wait = apr_time_now();
+ *ptask = NULL;
+ *psticky = 0;
status = apr_thread_mutex_lock(workers->lock);
if (status == APR_SUCCESS) {
- const h2_request *req = NULL;
- h2_mplx *m = NULL;
- int has_more = 0;
-
- ++workers->idle_worker_count;
+ ++workers->idle_workers;
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
"h2_worker(%d): looking for work", h2_worker_get_id(worker));
- while (!req && !h2_worker_is_aborted(worker) && !workers->aborted) {
-
- /* Get the next h2_mplx to process that has a task to hand out.
- * If it does, place it at the end of the queu and return the
- * task to the worker.
- * If it (currently) has no tasks, remove it so that it needs
- * to register again for scheduling.
- * If we run out of h2_mplx in the queue, we need to wait for
- * new mplx to arrive. Depending on how many workers do exist,
- * we do a timed wait or block indefinitely.
- */
- m = NULL;
- while (!req && !H2_MPLX_LIST_EMPTY(&workers->mplxs)) {
- m = H2_MPLX_LIST_FIRST(&workers->mplxs);
- H2_MPLX_REMOVE(m);
+ while (!h2_worker_is_aborted(worker) && !workers->aborted
+ && !(task = next_task(workers))) {
+
+ /* Need to wait for a new tasks to arrive. If we are above
+ * minimum workers, we do a timed wait. When timeout occurs
+ * and we have still more workers, we shut down one after
+ * the other. */
+ cleanup_zombies(workers, 0);
+ if (workers->worker_count > workers->min_workers) {
+ now = apr_time_now();
+ if (now >= wait_until) {
+ wait_until = now + apr_time_from_sec(workers->max_idle_secs);
+ }
- req = h2_mplx_pop_request(m, &has_more);
- if (req) {
- if (has_more) {
- H2_MPLX_LIST_INSERT_TAIL(&workers->mplxs, m);
- }
- else {
- has_more = !H2_MPLX_LIST_EMPTY(&workers->mplxs);
- }
+ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
+ "h2_worker(%d): waiting signal, "
+ "workers=%d, idle=%d", worker->id,
+ (int)workers->worker_count,
+ workers->idle_workers);
+ status = apr_thread_cond_timedwait(workers->mplx_added,
+ workers->lock,
+ wait_until - now);
+ if (status == APR_TIMEUP
+ && workers->worker_count > workers->min_workers) {
+ /* waited long enough without getting a task and
+ * we are above min workers, abort this one. */
+ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0,
+ workers->s,
+ "h2_workers: aborting idle worker");
+ h2_worker_abort(worker);
break;
}
}
-
- if (!req) {
- /* Need to wait for a new mplx to arrive.
- */
- cleanup_zombies(workers, 0);
-
- if (workers->worker_count > workers->min_size) {
- apr_time_t now = apr_time_now();
- if (now >= (start_wait + max_wait)) {
- /* waited long enough without getting a task. */
- if (workers->worker_count > workers->min_size) {
- ap_log_error(APLOG_MARK, APLOG_TRACE3, 0,
- workers->s,
- "h2_workers: aborting idle worker");
- h2_worker_abort(worker);
- break;
- }
- }
- ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
- "h2_worker(%d): waiting signal, "
- "worker_count=%d", worker->id,
- (int)workers->worker_count);
- apr_thread_cond_timedwait(workers->mplx_added,
- workers->lock, max_wait);
- }
- else {
- ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
- "h2_worker(%d): waiting signal (eternal), "
- "worker_count=%d", worker->id,
- (int)workers->worker_count);
- apr_thread_cond_wait(workers->mplx_added, workers->lock);
- }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
+ "h2_worker(%d): waiting signal (eternal), "
+ "worker_count=%d, idle=%d", worker->id,
+ (int)workers->worker_count,
+ workers->idle_workers);
+ apr_thread_cond_wait(workers->mplx_added, workers->lock);
}
}
- /* Here, we either have gotten task and mplx for the worker or
- * needed to give up with more than enough workers.
+ /* Here, we either have gotten task or decided to shut down
+ * the calling worker.
*/
- if (req) {
- ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
- "h2_worker(%d): start request(%ld-%d)",
- h2_worker_get_id(worker), m->id, req->id);
- *pm = m;
- *preq = req;
+ if (task) {
+ /* Ok, we got something to give back to the worker for execution.
+ * If we have more idle workers than h2_mplx in our queue, then
+ * we let the worker be sticky, e.g. making it poll the task's
+ * h2_mplx instance for more work before asking back here.
+ * This avoids entering our global lock as long as enough idle
+ * workers remain. Stickiness of a worker ends when the connection
+ * has no new tasks to process, so the worker will get back here
+ * eventually.
+ */
+ *ptask = task;
+ *psticky = (workers->max_workers >= workers->mplx_count);
- if (has_more && workers->idle_worker_count > 1) {
+ if (workers->mplx_count && workers->idle_workers > 1) {
apr_thread_cond_signal(workers->mplx_added);
}
- status = APR_SUCCESS;
- }
- else {
- status = APR_EOF;
}
- --workers->idle_worker_count;
+ --workers->idle_workers;
apr_thread_mutex_unlock(workers->lock);
}
- return status;
+ return *ptask? APR_SUCCESS : APR_EOF;
}
static void worker_done(h2_worker *worker, void *ctx)
{
- h2_workers *workers = (h2_workers *)ctx;
+ h2_workers *workers = ctx;
apr_status_t status = apr_thread_mutex_lock(workers->lock);
if (status == APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
@@ -213,7 +226,7 @@ static apr_status_t h2_workers_start(h2_
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
"h2_workers: starting");
- while (workers->worker_count < workers->min_size
+ while (workers->worker_count < workers->min_workers
&& status == APR_SUCCESS) {
status = add_worker(workers);
}
@@ -223,7 +236,7 @@ static apr_status_t h2_workers_start(h2_
}
h2_workers *h2_workers_create(server_rec *s, apr_pool_t *server_pool,
- int min_size, int max_size,
+ int min_workers, int max_workers,
apr_size_t max_tx_handles)
{
apr_status_t status;
@@ -239,13 +252,14 @@ h2_workers *h2_workers_create(server_rec
* happen on the pool handed to us, which we do not guard.
*/
apr_pool_create(&pool, server_pool);
+ apr_pool_tag(pool, "h2_workers");
workers = apr_pcalloc(pool, sizeof(h2_workers));
if (workers) {
workers->s = s;
workers->pool = pool;
- workers->min_size = min_size;
- workers->max_size = max_size;
- apr_atomic_set32(&workers->max_idle_secs, 10);
+ workers->min_workers = min_workers;
+ workers->max_workers = max_workers;
+ workers->max_idle_secs = 10;
workers->max_tx_handles = max_tx_handles;
workers->spare_tx_handles = workers->max_tx_handles;
@@ -320,22 +334,22 @@ apr_status_t h2_workers_register(h2_work
apr_status_t status = apr_thread_mutex_lock(workers->lock);
if (status == APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_TRACE3, status, workers->s,
- "h2_workers: register mplx(%ld)", m->id);
+ "h2_workers: register mplx(%ld), idle=%d",
+ m->id, workers->idle_workers);
if (in_list(workers, m)) {
- ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
- "h2_workers: already registered mplx(%ld)", m->id);
status = APR_EAGAIN;
}
else {
H2_MPLX_LIST_INSERT_TAIL(&workers->mplxs, m);
+ ++workers->mplx_count;
status = APR_SUCCESS;
}
- if (workers->idle_worker_count > 0) {
+ if (workers->idle_workers > 0) {
apr_thread_cond_signal(workers->mplx_added);
}
else if (status == APR_SUCCESS
- && workers->worker_count < workers->max_size) {
+ && workers->worker_count < workers->max_workers) {
ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, workers->s,
"h2_workers: got %d worker, adding 1",
workers->worker_count);
@@ -368,7 +382,7 @@ void h2_workers_set_max_idle_secs(h2_wor
" is not valid, ignored.", idle_secs);
return;
}
- apr_atomic_set32(&workers->max_idle_secs, idle_secs);
+ workers->max_idle_secs = idle_secs;
}
apr_size_t h2_workers_tx_reserve(h2_workers *workers, apr_size_t count)
Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h Wed Mar 2 11:21:28 2016
@@ -27,7 +27,6 @@ struct apr_thread_cond_t;
struct h2_mplx;
struct h2_request;
struct h2_task;
-struct h2_task_queue;
typedef struct h2_workers h2_workers;
@@ -36,8 +35,11 @@ struct h2_workers {
apr_pool_t *pool;
int next_worker_id;
- int min_size;
- int max_size;
+ int min_workers;
+ int max_workers;
+ int worker_count;
+ int idle_workers;
+ int max_idle_secs;
apr_size_t max_tx_handles;
apr_size_t spare_tx_handles;
@@ -49,10 +51,7 @@ struct h2_workers {
APR_RING_HEAD(h2_worker_list, h2_worker) workers;
APR_RING_HEAD(h2_worker_zombies, h2_worker) zombies;
APR_RING_HEAD(h2_mplx_list, h2_mplx) mplxs;
-
- int worker_count;
- volatile apr_uint32_t max_idle_secs;
- volatile apr_uint32_t idle_worker_count;
+ int mplx_count;
struct apr_thread_mutex_t *lock;
struct apr_thread_cond_t *mplx_added;
Modified: httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/mod_http2.c Wed Mar 2 11:21:28 2016
@@ -15,6 +15,7 @@
#include <apr_optional.h>
#include <apr_optional_hooks.h>
+#include <apr_time.h>
#include <apr_want.h>
#include <httpd.h>
@@ -34,6 +35,7 @@
#include "h2_config.h"
#include "h2_ctx.h"
#include "h2_h2.h"
+#include "h2_mplx.h"
#include "h2_push.h"
#include "h2_request.h"
#include "h2_switch.h"
@@ -71,7 +73,7 @@ static int h2_post_config(apr_pool_t *p,
apr_pool_t *ptemp, server_rec *s)
{
void *data = NULL;
- const char *mod_h2_init_key = "mod_h2_init_counter";
+ const char *mod_h2_init_key = "mod_http2_init_counter";
nghttp2_info *ngh2;
apr_status_t status;
(void)plog;(void)ptemp;
@@ -91,6 +93,12 @@ static int h2_post_config(apr_pool_t *p,
MOD_HTTP2_VERSION, ngh2? ngh2->version_str : "unknown");
switch (h2_conn_mpm_type()) {
+ case H2_MPM_SIMPLE:
+ case H2_MPM_MOTORZ:
+ case H2_MPM_NETWARE:
+ case H2_MPM_WINNT:
+ /* not sure we need something extra for those. */
+ break;
case H2_MPM_EVENT:
case H2_MPM_WORKER:
/* all fine, we know these ones */
@@ -109,6 +117,9 @@ static int h2_post_config(apr_pool_t *p,
if (status == APR_SUCCESS) {
status = h2_switch_init(p, s);
}
+ if (status == APR_SUCCESS) {
+ status = h2_task_init(p, s);
+ }
return status;
}
@@ -117,6 +128,31 @@ static char *http2_var_lookup(apr_pool_t
conn_rec *, request_rec *, char *name);
static int http2_is_h2(conn_rec *);
+static apr_status_t http2_req_engine_push(const char *engine_type,
+ request_rec *r,
+ h2_req_engine_init *einit)
+{
+ return h2_mplx_engine_push(engine_type, r, einit);
+}
+
+static apr_status_t http2_req_engine_pull(h2_req_engine *engine,
+ apr_read_type_e block,
+ request_rec **pr)
+{
+ return h2_mplx_engine_pull(engine, block, pr);
+}
+
+static void http2_req_engine_done(h2_req_engine *engine, conn_rec *r_conn)
+{
+ h2_mplx_engine_done(engine, r_conn);
+}
+
+static void http2_req_engine_exit(h2_req_engine *engine)
+{
+ h2_mplx_engine_exit(engine);
+}
+
+
/* Runs once per created child process. Perform any process
* related initionalization here.
*/
@@ -129,8 +165,6 @@ static void h2_child_init(apr_pool_t *po
APLOGNO(02949) "initializing connection handling");
}
- APR_REGISTER_OPTIONAL_FN(http2_is_h2);
- APR_REGISTER_OPTIONAL_FN(http2_var_lookup);
}
/* Install this module into the apache2 infrastructure.
@@ -139,6 +173,13 @@ static void h2_hooks(apr_pool_t *pool)
{
static const char *const mod_ssl[] = { "mod_ssl.c", NULL};
+ APR_REGISTER_OPTIONAL_FN(http2_is_h2);
+ APR_REGISTER_OPTIONAL_FN(http2_var_lookup);
+ APR_REGISTER_OPTIONAL_FN(http2_req_engine_push);
+ APR_REGISTER_OPTIONAL_FN(http2_req_engine_pull);
+ APR_REGISTER_OPTIONAL_FN(http2_req_engine_done);
+ APR_REGISTER_OPTIONAL_FN(http2_req_engine_exit);
+
ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
/* Run once after configuration is set, but before mpm children initialize.
Modified: httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp Wed Mar 2 11:21:28 2016
@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "ssize_t=long" /FD /c
-# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/nghttp2/lib/includes" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ssize_t=long" /Fd"Release\mod_http2_src" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../ssl" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/nghttp2/lib/includes" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ssize_t=long" /Fd"Release\mod_http2_src" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -75,7 +75,7 @@ PostBuild_Cmds=if exist $(TargetPath).ma
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "ssize_t=long" /FD /c
-# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/nghttp2/lib/includes" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ssize_t=long" /Fd"Debug\mod_http2_src" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../ssl" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../../srclib/nghttp2/lib/includes" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ssize_t=long" /Fd"Debug\mod_http2_src" /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
@@ -141,6 +141,10 @@ SOURCE=./h2_h2.c
# End Source File
# Begin Source File
+SOURCE=./h2_int_queue.c
+# End Source File
+# Begin Source File
+
SOURCE=./h2_io.c
# End Source File
# Begin Source File
@@ -173,10 +177,6 @@ SOURCE=./h2_stream.c
# End Source File
# Begin Source File
-SOURCE=./h2_stream_set.c
-# End Source File
-# Begin Source File
-
SOURCE=./h2_switch.c
# End Source File
# Begin Source File
@@ -193,10 +193,6 @@ SOURCE=./h2_task_output.c
# End Source File
# Begin Source File
-SOURCE=./h2_task_queue.c
-# End Source File
-# Begin Source File
-
SOURCE=./h2_util.c
# End Source File
# Begin Source File
Modified: httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h?rev=1733259&r1=1733258&r2=1733259&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/mod_http2.h Wed Mar 2 11:21:28 2016
@@ -13,18 +13,101 @@
* limitations under the License.
*/
-#ifndef mod_http2_mod_http2_h
-#define mod_http2_mod_http2_h
+#ifndef __MOD_HTTP2_H__
+#define __MOD_HTTP2_H__
/** The http2_var_lookup() optional function retrieves HTTP2 environment
* variables. */
-APR_DECLARE_OPTIONAL_FN(char *, http2_var_lookup,
- (apr_pool_t *, server_rec *,
- conn_rec *, request_rec *,
- char *));
+APR_DECLARE_OPTIONAL_FN(char *,
+ http2_var_lookup, (apr_pool_t *, server_rec *,
+ conn_rec *, request_rec *, char *));
/** An optional function which returns non-zero if the given connection
* or its master connection is using HTTP/2. */
-APR_DECLARE_OPTIONAL_FN(int, http2_is_h2, (conn_rec *));
+APR_DECLARE_OPTIONAL_FN(int,
+ http2_is_h2, (conn_rec *));
+
+
+/*******************************************************************************
+ * HTTP/2 request engines
+ ******************************************************************************/
+
+struct apr_thread_cond_t;
+
+typedef struct h2_req_engine h2_req_engine;
+
+/**
+ * Initialize a h2_req_engine. The structure will be passed in but
+ * only the name and master are set. The function should initialize
+ * all fields.
+ * @param engine the allocated, partially filled structure
+ * @param r the first request to process, or NULL
+ */
+typedef apr_status_t h2_req_engine_init(h2_req_engine *engine, request_rec *r);
+
+/**
+ * The public structure of a h2_req_engine. It gets allocated by the http2
+ * infrastructure, assigned id, type, pool, io and connection and passed to the
+ * h2_req_engine_init() callback to complete initialization.
+ * This happens whenever a new request gets "push"ed for an engine type and
+ * no instance, or no free instance, for the type is available.
+ */
+struct h2_req_engine {
+ const char *id; /* identifier */
+ apr_pool_t *pool; /* pool for engine specific allocations */
+ const char *type; /* name of the engine type */
+ unsigned char window_bits;/* preferred size of overall response data
+ * mod_http2 is willing to buffer as log2 */
+ unsigned char req_window_bits;/* preferred size of response body data
+ * mod_http2 is willing to buffer per request,
+ * as log2 */
+ apr_size_t capacity; /* maximum concurrent requests */
+ void *user_data; /* user specific data */
+};
+
+/**
+ * Push a request to an engine with the specified name for further processing.
+ * If no such engine is available, einit is not NULL, einit is called
+ * with a new engine record and the caller is responsible for running the
+ * new engine instance.
+ * @param engine_type the type of the engine to add the request to
+ * @param r the request to push to an engine for processing
+ * @param einit an optional initialization callback for a new engine
+ * of the requested type, should no instance be available.
+ * By passing a non-NULL callback, the caller is willing
+ * to init and run a new engine itself.
+ * @return APR_SUCCESS iff slave was successfully added to an engine
+ */
+APR_DECLARE_OPTIONAL_FN(apr_status_t,
+ http2_req_engine_push, (const char *engine_type,
+ request_rec *r,
+ h2_req_engine_init *einit));
+
+/**
+ * Get a new request for processing in this engine.
+ * @param engine the engine which is done processing the slave
+ * @param timeout wait a maximum amount of time for a new slave, 0 will not wait
+ * @param pslave the slave connection that needs processing or NULL
+ * @return APR_SUCCESS if new request was assigned
+ * APR_EAGAIN/APR_TIMEUP if no new request is available
+ * APR_ECONNABORTED if the engine needs to shut down
+ */
+APR_DECLARE_OPTIONAL_FN(apr_status_t,
+ http2_req_engine_pull, (h2_req_engine *engine,
+ apr_read_type_e block,
+ request_rec **pr));
+APR_DECLARE_OPTIONAL_FN(void,
+ http2_req_engine_done, (h2_req_engine *engine,
+ conn_rec *rconn));
+/**
+ * The given request engine is done processing and needs to be excluded
+ * from further handling.
+ * @param engine the engine to exit
+ */
+APR_DECLARE_OPTIONAL_FN(void,
+ http2_req_engine_exit, (h2_req_engine *engine));
+
+
+#define H2_TASK_ID_NOTE "http2-task-id"
#endif