apr_status_t h2_task_do(h2_task *task, h2_worker *worker) { apr_status_t status = APR_SUCCESS; AP_DEBUG_ASSERT(task); task->serialize_headers = h2_config_geti(task->request->config, H2_CONF_SER_HEADERS); status = h2_worker_setup_task(worker, task); /* save in connection that this one is a pseudo connection */ h2_ctx_create_for(task->c, task); if (status == APR_SUCCESS) { task->input = h2_task_input_create(task, task->pool, task->c->bucket_alloc); task->output = h2_task_output_create(task, task->pool); ap_process_connection(task->c, h2_worker_get_socket(worker)); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, task->c, "h2_task(%s): processing done", task->id); } else { ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, task->c, APLOGNO(02957) "h2_task(%s): error setting up h2_task", task->id); } if (task->input) { h2_task_input_destroy(task->input); task->input = NULL; } if (task->output) { h2_task_output_close(task->output); h2_task_output_destroy(task->output); task->output = NULL; } if (task->io) { apr_thread_cond_signal(task->io); } h2_worker_release_task(worker, task); h2_mplx_task_done(task->mplx, task->stream_id); return status; }
apr_status_t h2_task_do(h2_task *task, h2_worker *worker) { apr_status_t status = APR_SUCCESS; h2_config *cfg = h2_config_get(task->mplx->c); h2_task_env env; AP_DEBUG_ASSERT(task); memset(&env, 0, sizeof(env)); env.id = task->id; env.stream_id = task->stream_id; env.mplx = task->mplx; task->mplx = NULL; env.input_eos = task->input_eos; env.serialize_headers = !!h2_config_geti(cfg, H2_CONF_SER_HEADERS); /* Create a subpool from the worker one to be used for all things * with life-time of this task_env execution. */ apr_pool_create(&env.pool, h2_worker_get_pool(worker)); /* Link the env to the worker which provides useful things such * as mutex, a socket etc. */ env.io = h2_worker_get_cond(worker); /* Clone fields, so that lifetimes become (more) independent. */ env.method = apr_pstrdup(env.pool, task->method); env.path = apr_pstrdup(env.pool, task->path); env.authority = apr_pstrdup(env.pool, task->authority); env.headers = apr_table_clone(env.pool, task->headers); /* Setup the pseudo connection to use our own pool and bucket_alloc */ if (task->c) { env.c = *task->c; task->c = NULL; status = h2_conn_setup(&env, worker); } else { status = h2_conn_init(&env, worker); } /* save in connection that this one is a pseudo connection, prevents * other hooks from messing with it. */ h2_ctx_create_for(&env.c, &env); if (status == APR_SUCCESS) { env.input = h2_task_input_create(&env, env.pool, env.c.bucket_alloc); env.output = h2_task_output_create(&env, env.pool, env.c.bucket_alloc); status = h2_conn_process(&env.c, h2_worker_get_socket(worker)); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, &env.c, "h2_task(%s): processing done", env.id); } else { ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, &env.c, "h2_task(%s): error setting up h2_task_env", env.id); } if (env.input) { h2_task_input_destroy(env.input); env.input = NULL; } if (env.output) { h2_task_output_close(env.output); h2_task_output_destroy(env.output); env.output = NULL; } h2_task_set_finished(task); if (env.io) { apr_thread_cond_signal(env.io); } if (env.pool) { apr_pool_destroy(env.pool); env.pool = NULL; } if (env.c.id) { h2_conn_post(&env.c, worker); } h2_mplx_task_done(env.mplx, env.stream_id); return status; }
apr_status_t h2_task_do(h2_task *task, h2_worker *worker) { apr_status_t status = APR_SUCCESS; h2_config *cfg = h2_config_get(task->mplx->c); h2_task_env env; AP_DEBUG_ASSERT(task); memset(&env, 0, sizeof(env)); env.id = task->id; env.stream_id = task->stream_id; env.mplx = task->mplx; /* Not cloning these task fields: * If the stream is destroyed before the task is done, this might * be a problem. However that should never happen as stream destruction * explicitly checks if task processing has finished. */ env.method = task->method; env.path = task->path; env.authority = task->authority; env.headers = task->headers; env.input_eos = task->input_eos; task->io = env.io = h2_worker_get_cond(worker); env.conn = task->conn; task->conn = NULL; env.serialize_headers = !!h2_config_geti(cfg, H2_CONF_SER_HEADERS); status = h2_conn_prep(env.conn, task->mplx->c, worker); /* save in connection that this one is for us, prevents * other hooks from messing with it. */ h2_ctx_create_for(env.conn->c, &env); if (status == APR_SUCCESS) { apr_pool_t *pool = env.conn->pool; apr_bucket_alloc_t *bucket_alloc = env.conn->bucket_alloc; env.input = h2_task_input_create(&env, pool, bucket_alloc); env.output = h2_task_output_create(&env, pool, bucket_alloc); status = h2_conn_process(env.conn); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, env.conn->c, "h2_task(%s):processing done", task->id); if (env.input) { h2_task_input_destroy(env.input); env.input = NULL; } if (env.conn) { h2_conn_post(env.conn, worker); env.conn = NULL; } if (env.output) { h2_task_output_close(env.output); h2_task_output_destroy(env.output); env.output = NULL; } h2_task_set_finished(task); if (env.io) { apr_thread_cond_signal(env.io); } return status; }
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id) { conn_rec *c; ap_assert(task); c = task->c; task->worker_started = 1; task->started_at = apr_time_now(); if (c->master) { /* Each conn_rec->id is supposed to be unique at a point in time. Since * some modules (and maybe external code) uses this id as an identifier * for the request_rec they handle, it needs to be unique for slave * connections also. * The connection id is generated by the MPM and most MPMs use the formula * id := (child_num * max_threads) + thread_num * which means that there is a maximum id of about * idmax := max_child_count * max_threads * If we assume 2024 child processes with 2048 threads max, we get * idmax ~= 2024 * 2048 = 2 ** 22 * On 32 bit systems, we have not much space left, but on 64 bit systems * (and higher?) we can use the upper 32 bits without fear of collision. * 32 bits is just what we need, since a connection can only handle so * many streams. */ int slave_id, free_bits; task->id = apr_psprintf(task->pool, "%ld-%d", c->master->id, task->stream_id); if (sizeof(unsigned long) >= 8) { free_bits = 32; slave_id = task->stream_id; } else { /* Assume we have a more limited number of threads/processes * and h2 workers on a 32-bit system. Use the worker instead * of the stream id. */ free_bits = 8; slave_id = worker_id; } task->c->id = (c->master->id << free_bits)^slave_id; c->keepalive = AP_CONN_KEEPALIVE; } h2_beam_create(&task->output.beam, c->pool, task->stream_id, "output", H2_BEAM_OWNER_SEND, 0, task->timeout); if (!task->output.beam) { return APR_ENOMEM; } h2_beam_buffer_size_set(task->output.beam, task->output.max_buffer); h2_beam_send_from(task->output.beam, task->pool); h2_ctx_create_for(c, task); apr_table_setn(c->notes, H2_TASK_ID_NOTE, task->id); if (task->input.beam) { h2_beam_mutex_enable(task->input.beam); } h2_slave_run_pre_connection(c, ap_get_conn_socket(c)); task->input.bb = apr_brigade_create(task->pool, c->bucket_alloc); if (task->request->serialize) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): serialize request %s %s", task->id, task->request->method, task->request->path); apr_brigade_printf(task->input.bb, NULL, NULL, "%s %s HTTP/1.1\r\n", task->request->method, task->request->path); apr_table_do(input_ser_header, task, task->request->headers, NULL); apr_brigade_puts(task->input.bb, NULL, NULL, "\r\n"); } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): process connection", task->id); task->c->current_thread = thread; ap_run_process_connection(c); if (task->frozen) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): process_conn returned frozen task", task->id); /* cleanup delayed */ return APR_EAGAIN; } else { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_task(%s): processing done", task->id); return output_finish(task); } }
apr_status_t h2_task_do(h2_task *task, h2_worker *worker) { apr_status_t status = APR_SUCCESS; h2_config *cfg = h2_config_get(task->mplx->c); AP_DEBUG_ASSERT(task); task->serialize_headers = h2_config_geti(cfg, H2_CONF_SER_HEADERS); /* Create a subpool from the worker one to be used for all things * with life-time of this task execution. */ apr_pool_create(&task->pool, h2_worker_get_pool(worker)); /* Link the task to the worker which provides useful things such * as mutex, a socket etc. */ task->io = h2_worker_get_cond(worker); status = h2_conn_setup(task, worker); /* save in connection that this one is a pseudo connection, prevents * other hooks from messing with it. */ h2_ctx_create_for(task->c, task); if (status == APR_SUCCESS) { task->input = h2_task_input_create(task, task->pool, task->c->bucket_alloc); task->output = h2_task_output_create(task, task->pool, task->c->bucket_alloc); status = h2_conn_process(task->c, h2_worker_get_socket(worker)); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, task->c, "h2_task(%s): processing done", task->id); } else { ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, task->c, APLOGNO(02957) "h2_task(%s): error setting up h2_task", task->id); } if (task->input) { h2_task_input_destroy(task->input); task->input = NULL; } if (task->output) { h2_task_output_close(task->output); h2_task_output_destroy(task->output); task->output = NULL; } if (task->io) { apr_thread_cond_signal(task->io); } if (task->pool) { apr_pool_destroy(task->pool); task->pool = NULL; } if (task->c->id) { h2_conn_post(task->c, worker); } h2_mplx_task_done(task->mplx, task->stream_id); return status; }