Loading CHANGES +5 −1 Original line number Diff line number Diff line -*- coding: utf-8 -*- Changes with Apache 2.4.18 *) mod_http2: reworked deallocation on connection shutdown and worker abort. Separate parent pool for all workers. worker threads are joined on planned worker shutdown. [Yann Ylavic, Stefan Eissing] Changes with Apache 2.4.17 Loading modules/http2/h2_conn.c +1 −1 Original line number Diff line number Diff line Loading @@ -255,7 +255,7 @@ apr_status_t h2_session_process(h2_session *session) have_written = 1; wait_micros = 0; } else if (status == APR_EAGAIN) { else if (APR_STATUS_IS_EAGAIN(status)) { /* nop */ } else if (status == APR_TIMEUP) { Loading modules/http2/h2_io.c +53 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,12 @@ void h2_io_destroy(h2_io *io) h2_io_cleanup(io); } void h2_io_rst(h2_io *io, int error) { io->rst_error = error; io->eos_in = 1; } int h2_io_in_has_eos_for(h2_io *io) { return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, 0)); Loading Loading @@ -124,16 +130,52 @@ apr_status_t h2_io_out_readx(h2_io *io, h2_io_data_cb *cb, void *ctx, apr_size_t *plen, int *peos) { apr_status_t status; if (io->eos_out) { *plen = 0; *peos = 1; return APR_SUCCESS; } if (cb == NULL) { /* just checking length available */ return h2_util_bb_avail(io->bbout, plen, peos); status = h2_util_bb_avail(io->bbout, plen, peos); } else { status = h2_util_bb_readx(io->bbout, cb, ctx, plen, peos); if (status == APR_SUCCESS) { io->eos_out = *peos; } return h2_util_bb_readx(io->bbout, cb, ctx, plen, peos); } return status; } apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, apr_size_t maxlen, int *pfile_handles_allowed) { apr_status_t status; int start_allowed; if (io->eos_out) { apr_off_t len; /* We have already delivered an EOS bucket to a reader, no * sense in storing anything more here. */ status = apr_brigade_length(bb, 1, &len); if (status == APR_SUCCESS) { if (len > 0) { /* someone tries to write real data after EOS, that * does not look right. */ status = APR_EOF; } /* cleanup, as if we had moved the data */ apr_brigade_cleanup(bb); } return status; } /* Let's move the buckets from the request processing in here, so * that the main thread can read them when it has time/capacity. * Loading @@ -144,8 +186,11 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, * many open files already buffered. Otherwise we will run out of * file handles. */ int start_allowed = *pfile_handles_allowed; apr_status_t status; start_allowed = *pfile_handles_allowed; if (io->rst_error) { return APR_ECONNABORTED; } status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed, "h2_io_out_write"); /* track # file buckets moved into our pool */ Loading @@ -158,7 +203,9 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, apr_status_t h2_io_out_close(h2_io *io) { if (!io->eos_out && !h2_util_has_eos(io->bbout, 0)) { APR_BRIGADE_INSERT_TAIL(io->bbout, apr_bucket_eos_create(io->bbout->bucket_alloc)); } return APR_SUCCESS; } modules/http2/h2_io.h +7 −0 Original line number Diff line number Diff line Loading @@ -33,11 +33,13 @@ struct h2_io { apr_bucket_brigade *bbin; /* input data for stream */ int eos_in; int task_done; int rst_error; apr_size_t input_consumed; /* how many bytes have been read */ struct apr_thread_cond_t *input_arrived; /* block on reading */ apr_bucket_brigade *bbout; /* output data from stream */ int eos_out; struct apr_thread_cond_t *output_drained; /* block on writing */ struct h2_response *response;/* submittable response created */ Loading @@ -58,6 +60,11 @@ h2_io *h2_io_create(int id, apr_pool_t *pool, apr_bucket_alloc_t *bucket_alloc); */ void h2_io_destroy(h2_io *io); /** * Reset the stream with the given error code. */ void h2_io_rst(h2_io *io, int error); /** * The input data is completely queued. Blocked reads will return immediately * and give either data or EOF. Loading modules/http2/h2_io_set.c +28 −23 Original line number Diff line number Diff line Loading @@ -78,19 +78,6 @@ h2_io *h2_io_set_get(h2_io_set *sp, int stream_id) return ps? *ps : NULL; } h2_io *h2_io_set_get_highest_prio(h2_io_set *set) { h2_io *highest = NULL; int i; for (i = 0; i < set->list->nelts; ++i) { h2_io *io = h2_io_IDX(set->list, i); if (!highest /*|| io-prio even higher */ ) { highest = io; } } return highest; } static void h2_io_set_sort(h2_io_set *sp) { qsort(sp->list->elts, sp->list->nelts, sp->list->elt_size, Loading Loading @@ -118,28 +105,46 @@ apr_status_t h2_io_set_add(h2_io_set *sp, h2_io *io) return APR_SUCCESS; } h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io) static void remove_idx(h2_io_set *sp, int idx) { int i; for (i = 0; i < sp->list->nelts; ++i) { h2_io *e = h2_io_IDX(sp->list, i); if (e == io) { int n; --sp->list->nelts; n = sp->list->nelts - i; n = sp->list->nelts - idx; if (n > 0) { /* Close the hole in the array by moving the upper * parts down one step. */ h2_io **selts = (h2_io**)sp->list->elts; memmove(selts+i, selts+i+1, n * sizeof(h2_io*)); memmove(selts + idx, selts + idx + 1, n * sizeof(h2_io*)); } } h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io) { int i; for (i = 0; i < sp->list->nelts; ++i) { h2_io *e = h2_io_IDX(sp->list, i); if (e == io) { remove_idx(sp, i); return e; } } return NULL; } h2_io *h2_io_set_pop_highest_prio(h2_io_set *set) { /* For now, this just removes the first element in the set. * the name is misleading... */ if (set->list->nelts > 0) { h2_io *io = h2_io_IDX(set->list, 0); remove_idx(set, 0); return io; } return NULL; } void h2_io_set_destroy_all(h2_io_set *sp) { int i; Loading Loading
CHANGES +5 −1 Original line number Diff line number Diff line -*- coding: utf-8 -*- Changes with Apache 2.4.18 *) mod_http2: reworked deallocation on connection shutdown and worker abort. Separate parent pool for all workers. worker threads are joined on planned worker shutdown. [Yann Ylavic, Stefan Eissing] Changes with Apache 2.4.17 Loading
modules/http2/h2_conn.c +1 −1 Original line number Diff line number Diff line Loading @@ -255,7 +255,7 @@ apr_status_t h2_session_process(h2_session *session) have_written = 1; wait_micros = 0; } else if (status == APR_EAGAIN) { else if (APR_STATUS_IS_EAGAIN(status)) { /* nop */ } else if (status == APR_TIMEUP) { Loading
modules/http2/h2_io.c +53 −6 Original line number Diff line number Diff line Loading @@ -47,6 +47,12 @@ void h2_io_destroy(h2_io *io) h2_io_cleanup(io); } void h2_io_rst(h2_io *io, int error) { io->rst_error = error; io->eos_in = 1; } int h2_io_in_has_eos_for(h2_io *io) { return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, 0)); Loading Loading @@ -124,16 +130,52 @@ apr_status_t h2_io_out_readx(h2_io *io, h2_io_data_cb *cb, void *ctx, apr_size_t *plen, int *peos) { apr_status_t status; if (io->eos_out) { *plen = 0; *peos = 1; return APR_SUCCESS; } if (cb == NULL) { /* just checking length available */ return h2_util_bb_avail(io->bbout, plen, peos); status = h2_util_bb_avail(io->bbout, plen, peos); } else { status = h2_util_bb_readx(io->bbout, cb, ctx, plen, peos); if (status == APR_SUCCESS) { io->eos_out = *peos; } return h2_util_bb_readx(io->bbout, cb, ctx, plen, peos); } return status; } apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, apr_size_t maxlen, int *pfile_handles_allowed) { apr_status_t status; int start_allowed; if (io->eos_out) { apr_off_t len; /* We have already delivered an EOS bucket to a reader, no * sense in storing anything more here. */ status = apr_brigade_length(bb, 1, &len); if (status == APR_SUCCESS) { if (len > 0) { /* someone tries to write real data after EOS, that * does not look right. */ status = APR_EOF; } /* cleanup, as if we had moved the data */ apr_brigade_cleanup(bb); } return status; } /* Let's move the buckets from the request processing in here, so * that the main thread can read them when it has time/capacity. * Loading @@ -144,8 +186,11 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, * many open files already buffered. Otherwise we will run out of * file handles. */ int start_allowed = *pfile_handles_allowed; apr_status_t status; start_allowed = *pfile_handles_allowed; if (io->rst_error) { return APR_ECONNABORTED; } status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed, "h2_io_out_write"); /* track # file buckets moved into our pool */ Loading @@ -158,7 +203,9 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, apr_status_t h2_io_out_close(h2_io *io) { if (!io->eos_out && !h2_util_has_eos(io->bbout, 0)) { APR_BRIGADE_INSERT_TAIL(io->bbout, apr_bucket_eos_create(io->bbout->bucket_alloc)); } return APR_SUCCESS; }
modules/http2/h2_io.h +7 −0 Original line number Diff line number Diff line Loading @@ -33,11 +33,13 @@ struct h2_io { apr_bucket_brigade *bbin; /* input data for stream */ int eos_in; int task_done; int rst_error; apr_size_t input_consumed; /* how many bytes have been read */ struct apr_thread_cond_t *input_arrived; /* block on reading */ apr_bucket_brigade *bbout; /* output data from stream */ int eos_out; struct apr_thread_cond_t *output_drained; /* block on writing */ struct h2_response *response;/* submittable response created */ Loading @@ -58,6 +60,11 @@ h2_io *h2_io_create(int id, apr_pool_t *pool, apr_bucket_alloc_t *bucket_alloc); */ void h2_io_destroy(h2_io *io); /** * Reset the stream with the given error code. */ void h2_io_rst(h2_io *io, int error); /** * The input data is completely queued. Blocked reads will return immediately * and give either data or EOF. Loading
modules/http2/h2_io_set.c +28 −23 Original line number Diff line number Diff line Loading @@ -78,19 +78,6 @@ h2_io *h2_io_set_get(h2_io_set *sp, int stream_id) return ps? *ps : NULL; } h2_io *h2_io_set_get_highest_prio(h2_io_set *set) { h2_io *highest = NULL; int i; for (i = 0; i < set->list->nelts; ++i) { h2_io *io = h2_io_IDX(set->list, i); if (!highest /*|| io-prio even higher */ ) { highest = io; } } return highest; } static void h2_io_set_sort(h2_io_set *sp) { qsort(sp->list->elts, sp->list->nelts, sp->list->elt_size, Loading Loading @@ -118,28 +105,46 @@ apr_status_t h2_io_set_add(h2_io_set *sp, h2_io *io) return APR_SUCCESS; } h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io) static void remove_idx(h2_io_set *sp, int idx) { int i; for (i = 0; i < sp->list->nelts; ++i) { h2_io *e = h2_io_IDX(sp->list, i); if (e == io) { int n; --sp->list->nelts; n = sp->list->nelts - i; n = sp->list->nelts - idx; if (n > 0) { /* Close the hole in the array by moving the upper * parts down one step. */ h2_io **selts = (h2_io**)sp->list->elts; memmove(selts+i, selts+i+1, n * sizeof(h2_io*)); memmove(selts + idx, selts + idx + 1, n * sizeof(h2_io*)); } } h2_io *h2_io_set_remove(h2_io_set *sp, h2_io *io) { int i; for (i = 0; i < sp->list->nelts; ++i) { h2_io *e = h2_io_IDX(sp->list, i); if (e == io) { remove_idx(sp, i); return e; } } return NULL; } h2_io *h2_io_set_pop_highest_prio(h2_io_set *set) { /* For now, this just removes the first element in the set. * the name is misleading... */ if (set->list->nelts > 0) { h2_io *io = h2_io_IDX(set->list, 0); remove_idx(set, 0); return io; } return NULL; } void h2_io_set_destroy_all(h2_io_set *sp) { int i; Loading