mpm_common.c revision 7c7372abe2484e7fcf81937b93496d1246e5b816
2N/A/* ====================================================================
2N/A * The Apache Software License, Version 1.1
2N/A *
2N/A * Copyright (c) 2000 The Apache Software Foundation. All rights
2N/A * reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * 2. Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * 3. The end-user documentation included with the redistribution,
2N/A * if any, must include the following acknowledgment:
2790N/A * "This product includes software developed by the
2790N/A * Apache Software Foundation (http://www.apache.org/)."
5337N/A * Alternately, this acknowledgment may appear in the software itself,
2N/A * if and wherever such third-party acknowledgments normally appear.
2N/A *
2N/A * 4. The names "Apache" and "Apache Software Foundation" must
2N/A * not be used to endorse or promote products derived from this
2N/A * software without prior written permission. For written
2N/A * permission, please contact apache@apache.org.
3817N/A *
2N/A * 5. Products derived from this software may not be called "Apache",
2N/A * nor may "Apache" appear in their name, without prior written
2N/A * permission of the Apache Software Foundation.
59N/A *
59N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
2N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1470N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1470N/A * SUCH DAMAGE.
1470N/A * ====================================================================
1470N/A *
181N/A * This software consists of voluntary contributions made by many
26N/A * individuals on behalf of the Apache Software Foundation. For more
4811N/A * information on the Apache Software Foundation, please see
4811N/A * <http://www.apache.org/>.
4811N/A *
3739N/A * Portions of this software are based upon public domain software
3739N/A * originally written at the National Center for Supercomputing Applications,
3739N/A * University of Illinois, Urbana-Champaign.
3739N/A */
3739N/A
3739N/A/* The purpose of this file is to store the code that MOST mpm's will need
3739N/A * this does not mean a function only goes into this file if every MPM needs
3739N/A * it. It means that if a function is needed by more than one MPM, and
3817N/A * future maintenance would be served by making the code common, then the
3817N/A * function belongs here.
26N/A *
26N/A * This is going in src/main because it is not platform specific, it is
26N/A * specific to multi-process servers, but NOT to Unix. Which is why it
26N/A * does not belong in src/os/unix
26N/A */
26N/A
26N/A#include "apr.h"
700N/A#include "apr_thread_proc.h"
700N/A#include "apr_signal.h"
26N/A
26N/A#include "httpd.h"
26N/A#include "http_config.h"
1498N/A#include "http_log.h"
1498N/A#include "http_main.h"
26N/A#include "mpm.h"
1498N/A#include "mpm_common.h"
151N/A#include "ap_mpm.h"
206N/A
26N/A#ifdef HAVE_PWD_H
26N/A#include <pwd.h>
26N/A#endif
26N/A#ifdef HAVE_GRP_H
26N/A#include <grp.h>
3998N/A#endif
2818N/A
2830N/A#ifdef MPM_NEEDS_RECLAIM_CHILD_PROCESSES
3127N/Avoid ap_reclaim_child_processes(int terminate)
3998N/A{
26N/A int i;
3294N/A long int waittime = 1024 * 16; /* in usecs */
26N/A apr_status_t waitret;
2N/A int tries;
4747N/A int not_dead_yet;
4437N/A int max_daemons = ap_get_max_daemons();
4437N/A
4488N/A MPM_SYNC_CHILD_TABLE();
4488N/A
4437N/A for (tries = terminate ? 4 : 1; tries <= 9; ++tries) {
4437N/A /* don't want to hold up progress any more than
26N/A * necessary, but we need to allow children a few moments to exit.
26N/A * Set delay with an exponential backoff.
26N/A */
26N/A waittime = waittime * 4;
883N/A apr_sleep(waittime);
26N/A
26N/A /* now see who is done */
26N/A not_dead_yet = 0;
26N/A for (i = 0; i < max_daemons; ++i) {
1043N/A pid_t pid = MPM_CHILD_PID(i);
4953N/A apr_proc_t proc;
4953N/A
586N/A if (pid == 0)
26N/A continue;
5329N/A
5329N/A proc.pid = pid;
93N/A waitret = apr_proc_wait(&proc, APR_NOWAIT);
5329N/A if (waitret != APR_CHILD_NOTDONE) {
5329N/A MPM_NOTE_CHILD_KILLED(i);
166N/A continue;
26N/A }
379N/A ++not_dead_yet;
379N/A switch (tries) {
1498N/A case 1: /* 16ms */
5123N/A case 2: /* 82ms */
1498N/A break;
4518N/A case 3: /* 344ms */
4518N/A case 4: /* 16ms */
2899N/A case 5: /* 82ms */
5349N/A case 6: /* 344ms */
5349N/A case 7: /* 1.4sec */
5349N/A /* ok, now it's being annoying */
5349N/A ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING,
5349N/A 0, ap_server_conf,
2236N/A "child process %ld still did not exit, sending a SIGTERM",
2818N/A (long)pid);
4910N/A kill(pid, SIGTERM);
2N/A break;
26N/A case 8: /* 6 sec */
26N/A /* die child scum */
181N/A ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
181N/A 0, ap_server_conf,
4353N/A "child process %ld still did not exit, sending a SIGKILL",
4353N/A (long)pid);
4353N/A#ifndef BEOS
4488N/A kill(pid, SIGKILL);
99N/A#else
59N/A /* sending a SIGKILL kills the entire team on BeOS, and as
12N/A * httpd thread is part of that team it removes any chance
30N/A * of ever doing a restart. To counter this I'm changing to
4811N/A * use a kinder, gentler way of killing a specific thread
4811N/A * that is just as effective.
4811N/A */
1256N/A kill_thread(pid);
1256N/A#endif
1256N/A break;
2818N/A case 9: /* 14 sec */
1256N/A /* gave it our best shot, but alas... If this really
1256N/A * is a child we are trying to kill and it really hasn't
1256N/A * exited, we will likely fail to bind to the port
1256N/A * after the restart.
1256N/A */
1256N/A ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
1256N/A 0, ap_server_conf,
1256N/A "could not make child process %ld exit, "
1256N/A "attempting to continue anyway", (long)pid);
2818N/A break;
1256N/A }
1256N/A }
1256N/A apr_proc_other_child_check();
1256N/A if (!not_dead_yet) {
1256N/A /* nothing left to wait for */
1256N/A break;
1256N/A }
3109N/A }
3109N/A}
3109N/A#endif /* NEED_RECLAIM_CHILD_PROCESSES */
3109N/A
3109N/A/* number of calls to wait_or_timeout between writable probes */
3109N/A#ifndef INTERVAL_OF_WRITABLE_PROBES
3109N/A#define INTERVAL_OF_WRITABLE_PROBES 10
3109N/A#endif
3109N/Astatic int wait_or_timeout_counter;
3109N/A
3109N/Avoid ap_wait_or_timeout(apr_wait_t *status, apr_proc_t *ret, apr_pool_t *p)
3109N/A{
3109N/A apr_status_t rv;
3109N/A
3109N/A ++wait_or_timeout_counter;
3109N/A if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
3109N/A wait_or_timeout_counter = 0;
1256N/A#if APR_HAS_OTHER_CHILD
1256N/A apr_proc_probe_writable_fds();
1256N/A#endif
3109N/A }
4811N/A rv = apr_proc_wait_all_procs(ret, status, APR_NOWAIT, p);
1256N/A if (APR_STATUS_IS_EINTR(rv)) {
26N/A ret->pid = -1;
26N/A return;
1256N/A }
2N/A if (APR_STATUS_IS_CHILD_DONE(rv)) {
26N/A return;
1256N/A }
1256N/A#ifdef NEED_WAITPID
185N/A if ((ret = reap_children(status)) > 0) {
2N/A return;
255N/A }
145N/A#endif
7N/A apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
26N/A ret->pid = -1;
26N/A return;
38N/A}
26N/A
197N/Avoid ap_process_child_status(apr_proc_t *pid, apr_wait_t status)
197N/A{
197N/A int signum = WTERMSIG(status);
197N/A const char *sigdesc = apr_signal_get_description(signum);
197N/A
26N/A /* Child died... if it died due to a fatal error,
30N/A * we should simply bail out.
26N/A */
46N/A if ((WIFEXITED(status)) &&
46N/A WEXITSTATUS(status) == APEXIT_CHILDFATAL) {
46N/A ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf,
64N/A "Child %ld returned a Fatal error..." APR_EOL_STR
64N/A "Apache is exiting!",
26N/A (long)pid->pid);
46N/A exit(APEXIT_CHILDFATAL);
46N/A }
46N/A
2N/A if (WIFSIGNALED(status)) {
1256N/A switch (signum) {
1256N/A case SIGTERM:
1256N/A case SIGHUP:
1256N/A case SIGWINCH:
1256N/A case SIGKILL:
2818N/A break;
1256N/A default:
1256N/A#ifdef WCOREDUMP
1256N/A if (WCOREDUMP(status)) {
1256N/A ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
1256N/A 0, ap_server_conf,
2818N/A "child pid %ld exit signal %s (%d), "
2818N/A "possible coredump in %s",
1256N/A (long)pid->pid, sigdesc, signum,
2236N/A ap_coredump_dir);
2236N/A }
1256N/A else
2818N/A#endif
3739N/A {
1256N/A ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE,
1256N/A 0, ap_server_conf,
1256N/A "child pid %ld exit signal %s (%d)",
1256N/A (long)pid->pid, sigdesc, signum);
1256N/A }
1256N/A }
1256N/A }
1256N/A}
3817N/A
1256N/A#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF)
1256N/Avoid ap_sock_disable_nagle(apr_socket_t *s)
1256N/A{
1256N/A /* The Nagle algorithm says that we should delay sending partial
1256N/A * packets in hopes of getting more data. We don't want to do
2818N/A * this; we are not telnet. There are bad interactions between
3449N/A * persistent connections and Nagle's algorithm that have very severe
3449N/A * performance penalties. (Failing to disable Nagle is not much of a
3449N/A * problem with simple HTTP.)
3449N/A *
3449N/A * In spite of these problems, failure here is not a shooting offense.
3449N/A */
3449N/A apr_status_t status = apr_setsocketopt(s, APR_TCP_NODELAY, 1);
1934N/A
3739N/A if (status != APR_SUCCESS) {
2818N/A ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,
1256N/A "setsockopt: (TCP_NODELAY)");
1256N/A }
1256N/A}
1413N/A#endif
1413N/A
1413N/AAP_DECLARE(uid_t) ap_uname2id(const char *name)
1413N/A{
3739N/A struct passwd *ent;
1413N/A
1413N/A if (name[0] == '#')
1413N/A return (atoi(&name[1]));
1413N/A
1413N/A if (!(ent = getpwnam(name))) { ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad user name %s", ap_server_argv0, name);
1256N/A exit(1);
1256N/A }
1256N/A return (ent->pw_uid);
1256N/A}
3817N/A
1256N/AAP_DECLARE(gid_t) ap_gname2id(const char *name)
1256N/A{
1256N/A struct group *ent;
1256N/A
1256N/A if (name[0] == '#')
3449N/A return (atoi(&name[1]));
3449N/A
1934N/A if (!(ent = getgrnam(name))) {
3739N/A ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad group name %s", ap_server_argv0, name); exit(1);
3449N/A }
1256N/A return (ent->gr_gid);
1256N/A}
1256N/A
3109N/A#ifndef HAVE_INITGROUPS
3109N/Aint initgroups(const char *name, gid_t basegid)
3109N/A{
3109N/A#if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32)
3109N/A/* QNX, MPE and BeOS do not appear to support supplementary groups. */
3109N/A return 0;
3109N/A#else /* ndef QNX */
3109N/A gid_t groups[NGROUPS_MAX];
3109N/A struct group *g;
3109N/A int index = 0;
3109N/A
3109N/A setgrent();
3109N/A
3739N/A groups[index++] = basegid;
3109N/A
3109N/A while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
3109N/A if (g->gr_gid != basegid) {
3109N/A char **names;
3109N/A
3109N/A for (names = g->gr_mem; *names != NULL; ++names)
3109N/A if (!strcmp(*names, name))
3109N/A groups[index++] = g->gr_gid;
3109N/A }
3109N/A
3109N/A endgrent();
3817N/A
3109N/A return setgroups(index, groups);
3109N/A#endif /* def QNX */
3109N/A}
3109N/A#endif /* def NEED_INITGROUPS */
3109N/A
3109N/A
3109N/A