AP_CORE_DECLARE(void) ap_process_connection(conn_rec *c, void *csd) { int rc; ap_update_vhost_given_ip(c); rc = ap_run_pre_connection(c, csd); if (rc != OK && rc != DONE) { c->aborted = 1; } if (!c->aborted) { ap_run_process_connection(c); } }
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); } }
/* * worker_main() * Main entry point for the worker threads. Worker threads block in * win*_get_connection() awaiting a connection to service. */ static DWORD __stdcall worker_main(void *thread_num_val) { apr_thread_t *thd; apr_os_thread_t osthd; static int requests_this_child = 0; winnt_conn_ctx_t *context = NULL; int thread_num = (int)thread_num_val; ap_sb_handle_t *sbh; apr_bucket *e; int rc; conn_rec *c; apr_int32_t disconnected; osthd = apr_os_thread_current(); while (1) { ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL); /* Grab a connection off the network */ context = winnt_get_connection(context); if (!context) { /* Time for the thread to exit */ break; } /* Have we hit MaxConnectionsPerChild connections? */ if (ap_max_requests_per_child) { requests_this_child++; if (requests_this_child > ap_max_requests_per_child) { SetEvent(max_requests_per_child_event); } } e = context->overlapped.Pointer; ap_create_sb_handle(&sbh, context->ptrans, 0, thread_num); c = ap_run_create_connection(context->ptrans, ap_server_conf, context->sock, thread_num, sbh, context->ba); if (!c) { /* ap_run_create_connection closes the socket on failure */ context->accept_socket = INVALID_SOCKET; if (e) apr_bucket_free(e); continue; } thd = NULL; apr_os_thread_put(&thd, &osthd, context->ptrans); c->current_thread = thd; /* follow ap_process_connection(c, context->sock) logic * as it left us no chance to reinject our first data bucket. */ ap_update_vhost_given_ip(c); rc = ap_run_pre_connection(c, context->sock); if (rc != OK && rc != DONE) { c->aborted = 1; } if (e && c->aborted) { apr_bucket_free(e); } else { ap_set_module_config(c->conn_config, &mpm_winnt_module, context); } if (!c->aborted) { ap_run_process_connection(c); apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED, &disconnected); if (!disconnected) { context->accept_socket = INVALID_SOCKET; ap_lingering_close(c); } } } ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD, (request_rec *) NULL); return 0; }