📄 prefork.c
字号:
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. *//* * httpd.c: simple http daemon for answering WWW file requests * * * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) * * 03-06-95 blong * changed server number for child-alone processes to 0 and changed name * of processes * * 03-10-95 blong * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu) * including set group before fork, and call gettime before to fork * to set up libraries. * * 04-14-95 rst / rh * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the * Apache server, and also to have child processes do accept() directly. * * April-July '95 rst * Extensive rework for Apache. *//* TODO: this is a cobbled together prefork MPM example... it should mostly * TODO: behave like apache-1.3... here's a short list of things I think * TODO: need cleaning up still: */#include "apr.h"#include "apr_portable.h"#include "apr_strings.h"#include "apr_thread_proc.h"#include "apr_signal.h"#define APR_WANT_STDIO#define APR_WANT_STRFUNC#include "apr_want.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_SYS_TYPES_H#include <sys/types.h>#endif#define CORE_PRIVATE#include "ap_config.h"#include "httpd.h"#include "mpm_default.h"#include "http_main.h"#include "http_log.h"#include "http_config.h"#include "http_core.h" /* for get_remote_host */#include "http_connection.h"#include "scoreboard.h"#include "ap_mpm.h"#include "unixd.h"#include "mpm_common.h"#include "ap_listen.h"#include "ap_mmn.h"#ifdef HAVE_BSTRING_H#include <bstring.h> /* for IRIX, FD_SET calls bzero() */#endif#ifdef HAVE_TIME_H#include <time.h>#endif#include <signal.h>#include <sys/times.h>/* config globals */int ap_threads_per_child=0; /* Worker threads per child */static int ap_max_requests_per_child=0;static const char *ap_pid_fname=NULL;static apr_lock_t *accept_lock;static const char *ap_lock_fname;static int ap_daemons_to_start=0;static int ap_daemons_min_free=0;static int ap_daemons_max_free=0;static int ap_daemons_limit=0;/* * The max child slot ever assigned, preserved across restarts. Necessary * to deal with MaxClients changes across SIGWINCH restarts. We use this * value to optimize routines that have to scan the entire scoreboard. */int ap_max_daemons_limit = -1;server_rec *ap_server_conf;char ap_coredump_dir[MAX_STRING_LEN];/* *Non*-shared http_main globals... */static apr_socket_t *sd;static fd_set listenfds;static int listenmaxfd;/* one_process --- debugging mode variable; can be set from the command line * with the -X flag. If set, this gets you the child_main loop running * in the process which originally started up (no detach, no make_child), * which is a pretty nice debugging environment. (You'll get a SIGHUP * early in standalone_main; just continue through. This is the server * trying to kill off any child processes which it might have lying * around --- Apache doesn't keep track of their pids, it just sends * SIGHUP to the process group, ignoring it in the root process. * Continue through and you'll be fine.). */static int one_process = 0;static apr_pool_t *pconf; /* Pool for config stuff */static apr_pool_t *pchild; /* Pool for httpd child stuff */static pid_t ap_my_pid; /* it seems silly to call getpid all the time */#ifndef MULTITHREADstatic int my_child_num;#endif#ifdef TPFint tpf_child = 0;char tpf_server_name[INETD_SERVNAME_LENGTH+1];#endif /* TPF */#ifdef GPROF/* * change directory for gprof to plop the gmon.out file * configure in httpd.conf: * GprofDir logs/ -> $ServerRoot/logs/gmon.out * GprofDir logs/% -> $ServerRoot/logs/gprof.$pid/gmon.out */static void chdir_for_gprof(void){ core_server_config *sconf = ap_get_module_config(ap_server_conf->module_config, &core_module); char *dir = sconf->gprof_dir; const char *use_dir; if(dir) { apr_status_t res; char buf[512]; int len = strlen(sconf->gprof_dir) - 1; if(*(dir + len) == '%') { dir[len] = '\0'; apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid()); } use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir); res = apr_dir_make(use_dir, 0755, pconf); if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) { ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, "gprof: error creating directory %s", dir); } } else { use_dir = ap_server_root_relative(pconf, "logs"); } chdir(dir);}#else#define chdir_for_gprof()#endif/* XXX - I don't know if TPF will ever use this module or not, so leave * the ap_check_signals calls in but disable them - manoj */#define ap_check_signals() /* a clean exit from a child with proper cleanup */static void clean_child_exit(int code) __attribute__ ((noreturn));static void clean_child_exit(int code){ if (pchild) { apr_pool_destroy(pchild); } chdir_for_gprof(); exit(code);}static void expand_lock_fname(apr_pool_t *p){ /* XXXX possibly bogus cast */ ap_lock_fname = apr_psprintf(p, "%s.%lu", ap_server_root_relative(p, ap_lock_fname), (unsigned long)getpid());}/* Initialize mutex lock. * Done by each child at its birth */static void accept_mutex_child_init(apr_pool_t *p){ apr_status_t rv; rv = apr_lock_child_init(&accept_lock, ap_lock_fname, p); if (rv) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't do child init for accept mutex"); clean_child_exit(APEXIT_CHILDINIT); }}/* Initialize mutex lock. * Must be safe to call this on a restart. */static void accept_mutex_init(apr_pool_t *p){ apr_status_t rv; expand_lock_fname(p); rv = apr_lock_create(&accept_lock, APR_MUTEX, APR_CROSS_PROCESS, ap_lock_fname, p); if (rv) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't create accept mutex"); exit(APEXIT_INIT); }}static void accept_mutex_on(void){ apr_status_t rv = apr_lock_acquire(accept_lock); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't grab the accept mutex"); exit(APEXIT_CHILDFATAL); }}static void accept_mutex_off(void){ apr_status_t rv = apr_lock_release(accept_lock); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't release the accept mutex"); exit(APEXIT_CHILDFATAL); }}/* On some architectures it's safe to do unserialized accept()s in the single * Listen case. But it's never safe to do it in the case where there's * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT * when it's safe in the single Listen case. */#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)#else#define SAFE_ACCEPT(stmt) do {stmt;} while(0)#endifAP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result){ switch(query_code){ case AP_MPMQ_MAX_DAEMONS: *result = ap_daemons_limit; return APR_SUCCESS; case AP_MPMQ_IS_THREADED: *result = 0; return APR_SUCCESS; case AP_MPMQ_IS_FORKED: *result = 1; return APR_SUCCESS; } return APR_ENOTIMPL;}#if defined(NEED_WAITPID)/* Systems without a real waitpid sometimes lose a child's exit while waiting for another. Search through the scoreboard for missing children. */int reap_children(apr_wait_t *status){ int n, pid; for (n = 0; n < ap_max_daemons_limit; ++n) { ap_sync_scoreboard_image(); if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { ap_update_child_status(AP_CHILD_THREAD_FROM_ID(n), SERVER_DEAD, NULL); /* just mark it as having a successful exit status */ memset(status, 0, sizeof(apr_wait_t)); return(pid); } } return 0;}#endif/* handle all varieties of core dumping signals */static void sig_coredump(int sig){ chdir(ap_coredump_dir); apr_signal(sig, SIG_DFL); kill(getpid(), sig); /* At this point we've got sig blocked, because we're still inside * the signal handler. When we leave the signal handler it will * be unblocked, and we'll take the signal... and coredump or whatever * is appropriate for this particular Unix. In addition the parent * will see the real signal we received -- whereas if we called * abort() here, the parent would only see SIGABRT. */}/***************************************************************** * Connection structures and accounting... */static void just_die(int sig){ clean_child_exit(0);}static int volatile deferred_die;static int volatile usr1_just_die;static void usr1_handler(int sig){ if (usr1_just_die) { just_die(sig); } deferred_die = 1;}/* volatile just in case */static int volatile shutdown_pending;static int volatile restart_pending;static int volatile is_graceful;ap_generation_t volatile ap_my_generation=0;static void sig_term(int sig){ if (shutdown_pending == 1) { /* Um, is this _probably_ not an error, if the user has * tried to do a shutdown twice quickly, so we won't * worry about reporting it. */ return; } shutdown_pending = 1;}static void restart(int sig){ if (restart_pending == 1) { /* Probably not an error - don't bother reporting it */ return; } restart_pending = 1; if ((is_graceful = (sig == SIGWINCH))) { apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); }}static void set_signals(void){#ifndef NO_USE_SIGACTION struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (!one_process) { sa.sa_handler = sig_coredump;#if defined(SA_ONESHOT) sa.sa_flags = SA_ONESHOT;#elif defined(SA_RESETHAND) sa.sa_flags = SA_RESETHAND;#endif if (sigaction(SIGSEGV, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");#ifdef SIGBUS if (sigaction(SIGBUS, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");#endif#ifdef SIGABORT if (sigaction(SIGABORT, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");#endif#ifdef SIGABRT if (sigaction(SIGABRT, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");#endif#ifdef SIGILL if (sigaction(SIGILL, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");#endif sa.sa_flags = 0; } sa.sa_handler = sig_term; if (sigaction(SIGTERM, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");#ifdef SIGINT if (sigaction(SIGINT, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");#endif#ifdef SIGXCPU sa.sa_handler = SIG_DFL; if (sigaction(SIGXCPU, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");#endif#ifdef SIGXFSZ sa.sa_handler = SIG_DFL; if (sigaction(SIGXFSZ, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");#endif#ifdef SIGPIPE sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");#endif /* we want to ignore HUPs and WINCH while we're busy processing one */ sigaddset(&sa.sa_mask, SIGHUP); sigaddset(&sa.sa_mask, SIGWINCH); sa.sa_handler = restart; if (sigaction(SIGHUP, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); if (sigaction(SIGWINCH, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)");#else if (!one_process) { apr_signal(SIGSEGV, sig_coredump);#ifdef SIGBUS apr_signal(SIGBUS, sig_coredump);#endif /* SIGBUS */#ifdef SIGABORT apr_signal(SIGABORT, sig_coredump);#endif /* SIGABORT */#ifdef SIGABRT apr_signal(SIGABRT, sig_coredump);#endif /* SIGABRT */#ifdef SIGILL apr_signal(SIGILL, sig_coredump);#endif /* SIGILL */#ifdef SIGXCPU apr_signal(SIGXCPU, SIG_DFL);#endif /* SIGXCPU */#ifdef SIGXFSZ apr_signal(SIGXFSZ, SIG_DFL);#endif /* SIGXFSZ */ } apr_signal(SIGTERM, sig_term);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -