📄 perchild.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. */#include "apr_hash.h"#include "apr_strings.h"#include "apr_pools.h"#include "apr_portable.h"#include "apr_file_io.h"#include "apr_signal.h"#define APR_WANT_IOVEC#include "apr_want.h"#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#if APR_HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#define CORE_PRIVATE #include "ap_config.h"#include "httpd.h" #include "http_main.h" #include "http_log.h" #include "http_config.h" /* for read_config */ #include "http_core.h" /* for get_remote_host */ #include "http_protocol.h"#include "http_connection.h"#include "ap_mpm.h"#include "unixd.h"#include "mpm_common.h"#include "ap_listen.h"#include "mpm_default.h"#include "mpm.h"#include "scoreboard.h"#include "util_filter.h"/* ### should be APR-ized */#include <poll.h>#include <grp.h>#include <pwd.h>#include <sys/stat.h>#include <sys/un.h>#include <setjmp.h>/* * Actual definitions of config globals */static int threads_to_start = 0; /* Worker threads per child */static int min_spare_threads = 0;static int max_spare_threads = 0;static int max_threads = 0;static int max_requests_per_child = 0;static const char *ap_pid_fname=NULL;static int num_daemons=0;static int curr_child_num=0;static int workers_may_exit = 0;static int requests_this_child;static int num_listenfds = 0;static apr_socket_t **listenfds;static jmp_buf jmpbuffer;struct child_info_t { uid_t uid; gid_t gid; int sd;};typedef struct { const char *sockname; /* The base name for the socket */ const char *fullsockname; /* socket base name + extension */ int sd; /* The socket descriptor */ int sd2; /* The socket descriptor */} perchild_server_conf;typedef struct child_info_t child_info_t;/* Tables used to determine the user and group each child process should * run as. The hash table is used to correlate a server name with a child * process. */static child_info_t child_info_table[HARD_SERVER_LIMIT];static int thread_socket_table[HARD_THREAD_LIMIT];struct ap_ctable ap_child_table[HARD_SERVER_LIMIT];/* * The max child slot ever assigned, preserved across restarts. Necessary * to deal with NumServers changes across SIGWINCH restarts. We use this * value to optimize routines that have to scan the entire child table. * * XXX - It might not be worth keeping this code in. There aren't very * many child processes in this MPM. */int ap_max_daemons_limit = -1;int ap_threads_per_child = HARD_THREAD_LIMIT;char ap_coredump_dir[MAX_STRING_LEN];module AP_MODULE_DECLARE_DATA mpm_perchild_module;static apr_file_t *pipe_of_death_in = NULL;static apr_file_t *pipe_of_death_out = NULL;static apr_lock_t *pipe_of_death_mutex;/* *Non*-shared http_main globals... */server_rec *ap_server_conf;/* 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;#ifdef DEBUG_SIGSTOPint raise_sigstop_flags;#endifstatic apr_pool_t *pconf; /* Pool for config stuff */static apr_pool_t *pchild; /* Pool for httpd child stuff */static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */static apr_lock_t *thread_pool_parent_mutex;static int child_num;static unsigned int my_pid; /* Linux getpid() doesn't work except in main thread. Use this instead *//* Keep track of the number of worker threads currently active */static int worker_thread_count;static apr_lock_t *worker_thread_count_mutex;static int worker_thread_free_ids[HARD_THREAD_LIMIT];static apr_threadattr_t *worker_thread_attr;/* Keep track of the number of idle worker threads */static int idle_thread_count;static apr_lock_t *idle_thread_count_mutex;/* Locks for accept serialization */#ifdef NO_SERIALIZED_ACCEPT#define SAFE_ACCEPT(stmt) APR_SUCCESS#else#define SAFE_ACCEPT(stmt) (stmt)static apr_lock_t *process_accept_mutex;#endif /* NO_SERIALIZED_ACCEPT */static const char *lock_fname;static apr_lock_t *thread_accept_mutex;AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result){ switch(query_code){ case AP_MPMQ_MAX_DAEMONS: *result = ap_max_daemons_limit; return APR_SUCCESS; case AP_MPMQ_IS_THREADED: *result = 1; return APR_SUCCESS; case AP_MPMQ_IS_FORKED: *result = 1; return APR_SUCCESS; } return APR_ENOTIMPL;}/* a clean exit from a child with proper cleanup */static void clean_child_exit(int code){ if (pchild) { apr_pool_destroy(pchild); } exit(code);}/* 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. */}static void just_die(int sig){ clean_child_exit(0);}/***************************************************************** * Connection structures and accounting... *//* volatile just in case */static int volatile shutdown_pending;static int volatile restart_pending;static int volatile is_graceful;/* we don't currently track ap_my_generation, but mod_status * references it so it must be defined */ap_generation_t volatile ap_my_generation=0;/* * ap_start_shutdown() and ap_start_restart(), below, are a first stab at * functions to initiate shutdown or restart without relying on signals. * Previously this was initiated in sig_term() and restart() signal handlers, * but we want to be able to start a shutdown/restart from other sources -- * e.g. on Win32, from the service manager. Now the service manager can * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that * these functions can also be called by the child processes, since global * variables are no longer used to pass on the required action to the parent. * * These should only be called from the parent process itself, since the * parent process will use the shutdown_pending and restart_pending variables * to determine whether to shutdown or restart. The child process should * call signal_parent() directly to tell the parent to die -- this will * cause neither of those variable to be set, which the parent will * assume means something serious is wrong (which it will be, for the * child to force an exit) and so do an exit anyway. */static void ap_start_shutdown(void){ 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;}/* do a graceful restart if graceful == 1 */static void ap_start_restart(int graceful){ if (restart_pending == 1) { /* Probably not an error - don't bother reporting it */ return; } restart_pending = 1; is_graceful = graceful; if (is_graceful) { apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); }}static void sig_term(int sig){ ap_start_shutdown();}static void restart(int sig){#ifndef WIN32 ap_start_restart(sig == SIGWINCH);#else ap_start_restart(1);#endif}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);#ifdef SIGHUP apr_signal(SIGHUP, restart);#endif /* SIGHUP */#ifdef SIGWINCH apr_signal(SIGWINCH, restart);#endif /* SIGWINCH */#ifdef SIGPIPE apr_signal(SIGPIPE, SIG_IGN);#endif /* SIGPIPE */#endif}/***************************************************************** * Here follows a long bunch of generic server bookkeeping stuff... */int ap_graceful_stop_signalled(void){ /* XXX - Does this really work? - Manoj */ return is_graceful;}/***************************************************************** * Child process main loop. */static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id){ conn_rec *current_conn; int csd; apr_status_t rv; int thread_num = conn_id % HARD_THREAD_LIMIT; if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -