From: Eric Covener Date: Wed, 13 Mar 2024 01:26:54 +0000 (+0000) Subject: shutdown carefully when threads don't start X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3e19c3cebdf07aec9ffef07dc4a81a666450e33;p=thirdparty%2Fapache%2Fhttpd.git shutdown carefully when threads don't start Submitted By: ylavic, covener git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1916267 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/start-threads.txt b/changes-entries/start-threads.txt new file mode 100644 index 00000000000..a3fa5e9cbe0 --- /dev/null +++ b/changes-entries/start-threads.txt @@ -0,0 +1,3 @@ + *) worker, event: Avoid possible hangs and crashes during shutdown of + child processes that fail to start their configured threads. + [Yann Ylavic, Eric Covener] diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 831d3c25161..3841142c603 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -2745,11 +2745,28 @@ static void *APR_THREAD_FUNC start_threads(apr_thread_t * thd, void *dummy) rv = ap_thread_create(&threads[i], thread_attr, worker_thread, my_info, pruntime); if (rv != APR_SUCCESS) { + ap_update_child_status_from_indexes(my_child_num, i, SERVER_DEAD, NULL); ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(03104) "ap_thread_create: unable to create worker thread"); - /* let the parent decide how bad this really is */ - signal_threads(listener_started ? ST_GRACEFUL : ST_UNGRACEFUL); + /* Let the parent decide how bad this really is by returning + * APEXIT_CHILDSICK. If threads were created already let them + * stop cleanly first to avoid deadlocks in clean_child_exit(), + * just stop creating new ones here (but set resource_shortage + * to return APEXIT_CHILDSICK still when the child exists). + */ + if (threads_created) { + resource_shortage = 1; + signal_threads(ST_GRACEFUL); + if (!listener_started) { + workers_may_exit = 1; + ap_queue_term(worker_queue); + /* wake up main POD thread too */ + kill(ap_my_pid, SIGTERM); + } + apr_thread_exit(thd, APR_SUCCESS); + return NULL; + } clean_child_exit(APEXIT_CHILDSICK); } threads_created++; diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index aebbd0b6f4b..ecf38aedfc9 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -979,9 +979,27 @@ static void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy) rv = ap_thread_create(&threads[i], thread_attr, worker_thread, my_info, pruntime); if (rv != APR_SUCCESS) { + ap_update_child_status_from_indexes(my_child_num, i, SERVER_DEAD, NULL); ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(03142) "ap_thread_create: unable to create worker thread"); - /* let the parent decide how bad this really is */ + /* Let the parent decide how bad this really is by returning + * APEXIT_CHILDSICK. If threads were created already let them + * stop cleanly first to avoid deadlocks in clean_child_exit(), + * just stop creating new ones here (but set resource_shortage + * to return APEXIT_CHILDSICK still when the child exists). + */ + if (threads_created) { + resource_shortage = 1; + signal_threads(ST_GRACEFUL); + if (!listener_started) { + workers_may_exit = 1; + ap_queue_term(worker_queue); + /* wake up main POD thread too */ + kill(ap_my_pid, SIGTERM); + } + apr_thread_exit(thd, APR_SUCCESS); + return NULL; + } clean_child_exit(APEXIT_CHILDSICK); } threads_created++;