worker.c revision a94a0f8604bc182459825c18b5574236ea2673c7
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/* Licensed to the Apache Software Foundation (ASF) under one or more
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * contributor license agreements. See the NOTICE file distributed with
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * this work for additional information regarding copyright ownership.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * The ASF licenses this file to You under the Apache License, Version 2.0
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * (the "License"); you may not use this file except in compliance with
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * the License. You may obtain a copy of the License at
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * Unless required by applicable law or agreed to in writing, software
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * distributed under the License is distributed on an "AS IS" BASIS,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * See the License for the specific language governing permissions and
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * limitations under the License.
b26e4ced91d0ac0eabdce1c505228ccafc65a23fDavid Herrmann/* The purpose of this MPM is to fix the design flaws in the threaded
b26e4ced91d0ac0eabdce1c505228ccafc65a23fDavid Herrmann * model. Because of the way that pthreads and mutex locks interact,
b26e4ced91d0ac0eabdce1c505228ccafc65a23fDavid Herrmann * it is basically impossible to cleanly gracefully shutdown a child
b26e4ced91d0ac0eabdce1c505228ccafc65a23fDavid Herrmann * process if multiple threads are all blocked in accept. This model
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * fixes those problems.
fa9d4be3f1f4a792b2f3624c2a08fe9cc6ce6e54Zbigniew Jędrzejewski-Szmek#include <sys/processor.h> /* for bindprocessor() */
fa9d4be3f1f4a792b2f3624c2a08fe9cc6ce6e54Zbigniew Jędrzejewski-Szmek#error The Worker MPM requires APR threads, but they are unavailable.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/* Limit on the total --- clients will be locked out if more servers than
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * this are needed. It is intended solely to keep the server from crashing
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * when things get out of hand.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * We keep a hard maximum number of servers, for two reasons --- first off,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * in case something goes seriously wrong, we want to stop the fork bomb
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * short of actually crashing the machine we're running on by filling some
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * kernel table. Secondly, it keeps the size of the scoreboard file small
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * enough that we can read the whole thing without worrying too much about
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * the overhead.
42a9de1c2513aa348df369080cdd941ef4ab00abMartin Pitt/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * some sort of compile-time limit to help catch typos.
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer/* Limit on the threads per process. Clients will be locked out if more than
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt * this * server_limit are needed.
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt * We keep this for one reason it keeps the size of the scoreboard file small
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt * enough that we can read the whole thing without worrying too much about
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * the overhead.
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt * some sort of compile-time limit to help catch typos.
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pitt * Actual definitions of config globals
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pittstatic int threads_per_child = 0; /* Worker threads per child */
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pittstatic int max_workers = 0;
c5b7838ddeae1fcd5c613ea15f04918b945823e5Martin Pittstatic int server_limit = 0;
51c0c2869845a058268d54c3111d55d0dd485704Peter Huttererstatic int dying = 0;
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/* data retained by worker across load/unload of the module
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * allocated on first call to pre-config hook; located on
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * subsequent calls to pre-config hook
aa75494ad5cdf7bede947212ad8c8356d78580faMario Limonciello int volatile is_graceful; /* set from signal handler */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * The max child slot ever assigned, preserved across restarts. Necessary
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * We use this value to optimize routines that have to scan the entire
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * scoreboard.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * idle_spawn_rate is the number of children that will be spawned on the
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * next maintenance cycle if there aren't enough idle servers. It is
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * without the need to spawn.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/* The structure used to pass unique initialization info to each thread */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieverstypedef struct {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/* Structure used to pass information to the thread responsible for
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * creating the rest of the threads.
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterertypedef struct {
fc1ae82cae69d8dbbd9e7a31938810a486fac782Hans de Goede#define ID_FROM_CHILD_THREAD(c, t) ((c * thread_limit) + t)
fc1ae82cae69d8dbbd9e7a31938810a486fac782Hans de Goede/* The worker MPM respects a couple of runtime flags that can aid
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * in debugging. Setting the -DNO_DETACH flag will prevent the root process
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * from detaching from its controlling terminal. Additionally, setting
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * the -DONE_PROCESS flag (which implies -DNO_DETACH) will get you the
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * child_main loop running in the process which originally started up.
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * This gives you a pretty nice debugging environment. (You'll get a SIGHUP
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * early in standalone_main; just continue through. This is the server
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * trying to kill off any child processes which it might have lying
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * around --- Apache doesn't keep track of their pids, it just sends
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * SIGHUP to the process group, ignoring it in the root process.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * Continue through and you'll be fine.).
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic int one_process = 0;
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic apr_pool_t *pconf; /* Pool for config stuff */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic apr_pool_t *pchild; /* Pool for httpd child stuff */
42a9de1c2513aa348df369080cdd941ef4ab00abMartin Pittstatic pid_t ap_my_pid; /* Linux getpid() doesn't work except in main
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers thread. Use this instead */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/* Locks for accept serialization */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers#define SAFE_ACCEPT(stmt) (child_listen->next ? (stmt) : APR_SUCCESS)
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer/* The LISTENER_SIGNAL signal will be sent from the main thread to the
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * listener thread to wake it up for graceful termination (what a child
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * process from an old generation does when the admin does "apachectl
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * graceful"). This signal will be blocked in all threads of a child
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * process except for the listener thread.
aba248ee6b1eb10baf3d89eca2ad7569459af6abHans de Goede/* The WORKER_SIGNAL signal will be sent from the main thread to the
aba248ee6b1eb10baf3d89eca2ad7569459af6abHans de Goede * worker threads during an ungraceful restart or shutdown.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * This ensures that on systems (i.e., Linux) where closing the worker
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * socket doesn't awake the worker thread when it is polling on the socket
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * (especially in apr_wait_for_io_or_timeout() when handling
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * Keep-Alive connections), close_worker_sockets() and join_workers()
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * still function in timely manner and allow ungraceful shutdowns to
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * proceed to completion. Otherwise join_workers() doesn't return
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * before the main process decides the child process is non-responsive
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * and sends a SIGKILL.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/* An array of socket descriptors in use by each thread used to
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * perform a non-graceful (forced) shutdown of the server. */
0e336347dedc3577214484ec3d97f0f799dd81fdMartin Pittstatic void close_worker_sockets(void)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers for (i = 0; i < threads_per_child; i++) {
24119cf10c7ed58a8fc0851745149dcc6dd5757fStefan Brünsstatic void wakeup_listener(void)
6e675e278c04bd5662914888a2b3cf856d743659Chen-Han Hsiao (Stanley) /* XXX there is an obscure path that this doesn't handle perfectly:
d946bb53f94713241004810de92cc37f1e19c2d2Martin Pitt * right after listener thread is created but before
1f6d36f267186c0e3184bab4c7eca48481c6faabHui Wang * listener_os_thread is set, the first worker thread hits an
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * error and starts graceful termination
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* unblock the listener if it's waiting for a worker */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * we should just be able to "kill(ap_my_pid, LISTENER_SIGNAL)" on all
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * platforms and wake up the listener thread since it is the only thread
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * with SIGHUP unblocked, but that doesn't work on Linux
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers pthread_kill(*listener_os_thread, LISTENER_SIGNAL);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* in case we weren't called from the listener thread, wake up the
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * listener thread
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* for ungraceful termination, let the workers exit now;
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * for graceful termination, the listener thread will notify the
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * workers to exit once it has stopped accepting new connections
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers close_worker_sockets(); /* forcefully kill all current connections */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic int worker_query(int query_code, int *result, apr_status_t *rv)
0787758d26337ec897d9553fe962678fbf0a0962Zbigniew Jędrzejewski-Szmek case AP_MPMQ_MIN_SPARE_DAEMONS:
0787758d26337ec897d9553fe962678fbf0a0962Zbigniew Jędrzejewski-Szmek case AP_MPMQ_MIN_SPARE_THREADS:
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieversstatic void worker_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers if (childnum != -1) { /* child had a scoreboard slot? */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->parent[childnum].generation,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieversstatic void worker_note_child_started(int slot, pid_t pid)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers retained->my_generation, slot, MPM_CHILD_STARTED);
51c0c2869845a058268d54c3111d55d0dd485704Peter Huttererstatic void worker_note_child_lost_slot(int slot, pid_t newpid)
e7627e14dc883ab0ad73c931e4ff0caa1cad6860Zbigniew Jędrzejewski-Szmek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00263)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
e7627e14dc883ab0ad73c931e4ff0caa1cad6860Zbigniew Jędrzejewski-Szmek ap_scoreboard_image->parent[slot].quiescing ?
e7627e14dc883ab0ad73c931e4ff0caa1cad6860Zbigniew Jędrzejewski-Szmek ap_run_child_status(ap_server_conf,
e7627e14dc883ab0ad73c931e4ff0caa1cad6860Zbigniew Jędrzejewski-Szmek ap_scoreboard_image->parent[slot].generation,
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer /* Don't forget about this exiting child process, or we
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * won't be able to kill it if it doesn't exit by the
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * time the server is shut down.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieversstatic const char *worker_get_name(void)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers return "worker";
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer/* a clean exit from a child with proper cleanup */
51c0c2869845a058268d54c3111d55d0dd485704Peter Huttererstatic void clean_child_exit(int code) __attribute__ ((noreturn));
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer worker_note_child_killed(/* slot */ 0, 0, 0);
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/*****************************************************************
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * Connection structures and accounting...
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/* volatile because they're updated from a signal handler */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieversstatic int volatile shutdown_pending;
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sieversstatic int volatile restart_pending;
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * functions to initiate shutdown or restart without relying on signals.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * Previously this was initiated in sig_term() and restart() signal handlers,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * but we want to be able to start a shutdown/restart from other sources --
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * e.g. on Win32, from the service manager. Now the service manager can
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * call ap_start_shutdown() or ap_start_restart() as appropriate. Note that
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * these functions can also be called by the child processes, since global
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * variables are no longer used to pass on the required action to the parent.
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * These should only be called from the parent process itself, since the
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * parent process will use the shutdown_pending and restart_pending variables
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * to determine whether to shutdown or restart. The child process should
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * call signal_parent() directly to tell the parent to die -- this will
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * cause neither of those variable to be set, which the parent will
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * assume means something serious is wrong (which it will be, for the
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * child to force an exit) and so do an exit anyway.
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt /* Um, is this _probably_ not an error, if the user has
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * tried to do a shutdown twice quickly, so we won't
82cd413782cca6de3088c2705f839ff31abec7f9Martin Pitt * worry about reporting it.
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer/* do a graceful restart if graceful == 1 */
bbea73316f12896364e8e8eef82259280063eda0Martin Pitt /* Probably not an error - don't bother reporting it */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic void set_signals(void)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00264)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "sigaction(SIGTERM)");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00265)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00266)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "sigaction(SIGINT)");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00267)
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer "sigaction(SIGXCPU)");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* For systems following the LFS standard, ignoring SIGXFSZ allows
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * a write() beyond the 2GB limit to fail gracefully with E2BIG
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * rather than terminate the process. */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00268)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "sigaction(SIGXFSZ)");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00269)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "sigaction(SIGPIPE)");
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * processing one */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00270)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "sigaction(SIGHUP)");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00271)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers#endif /* SIGXCPU */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers#endif /* SIGXFSZ */
ef686ae230c55124e3efdc7d756fb1931e10aef4Marc Schmitzer#endif /* SIGHUP */
ef686ae230c55124e3efdc7d756fb1931e10aef4Marc Schmitzer#endif /* AP_SIG_GRACEFUL */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer#endif /* AP_SIG_GRACEFUL_STOP */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers#endif /* SIGPIPE */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/*****************************************************************
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * Here follows a long bunch of generic server bookkeeping stuff...
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers/*****************************************************************
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * Child process main loop.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sieversstatic void process_socket(apr_thread_t *thd, apr_pool_t *p, apr_socket_t *sock,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers int my_thread_num, apr_bucket_alloc_t *bucket_alloc)
5d7afd82a159f8a781594f5538b7af35dbb9ceccBastien Nocera long conn_id = ID_FROM_CHILD_THREAD(my_child_num, my_thread_num);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_create_sb_handle(&sbh, p, my_child_num, my_thread_num);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers current_conn = ap_run_create_connection(p, ap_server_conf, sock,
71ed2d38711e345f22e2200bc7bb156aed98972aBastien Nocera/* requests_this_child has gone to zero or below. See if the admin coded
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "MaxConnectionsPerChild 0", and keep going in that case. Doing it this way
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer simplifies the hot path in worker_thread */
d258d4967eb24122c2b1014d4e873f61b633f1d2Martin Pitt /* XXX If specifying SIG_IGN is guaranteed to unblock a syscall,
d258d4967eb24122c2b1014d4e873f61b633f1d2Martin Pitt * then we don't need this goofy function.
d258d4967eb24122c2b1014d4e873f61b633f1d2Martin Pittstatic void accept_mutex_error(const char *func, apr_status_t rv, int process_slot)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers if (ap_scoreboard_image->parent[process_slot].generation !=
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->global->running_generation) {
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pitt level = APLOG_DEBUG; /* common to get these at restart time */
ce39bb6909578017aa10031638e724e038f0b859Kay Sievers || ((requests_this_child == ap_max_requests_per_child)
ce39bb6909578017aa10031638e724e038f0b859Kay Sievers ap_log_error(APLOG_MARK, level, rv, ap_server_conf, APLOGNO(00272)
ce39bb6909578017aa10031638e724e038f0b859Kay Sievers "apr_proc_mutex_%s failed "
ce39bb6909578017aa10031638e724e038f0b859Kay Sievers "before this child process served any requests.",
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pitt ap_log_error(APLOG_MARK, level, rv, ap_server_conf, APLOGNO(00273)
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pitt "apr_proc_mutex_%s failed. Attempting to "
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pittstatic void * APR_THREAD_FUNC listener_thread(apr_thread_t *thd, void * dummy)
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pitt apr_pool_t *ptrans = NULL; /* Pool for per-transaction stuff */
1b6bce89b3383904d0dab619dd38bff673f7286eMartin Pitt rv = apr_pollset_create(&pollset, num_listensocks, tpool, 0);
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
bf89b99c5a39115112c2eda4c2103e2db54988d2Martin Pitt "Couldn't create pollset in thread;"
bf89b99c5a39115112c2eda4c2103e2db54988d2Martin Pitt " check system or user limits");
bf89b99c5a39115112c2eda4c2103e2db54988d2Martin Pitt /* let the parent decide how bad this really is */
bf89b99c5a39115112c2eda4c2103e2db54988d2Martin Pitt for (lr = child_listen; lr != NULL; lr = lr->next) {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "Couldn't create add listener to pollset;"
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers " check system or user limits");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* let the parent decide how bad this really is */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* Unblock the signal used to wake this thread up, and set a handler for
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer apr_signal(LISTENER_SIGNAL, dummy_signal_handler);
19c98efe17155734698c12482cd40834a89f0e48Lennart Poettering /* TODO: Switch to a system where threads reuse the results from earlier
19c98efe17155734698c12482cd40834a89f0e48Lennart Poettering poll calls - manoj */
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt /* TODO: requests_this_child should be synchronized - aaron */
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt /* the following pops a recycled ptrans pool off a stack
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt * if there is one, in addition to reserving a worker thread
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt rv = ap_queue_info_wait_for_idler(worker_queue_info,
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt break; /* we've been signaled to die now */
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt "apr_queue_info_wait failed. Attempting to "
792d616391159f4fa992341bf264c9407e480c6dMartin Pitt " shutdown process gracefully.");
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer /* We've already decremented the idle worker count inside
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * ap_queue_info_wait_for_idler. */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers if ((rv = SAFE_ACCEPT(apr_proc_mutex_lock(child_mutex)))
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers break; /* skip the lock release */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* Only one listener, so skip the poll */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer rv = apr_pollset_poll(pollset, -1, &numdesc, &pdesc);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* apr_pollset_poll() will only return errors in catastrophic
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * circumstances. Let's try exiting gracefully, for now. */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "apr_pollset_poll: (listen)");
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* We can always use pdesc[0], but sockets at position N
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * could end up completely starved of attention in a very
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * busy server. Therefore, we round-robin across the
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * returned set of descriptors. While it is possible that
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * the returned set of descriptors might flip around and
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * continue to starve some sockets, we happen to know the
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * internal pollset implementation retains ordering
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * stability of the sockets. Thus, the round-robin should
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * ensure that a socket will eventually be serviced.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* Grab a listener record from the client_data of the poll
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * descriptor, and advance our saved index to round-robin
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * the next fetch.
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * ### hmm... this descriptor might have POLLERR rather
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * ### than POLLIN
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer } /* while */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer /* we can't use a recycled transaction pool this time.
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * create a new transaction pool */
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers apr_allocator_max_free_set(allocator, ap_max_mem_free);
288026bda90245ae6523441ce308d58ad1caefc8Maxim Mikityanskiy apr_pool_create_ex(&ptrans, pconf, NULL, allocator);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* later we trash rv and rely on csd to indicate success/failure */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* E[NM]FILE, ENOMEM, etc */
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(child_mutex)))
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* trash the connection; we couldn't queue the connected
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * socket to a worker
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "ap_queue_push failed");
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(child_mutex)))
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers if (ap_scoreboard_image->parent[process_slot].generation !=
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->global->running_generation) {
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers level = APLOG_DEBUG; /* common to get these at restart time */
d946bb53f94713241004810de92cc37f1e19c2d2Martin Pitt ap_log_error(APLOG_MARK, level, rv, ap_server_conf, APLOGNO(00274)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "apr_proc_mutex_unlock failed. Attempting to "
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers "shutdown process gracefully.");
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->parent[process_slot].quiescing = 1;
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* wake up the main thread */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers/* XXX For ungraceful termination/restart, we definitely don't want to
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * wait for active connections to finish but we may want to wait
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * for idle workers to get out of the queue code and release mutexes,
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * since those mutexes are cleaned up pretty soon and some systems
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * may not react favorably (i.e., segfault) if operations are attempted
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers * on cleaned-up mutexes.
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sieversstatic void * APR_THREAD_FUNC worker_thread(apr_thread_t *thd, void * dummy)
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers apr_pool_t *ptrans; /* Pool for per-transaction stuff */
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->servers[process_slot][thread_slot].pid = ap_my_pid;
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->servers[process_slot][thread_slot].tid = apr_os_thread_current();
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_scoreboard_image->servers[process_slot][thread_slot].generation = retained->my_generation;
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_STARTING, NULL);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers apr_signal(WORKER_SIGNAL, dummy_signal_handler);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers rv = ap_queue_info_set_idle(worker_queue_info, last_ptrans);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "ap_queue_info_set_idle failed. Attempting to "
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "shutdown process gracefully.");
9e3dbf6b2b99d0e16989d9cedb458729db5a60c3Zbigniew Jędrzejewski-Szmek ap_update_child_status_from_indexes(process_slot, thread_slot, SERVER_READY, NULL);
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers /* We get APR_EOF during a graceful shutdown once all the connections
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers * accepted by this server process have been handled.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* We get APR_EINTR whenever ap_queue_pop() has been interrupted
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * from an explicit call to ap_queue_interrupt_all(). This allows
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * us to unblock threads stuck in ap_queue_pop() when a shutdown
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * is pending.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * If workers_may_exit is set and this is ungraceful termination/
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * restart, we are bound to get an error on some systems (e.g.,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * AIX, which sanity-checks mutex operations) since the queue
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * may have already been cleaned up. Don't log the "error" if
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * workers_may_exit is set.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* We got some other error. */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "ap_queue_pop failed");
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer bucket_alloc = apr_bucket_alloc_create(ptrans);
6e1452d6f015ebca6801e497d12bc6c7c114386dMartin Pitt process_socket(thd, ptrans, csd, process_slot, thread_slot, bucket_alloc);
6e1452d6f015ebca6801e497d12bc6c7c114386dMartin Pitt ap_update_child_status_from_indexes(process_slot, thread_slot,
6e1452d6f015ebca6801e497d12bc6c7c114386dMartin Pitt (dying) ? SERVER_DEAD : SERVER_GRACEFUL, (request_rec *) NULL);
51c0c2869845a058268d54c3111d55d0dd485704Peter Huttererstatic void create_listener_thread(thread_starter *ts)
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer my_info = (proc_info *)ap_malloc(sizeof(proc_info));
dfa2ea215df5f1e78084de862a54c0f1f321a13aRaudi my_info->tid = -1; /* listener thread doesn't have a thread slot */
dfa2ea215df5f1e78084de862a54c0f1f321a13aRaudi rv = apr_thread_create(&ts->listener, thread_attr, listener_thread,
15f392394e75ffb7f318920008fd1bbe4e82b488Scott Thrasher ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, APLOGNO(00275)
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer "apr_thread_create: unable to create listener thread");
15f392394e75ffb7f318920008fd1bbe4e82b488Scott Thrasher /* let the parent decide how bad this really is */
15f392394e75ffb7f318920008fd1bbe4e82b488Scott Thrasher apr_os_thread_get(&listener_os_thread, ts->listener);
af97ebf2dd8a2ec0d46f2924e35a63a55523c133Gavin Li/* XXX under some circumstances not understood, children can get stuck
af97ebf2dd8a2ec0d46f2924e35a63a55523c133Gavin Li * in start_threads forever trying to take over slots which will
af97ebf2dd8a2ec0d46f2924e35a63a55523c133Gavin Li * never be cleaned up; for now there is an APLOG_DEBUG message issued
af97ebf2dd8a2ec0d46f2924e35a63a55523c133Gavin Li * every so often when this condition occurs
af97ebf2dd8a2ec0d46f2924e35a63a55523c133Gavin Listatic void * APR_THREAD_FUNC start_threads(apr_thread_t *thd, void *dummy)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* We must create the fd queues before we start up the listener
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * and worker threads. */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers worker_queue = apr_pcalloc(pchild, sizeof(*worker_queue));
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer rv = ap_queue_init(worker_queue, threads_per_child, pchild);
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers "ap_queue_init() failed");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers rv = ap_queue_info_create(&worker_queue_info, pchild,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "ap_queue_info_create() failed");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers worker_sockets = apr_pcalloc(pchild, threads_per_child
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer /* threads_per_child does not include the listener thread */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer for (i = 0; i < threads_per_child; i++) {
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer int status = ap_scoreboard_image->servers[child_num_arg][i].status;
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer if (status != SERVER_GRACEFUL && status != SERVER_DEAD) {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers my_info = (proc_info *)ap_malloc(sizeof(proc_info));
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer /* We are creating threads right now */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_update_child_status_from_indexes(my_child_num, i,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* We let each thread update its own scoreboard entry. This is
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * done because it lets us deal with tid better.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers rv = apr_thread_create(&threads[i], thread_attr,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf,
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer "apr_thread_create: unable to create worker thread");
7b36bf82c4deeadef6d914cef750b4a51ff2ed48Martin Pitt /* let the parent decide how bad this really is */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* Start the listener only when there are workers available */
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers if (start_thread_may_exit || threads_created == threads_per_child) {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* wait for previous generation to clean up an entry */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers if (loops % 120 == 0) { /* every couple of minutes */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer if (prev_threads_created == threads_created) {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "slots very quickly (%d of %d)",
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* What state should this child_main process be listed as in the
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * scoreboard...?
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * ap_update_child_status_from_indexes(my_child_num, i, SERVER_STARTING,
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * (request_rec *) NULL);
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * This state should be listed separately in the scoreboard, in some kind
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * of process_status, not mixed in with the worker threads' status.
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * "life_status" is almost right, but it's in the worker's structure, and
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers * the name could be clearer. gla
176cceb051fd9537239e5e8a43f80a33d06fe3b8Zbigniew Jędrzejewski-Szmekstatic void join_workers(apr_thread_t *listener, apr_thread_t **threads,
bc9cdba5ddf78d0ecb5c64f55621bb2f474ea280Jose Ignacio Naranjo /* deal with a rare timing window which affects waking up the
bc9cdba5ddf78d0ecb5c64f55621bb2f474ea280Jose Ignacio Naranjo * listener thread... if the signal sent to the listener thread
2a61aaac6607d998e981481c34ae06e3e3ace4feUnai Uribarri * is delivered between the time it verifies that the
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * listener_may_exit flag is clear and the time it enters a
2a61aaac6607d998e981481c34ae06e3e3ace4feUnai Uribarri * blocking syscall, the signal didn't do any good... work around
2a61aaac6607d998e981481c34ae06e3e3ace4feUnai Uribarri * that by sleeping briefly and sending it again
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers /* listener not dead yet */
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00276)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "the listener thread didn't exit");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00277)
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers "apr_thread_join: unable to join listener thread");
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers for (i = 0; i < threads_per_child; i++) {
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers if (threads[i]) { /* if we ever created this thread */
aedc2eddd16e48d468e6ad0aea2caf00c7d37365Kay Sievers apr_os_thread_get(&worker_os_thread, threads[i]);
0c959b39175b126fdb70ae00de37ca6d9c8ca3a1Kay Sievers ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00278)
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers "apr_thread_join: unable to join worker "
51c0c2869845a058268d54c3111d55d0dd485704Peter Huttererstatic void join_start_thread(apr_thread_t *start_thread_id)
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer start_thread_may_exit = 1; /* tell it to give up in case it is still
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * trying to take over slots from a
51c0c2869845a058268d54c3111d55d0dd485704Peter Hutterer * previous generation
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers rv = apr_thread_join(&thread_rv, start_thread_id);
e8193554925a22b63bef0e77b8397b56d63a91ffKay Sievers ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00279)
for (i = 0; i < num_buckets; i++) {
if (i != child_bucket) {
while(lr) {
pchild));
if (ap_max_requests_per_child) {
if (ap_thread_stacksize != 0) {
if (one_process) {
switch(terminate_mode) {
case ST_GRACEFUL:
case ST_UNGRACEFUL:
int pid;
if (one_process) {
set_signals();
child_main(0, 0);
ap_assert(0);
if (!pid) {
#ifdef HAVE_BINDPROCESSOR
ap_assert(0);
int idle_thread_count;
int free_length;
int totally_free_length = 0;
int last_non_dead;
int total_non_dead;
int active_thread_count = 0;
free_length = 0;
idle_thread_count = 0;
total_non_dead = 0;
for (i = 0; i < ap_daemons_limit; ++i) {
int any_dying_threads = 0;
int any_dead_threads = 0;
int child_threads_active = 0;
if (i >= retained->max_daemons_limit && totally_free_length == retained->idle_spawn_rate[child_bucket])
for (j = 0; j < threads_per_child; j++) {
if (all_dead_threads) {
++free_length;
if (!any_dying_threads) {
last_non_dead = i;
if (had_healthy_child) {
if (0 == idle_thread_count) {
"or Min/MaxSpareThreads), "
for (i = 0; i < free_length; ++i) {
int child_slot;
if (child_slot < 0
if (child_slot >= 0) {
for (i = 0; i < threads_per_child; i++)
else if (remaining_children_to_start
for (i = 0; i < num_buckets; i++) {
status) == 0) {
else if (remaining_children_to_start) {
for (i = 0; i < num_buckets; i++) {
for (i = 0; i < num_buckets; i++) {
s, _pconf, 0);
return DONE;
return DONE;
set_signals();
ap_log_common(s);
for (i = 0; i < num_buckets; i++) {
if (!child_fatal) {
return DONE;
} else if (shutdown_pending) {
int active_children;
int index;
for (i = 0; i < num_buckets; i++) {
if (!child_fatal) {
if (ap_graceful_shutdown_timeout) {
shutdown_pending = 0;
active_children = 0;
for (i = 0; i < num_buckets; i++) {
return DONE;
if (one_process) {
return DONE;
/* wake up the children...time to die. But we'll have more soon */
for (i = 0; i < num_buckets; i++) {
for (i = 0; i < num_buckets; i++) {
return OK;
int startup = 0;
int level_flags = 0;
pconf = p;
return DONE;
if (!one_process) {
for (i = 0; i < num_buckets; i++) {
return DONE;
return OK;
if (debug) {
no_detach = 0;
if (!retained) {
#ifdef _SC_NPROCESSORS_ONLN
if (have_so_reuseport) {
return HTTP_INTERNAL_SERVER_ERROR;
for (i = 0; i< num_buckets; i++) {
had_healthy_child = 0;
ap_extended_status = 0;
return OK;
int startup = 0;
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
if (startup) {
return OK;
one_process = 0;
ap_force_set_tz(p);
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
const char *arg)
return err;
return NULL;
return err;
return NULL;
return err;
return NULL;
"Maximum number of worker threads per child process for this run of Apache - Upper limit for ThreadsPerChild"),
{ NULL }