]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
shutdown carefully when threads don't start
authorEric Covener <covener@apache.org>
Wed, 13 Mar 2024 01:26:54 +0000 (01:26 +0000)
committerEric Covener <covener@apache.org>
Wed, 13 Mar 2024 01:26:54 +0000 (01:26 +0000)
Submitted By: ylavic, covener

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1916267 13f79535-47bb-0310-9956-ffa450edef68

changes-entries/start-threads.txt [new file with mode: 0644]
server/mpm/event/event.c
server/mpm/worker/worker.c

diff --git a/changes-entries/start-threads.txt b/changes-entries/start-threads.txt
new file mode 100644 (file)
index 0000000..a3fa5e9
--- /dev/null
@@ -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]
index 831d3c2516107f44bd43ced589b840e888f921e9..3841142c603a6dbb4e9d13802498d4597650cf04 100644 (file)
@@ -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++;
index aebbd0b6f4b090176ab4f8dc713f46d2134c3b8e..ecf38aedfc96b068c6e6ed301c65e5eef6350343 100644 (file)
@@ -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++;